redscript-mc 1.2.26 → 1.2.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -9
- package/README.zh.md +72 -4
- package/dist/__tests__/cli.test.js +13 -13
- package/dist/__tests__/optimizer-advanced.test.js +4 -4
- package/dist/__tests__/stdlib-advanced.test.js +114 -0
- package/dist/__tests__/stdlib-bigint.test.d.ts +7 -0
- package/dist/__tests__/stdlib-bigint.test.js +428 -0
- package/dist/cli.js +13 -5
- package/dist/codegen/mcfunction/index.d.ts +4 -0
- package/dist/codegen/mcfunction/index.js +9 -4
- package/dist/compile.d.ts +4 -0
- package/dist/compile.js +9 -1
- package/dist/data/arena/function/__load.mcfunction +6 -0
- package/dist/data/arena/function/__tick.mcfunction +2 -0
- package/dist/data/arena/function/announce_leaders/else_1.mcfunction +3 -0
- package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +3 -0
- package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +7 -0
- package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +4 -0
- package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +6 -0
- package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/then_0.mcfunction +4 -0
- package/dist/data/arena/function/announce_leaders.mcfunction +6 -0
- package/dist/data/arena/function/arena_tick/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/arena_tick/then_0.mcfunction +4 -0
- package/dist/data/arena/function/arena_tick.mcfunction +11 -0
- package/dist/data/counter/function/__load.mcfunction +5 -0
- package/dist/data/counter/function/__tick.mcfunction +2 -0
- package/dist/data/counter/function/counter_tick/merge_2.mcfunction +1 -0
- package/dist/data/counter/function/counter_tick/then_0.mcfunction +3 -0
- package/dist/data/counter/function/counter_tick.mcfunction +11 -0
- package/dist/data/gcd2/function/__load.mcfunction +3 -0
- package/dist/data/gcd2/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd2/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd2/function/abs.mcfunction +7 -0
- package/dist/data/gcd2/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd2/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd2/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd2/function/gcd.mcfunction +14 -0
- package/dist/data/gcd3/function/__load.mcfunction +3 -0
- package/dist/data/gcd3/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd3/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd3/function/abs.mcfunction +7 -0
- package/dist/data/gcd3/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd3/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd3/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd3/function/gcd.mcfunction +14 -0
- package/dist/data/gcd3/function/test.mcfunction +7 -0
- package/dist/data/gcd3nm/function/__load.mcfunction +3 -0
- package/dist/data/gcd3nm/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd3nm/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd3nm/function/abs.mcfunction +7 -0
- package/dist/data/gcd3nm/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd3nm/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd3nm/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd3nm/function/gcd.mcfunction +14 -0
- package/dist/data/gcd3nm/function/test.mcfunction +7 -0
- package/dist/data/gcd_test/function/__load.mcfunction +3 -0
- package/dist/data/gcd_test/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd_test/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd_test/function/abs.mcfunction +7 -0
- package/dist/data/gcd_test/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd_test/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd_test/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd_test/function/gcd.mcfunction +14 -0
- package/dist/data/isqrttest/function/__load.mcfunction +6 -0
- package/dist/data/isqrttest/function/isqrt/loop_body_4.mcfunction +12 -0
- package/dist/data/isqrttest/function/isqrt/loop_check_3.mcfunction +5 -0
- package/dist/data/isqrttest/function/isqrt/loop_exit_5.mcfunction +3 -0
- package/dist/data/isqrttest/function/isqrt/merge_2.mcfunction +4 -0
- package/dist/data/isqrttest/function/isqrt/merge_8.mcfunction +6 -0
- package/dist/data/isqrttest/function/isqrt/then_0.mcfunction +3 -0
- package/dist/data/isqrttest/function/isqrt/then_6.mcfunction +3 -0
- package/dist/data/isqrttest/function/isqrt.mcfunction +7 -0
- package/dist/data/isqrttest/function/test.mcfunction +6 -0
- package/dist/data/mathtest/function/__load.mcfunction +3 -0
- package/dist/data/mathtest/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/mathtest/function/abs/then_0.mcfunction +5 -0
- package/dist/data/mathtest/function/abs.mcfunction +6 -0
- package/dist/data/mathtest/function/test.mcfunction +5 -0
- package/dist/data/minecraft/tags/function/load.json +5 -0
- package/dist/data/minecraft/tags/function/tick.json +5 -0
- package/dist/data/mypack/function/__load.mcfunction +13 -0
- package/dist/data/mypack/function/_atan_init.mcfunction +2 -0
- package/dist/data/mypack/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/mypack/function/abs/then_0.mcfunction +5 -0
- package/dist/data/mypack/function/abs.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/__sgi_1.mcfunction +2 -0
- package/dist/data/mypack/function/atan2_fixed/else_34.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/loop_body_31.mcfunction +19 -0
- package/dist/data/mypack/function/atan2_fixed/loop_check_30.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/loop_exit_32.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_11.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_14.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/merge_17.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_2.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_20.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_23.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_26.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_29.mcfunction +4 -0
- package/dist/data/mypack/function/atan2_fixed/merge_38.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_41.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_44.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_47.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_5.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_8.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_0.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_12.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_15.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_18.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_21.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_24.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_27.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/then_3.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_33.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_36.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_39.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_42.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_45.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_6.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_9.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed.mcfunction +7 -0
- package/dist/data/mypack/function/my_game.mcfunction +10 -0
- package/dist/data/quiz/function/__load.mcfunction +16 -0
- package/dist/data/quiz/function/__tick.mcfunction +6 -0
- package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/answer_a.mcfunction +4 -0
- package/dist/data/quiz/function/answer_b.mcfunction +4 -0
- package/dist/data/quiz/function/answer_c.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/else_1.mcfunction +5 -0
- package/dist/data/quiz/function/ask_question/else_4.mcfunction +5 -0
- package/dist/data/quiz/function/ask_question/else_7.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/merge_2.mcfunction +1 -0
- package/dist/data/quiz/function/ask_question/merge_5.mcfunction +2 -0
- package/dist/data/quiz/function/ask_question/merge_8.mcfunction +2 -0
- package/dist/data/quiz/function/ask_question/then_0.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/then_3.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/then_6.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question.mcfunction +7 -0
- package/dist/data/quiz/function/finish_quiz.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/else_1.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/else_10.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_16.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_4.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_7.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +8 -0
- package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/then_0.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_12.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_15.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/then_3.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/then_6.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_9.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer.mcfunction +11 -0
- package/dist/data/quiz/function/start_quiz.mcfunction +5 -0
- package/dist/data/reqtest/function/__load.mcfunction +4 -0
- package/dist/data/reqtest/function/_table_init.mcfunction +2 -0
- package/dist/data/reqtest/function/no_trig.mcfunction +3 -0
- package/dist/data/reqtest/function/use_table.mcfunction +4 -0
- package/dist/data/reqtest2/function/__load.mcfunction +3 -0
- package/dist/data/reqtest2/function/no_trig.mcfunction +3 -0
- package/dist/data/runtime/function/__load.mcfunction +5 -0
- package/dist/data/runtime/function/__tick.mcfunction +2 -0
- package/dist/data/runtime/function/counter_tick/then_0.mcfunction +3 -0
- package/dist/data/runtime/function/counter_tick.mcfunction +13 -0
- package/dist/data/shop/function/__load.mcfunction +7 -0
- package/dist/data/shop/function/__tick.mcfunction +3 -0
- package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/else_1.mcfunction +5 -0
- package/dist/data/shop/function/complete_purchase/else_4.mcfunction +5 -0
- package/dist/data/shop/function/complete_purchase/else_7.mcfunction +3 -0
- package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/then_0.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/then_3.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/then_6.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase.mcfunction +7 -0
- package/dist/data/shop/function/handle_shop_trigger.mcfunction +3 -0
- package/dist/data/swap_test/function/__load.mcfunction +3 -0
- package/dist/data/swap_test/function/gcd_old/loop_body_1.mcfunction +7 -0
- package/dist/data/swap_test/function/gcd_old/loop_check_0.mcfunction +5 -0
- package/dist/data/swap_test/function/gcd_old/loop_exit_2.mcfunction +3 -0
- package/dist/data/swap_test/function/gcd_old.mcfunction +8 -0
- package/dist/data/turret/function/__load.mcfunction +5 -0
- package/dist/data/turret/function/__tick.mcfunction +4 -0
- package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +4 -0
- package/dist/data/turret/function/deploy_turret.mcfunction +8 -0
- package/dist/data/turret/function/turret_tick/at_1.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/tick_body.mcfunction +3 -0
- package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +1 -0
- package/dist/data/turret/function/turret_tick.mcfunction +5 -0
- package/dist/gcd2.map.json +15 -0
- package/dist/gcd3.map.json +17 -0
- package/dist/gcd_test.map.json +15 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +11 -6
- package/dist/isqrttest.map.json +15 -0
- package/dist/lowering/index.d.ts +3 -0
- package/dist/lowering/index.js +161 -64
- package/dist/mathtest.map.json +6 -0
- package/dist/mypack.map.json +27 -0
- package/dist/optimizer/commands.d.ts +1 -0
- package/dist/optimizer/commands.js +18 -11
- package/dist/optimizer/structure.d.ts +1 -0
- package/dist/optimizer/structure.js +6 -1
- package/dist/pack.mcmeta +6 -0
- package/dist/reqtest.map.json +4 -0
- package/dist/reqtest2.map.json +4 -0
- package/dist/runtime/index.js +26 -5
- package/dist/runtime.map.json +7 -0
- package/dist/swap_test.map.json +14 -0
- package/editors/vscode/package-lock.json +3 -3
- package/editors/vscode/package.json +1 -1
- package/examples/math-showcase.mcrs +146 -0
- package/examples/readme-demo.mcrs +92 -0
- package/examples/showcase.mcrs +505 -0
- package/package.json +1 -1
- package/src/__tests__/cli.test.ts +13 -13
- package/src/__tests__/optimizer-advanced.test.ts +4 -4
- package/src/__tests__/stdlib-advanced.test.ts +120 -0
- package/src/__tests__/stdlib-bigint.test.ts +427 -0
- package/src/cli.ts +14 -5
- package/src/codegen/mcfunction/index.ts +14 -5
- package/src/compile.ts +15 -2
- package/src/index.ts +17 -7
- package/src/lowering/index.ts +165 -63
- package/src/optimizer/commands.ts +18 -12
- package/src/optimizer/structure.ts +6 -2
- package/src/runtime/index.ts +27 -5
- package/src/stdlib/advanced.mcrs +81 -0
- package/src/stdlib/bigint.mcrs +205 -0
- package/src/stdlib/math.mcrs +19 -6
|
@@ -20,8 +20,14 @@ export interface CommandFunction {
|
|
|
20
20
|
commands: IRCommand[]
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
// Matches scoreboard reads for LICM/CSE — objective is captured in group 2
|
|
24
|
+
// so the optimizer can reconstruct the command with the same objective.
|
|
25
|
+
let _OBJ_PATTERN = 'rs'
|
|
26
|
+
export function setOptimizerObjective(obj: string): void { _OBJ_PATTERN = obj }
|
|
27
|
+
|
|
28
|
+
function scoreboardReadRe(): RegExp {
|
|
29
|
+
return new RegExp(`^execute store result score (\\$[A-Za-z0-9_]+) ${_OBJ_PATTERN} run scoreboard players get (\\S+) (\\S+)$`)
|
|
30
|
+
}
|
|
25
31
|
const SCOREBOARD_WRITE_RE =
|
|
26
32
|
/^(?:scoreboard players (?:set|add|remove|reset)\s+(\S+)\s+(\S+)|scoreboard players operation\s+(\S+)\s+(\S+)\s+[+\-*/%]?= )/
|
|
27
33
|
const EXECUTE_STORE_SCORE_RE =
|
|
@@ -130,7 +136,7 @@ function applyLICMInternal(functions: CommandFunction[]): Partial<OptimizationSt
|
|
|
130
136
|
const scoreboardWrites = new Set<string>()
|
|
131
137
|
|
|
132
138
|
for (const inner of loopFn.commands) {
|
|
133
|
-
const readMatch = inner.cmd.match(
|
|
139
|
+
const readMatch = inner.cmd.match(scoreboardReadRe())
|
|
134
140
|
if (readMatch) {
|
|
135
141
|
const [, temp, player, objective] = readMatch
|
|
136
142
|
const key = `${player} ${objective}`
|
|
@@ -147,7 +153,7 @@ function applyLICMInternal(functions: CommandFunction[]): Partial<OptimizationSt
|
|
|
147
153
|
for (const info of readInfo.values()) {
|
|
148
154
|
const matches = inner.cmd.match(TEMP_RE) ?? []
|
|
149
155
|
const usageCount = matches.filter(name => name === info.temp).length
|
|
150
|
-
const isDef = inner.cmd.startsWith(`execute store result score ${info.temp}
|
|
156
|
+
const isDef = inner.cmd.startsWith(`execute store result score ${info.temp} ${_OBJ_PATTERN} run scoreboard players get `)
|
|
151
157
|
if (!isDef) {
|
|
152
158
|
info.uses += usageCount
|
|
153
159
|
}
|
|
@@ -172,7 +178,7 @@ function applyLICMInternal(functions: CommandFunction[]): Partial<OptimizationSt
|
|
|
172
178
|
const rewrittenLoopCommands: IRCommand[] = []
|
|
173
179
|
|
|
174
180
|
for (const inner of loopFn.commands) {
|
|
175
|
-
const readMatch = inner.cmd.match(
|
|
181
|
+
const readMatch = inner.cmd.match(scoreboardReadRe())
|
|
176
182
|
if (readMatch && hoistedTemps.has(readMatch[1])) {
|
|
177
183
|
continue
|
|
178
184
|
}
|
|
@@ -182,7 +188,7 @@ function applyLICMInternal(functions: CommandFunction[]): Partial<OptimizationSt
|
|
|
182
188
|
loopFn.commands = rewrittenLoopCommands
|
|
183
189
|
nextCommands.push(
|
|
184
190
|
...hoistable.map(item => ({
|
|
185
|
-
cmd: `execute store result score ${item.temp}
|
|
191
|
+
cmd: `execute store result score ${item.temp} ${_OBJ_PATTERN} run scoreboard players get ${item.player} ${item.objective}`,
|
|
186
192
|
})),
|
|
187
193
|
command
|
|
188
194
|
)
|
|
@@ -198,9 +204,9 @@ function applyLICMInternal(functions: CommandFunction[]): Partial<OptimizationSt
|
|
|
198
204
|
|
|
199
205
|
function extractArithmeticExpression(commands: IRCommand[], index: number): { key: string; dst: string } | null {
|
|
200
206
|
const assign =
|
|
201
|
-
commands[index]?.cmd.match(
|
|
202
|
-
commands[index]?.cmd.match(
|
|
203
|
-
const op = commands[index + 1]?.cmd.match(
|
|
207
|
+
commands[index]?.cmd.match(new RegExp(`^scoreboard players operation (\\$[A-Za-z0-9_]+) ${_OBJ_PATTERN} = (\\$[A-Za-z0-9_]+|\\$const_-?\\d+) ${_OBJ_PATTERN}$`)) ??
|
|
208
|
+
commands[index]?.cmd.match(new RegExp(`^scoreboard players set (\\$[A-Za-z0-9_]+) ${_OBJ_PATTERN} (-?\\d+)$`))
|
|
209
|
+
const op = commands[index + 1]?.cmd.match(new RegExp(`^scoreboard players operation (\\$[A-Za-z0-9_]+) ${_OBJ_PATTERN} ([+\\-*/%]=) (\\$[A-Za-z0-9_]+|\\$const_-?\\d+) ${_OBJ_PATTERN}$`))
|
|
204
210
|
if (!assign || !op || assign[1] !== op[1]) {
|
|
205
211
|
return null
|
|
206
212
|
}
|
|
@@ -234,14 +240,14 @@ function applyCSEInternal(functions: CommandFunction[]): Partial<OptimizationSta
|
|
|
234
240
|
|
|
235
241
|
for (let i = 0; i < commands.length; i++) {
|
|
236
242
|
const command = commands[i]
|
|
237
|
-
const readMatch = command.cmd.match(
|
|
243
|
+
const readMatch = command.cmd.match(scoreboardReadRe())
|
|
238
244
|
if (readMatch) {
|
|
239
245
|
const [, dst, player, objective] = readMatch
|
|
240
246
|
const key = `${player} ${objective}`
|
|
241
247
|
const cached = readCache.get(key)
|
|
242
248
|
if (cached) {
|
|
243
249
|
stats.cseRedundantReads = (stats.cseRedundantReads ?? 0) + 1
|
|
244
|
-
rewritten.push({ ...command, cmd: `scoreboard players operation ${dst}
|
|
250
|
+
rewritten.push({ ...command, cmd: `scoreboard players operation ${dst} ${_OBJ_PATTERN} = ${cached} ${_OBJ_PATTERN}` })
|
|
245
251
|
} else {
|
|
246
252
|
readCache.set(key, dst)
|
|
247
253
|
rewritten.push(command)
|
|
@@ -255,7 +261,7 @@ function applyCSEInternal(functions: CommandFunction[]): Partial<OptimizationSta
|
|
|
255
261
|
if (expr) {
|
|
256
262
|
const cached = exprCache.get(expr.key)
|
|
257
263
|
if (cached) {
|
|
258
|
-
rewritten.push({ ...commands[i], cmd: `scoreboard players operation ${expr.dst}
|
|
264
|
+
rewritten.push({ ...commands[i], cmd: `scoreboard players operation ${expr.dst} ${_OBJ_PATTERN} = ${cached} ${_OBJ_PATTERN}` })
|
|
259
265
|
stats.cseArithmetic = (stats.cseArithmetic ?? 0) + 1
|
|
260
266
|
i += 1
|
|
261
267
|
} else {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { IRBlock, IRCommand, IRFunction, IRInstr, Operand, Terminator } from '../ir/types'
|
|
2
|
-
import { createEmptyOptimizationStats, mergeOptimizationStats, optimizeCommandFunctions, type OptimizationStats } from './commands'
|
|
2
|
+
import { createEmptyOptimizationStats, mergeOptimizationStats, optimizeCommandFunctions, setOptimizerObjective, type OptimizationStats } from './commands'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
let OBJ = 'rs'
|
|
5
|
+
export function setStructureObjective(obj: string): void {
|
|
6
|
+
OBJ = obj
|
|
7
|
+
setOptimizerObjective(obj)
|
|
8
|
+
}
|
|
5
9
|
const INLINE_THRESHOLD = 8
|
|
6
10
|
|
|
7
11
|
const BOP_OP: Record<string, string> = {
|
package/src/runtime/index.ts
CHANGED
|
@@ -697,17 +697,27 @@ export class MCRuntime {
|
|
|
697
697
|
continue
|
|
698
698
|
}
|
|
699
699
|
|
|
700
|
-
// Handle 'store result storage <ns:path> <field> <type> <scale>'
|
|
700
|
+
// Handle 'store result storage <ns:path> <field>[<idx>] <type> <scale>' (array element)
|
|
701
701
|
if (rest.startsWith('store result storage ')) {
|
|
702
|
-
|
|
703
|
-
//
|
|
704
|
-
|
|
702
|
+
const sliced = rest.slice(21)
|
|
703
|
+
// Try array-index form first: <ns:path> <field>[<idx>] <type> <scale> <run-cmd>
|
|
704
|
+
// Use [^\[\s]+ for field (no brackets or spaces) so that \[ matches correctly.
|
|
705
|
+
const arrParts = sliced.match(/^(\S+)\s+([^\[\s]+)\[(\d+)\]\s+(\S+)\s+([\d.]+)\s+(.*)$/)
|
|
706
|
+
if (arrParts) {
|
|
707
|
+
const [, storagePath, field, indexStr, , , remaining] = arrParts
|
|
708
|
+
storeTarget = { storagePath, field: `${field}[${indexStr}]`, type: 'result' }
|
|
709
|
+
rest = remaining.trim()
|
|
710
|
+
continue
|
|
711
|
+
}
|
|
712
|
+
// Plain form: <ns:path> <field> <type> <scale> <run-cmd>
|
|
713
|
+
const storageParts = sliced.match(/^(\S+)\s+(\S+)\s+(\S+)\s+([\d.]+)\s+(.*)$/)
|
|
705
714
|
if (storageParts) {
|
|
706
715
|
const [, storagePath, field, , , remaining] = storageParts
|
|
707
716
|
storeTarget = { storagePath, field, type: 'result' }
|
|
708
717
|
rest = remaining.trim()
|
|
709
718
|
continue
|
|
710
719
|
}
|
|
720
|
+
rest = sliced
|
|
711
721
|
}
|
|
712
722
|
|
|
713
723
|
// Handle 'store result score <player> <obj>'
|
|
@@ -834,8 +844,20 @@ export class MCRuntime {
|
|
|
834
844
|
return true
|
|
835
845
|
}
|
|
836
846
|
|
|
847
|
+
// data modify storage <ns:path> <field>[<index>] set value <val> (array element write)
|
|
848
|
+
const setArrMatch = cmd.match(/^data modify storage (\S+) ([^\[\s]+)\[(\d+)\] set value (.+)$/)
|
|
849
|
+
if (setArrMatch) {
|
|
850
|
+
const [, storagePath, field, indexStr, valueStr] = setArrMatch
|
|
851
|
+
const arr = this.getStorageField(storagePath, field)
|
|
852
|
+
const idx = parseInt(indexStr, 10)
|
|
853
|
+
if (Array.isArray(arr) && idx >= 0 && idx < arr.length) {
|
|
854
|
+
arr[idx] = this.parseDataValue(valueStr)
|
|
855
|
+
}
|
|
856
|
+
return true
|
|
857
|
+
}
|
|
858
|
+
|
|
837
859
|
// data get storage <ns:path> <field>[<index>] [scale] (array element access)
|
|
838
|
-
const getArrMatch = cmd.match(/^data get storage (\S+) (\
|
|
860
|
+
const getArrMatch = cmd.match(/^data get storage (\S+) ([^\[\s]+)\[(\d+)\](?:\s+[\d.]+)?$/)
|
|
839
861
|
if (getArrMatch) {
|
|
840
862
|
const [, storagePath, field, indexStr] = getArrMatch
|
|
841
863
|
const arr = this.getStorageField(storagePath, field)
|
package/src/stdlib/advanced.mcrs
CHANGED
|
@@ -247,3 +247,84 @@ fn julia_iter(z0r: int, z0i: int, cr: int, ci: int, max_iter: int) -> int {
|
|
|
247
247
|
}
|
|
248
248
|
return max_iter;
|
|
249
249
|
}
|
|
250
|
+
|
|
251
|
+
// ─── Category 5: Geometry experiments ────────────────────────────────────────
|
|
252
|
+
|
|
253
|
+
// Angle between two 2D vectors in degrees (×1 = degrees, unsigned 0..180).
|
|
254
|
+
// Strategy: normalize both vectors to unit (×1000 components), then
|
|
255
|
+
// angle = atan2(|cross|, dot) where cross,dot are from the unit vectors.
|
|
256
|
+
// Unit vector components are ≤ 1000, so cross/dot ≤ 10^6 (no overflow).
|
|
257
|
+
// After dividing by 1000 to re-scale, pass to atan2_fixed.
|
|
258
|
+
//
|
|
259
|
+
// angle_between(1000, 0, 0, 1000) == 90
|
|
260
|
+
// angle_between(1000, 0, 1000, 0) == 0
|
|
261
|
+
// angle_between(1000, 0, -1000, 0) == 180
|
|
262
|
+
fn angle_between(x1: int, y1: int, x2: int, y2: int) -> int {
|
|
263
|
+
let nx1: int = normalize2d_x(x1, y1);
|
|
264
|
+
let ny1: int = normalize2d_y(x1, y1);
|
|
265
|
+
let nx2: int = normalize2d_x(x2, y2);
|
|
266
|
+
let ny2: int = normalize2d_y(x2, y2);
|
|
267
|
+
if (nx1 == 0 && ny1 == 0) { return 0; }
|
|
268
|
+
if (nx2 == 0 && ny2 == 0) { return 0; }
|
|
269
|
+
// dot and cross of unit vectors (components ×1000 → result ×1000000)
|
|
270
|
+
let d: int = dot2d(nx1, ny1, nx2, ny2) / 1000; // cos × 1000
|
|
271
|
+
let c: int = abs(cross2d(nx1, ny1, nx2, ny2)) / 1000; // |sin| × 1000
|
|
272
|
+
return atan2_fixed(c, d);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Clamp a 2D point to lie within a circle of radius r centred at origin.
|
|
276
|
+
// r is in the same units as x, y (raw block coords, NOT fixed-point).
|
|
277
|
+
// Returns the clamped x component.
|
|
278
|
+
// Note: keep x, y < ~2000 to avoid overflow in normalize2d_x (x * 10^6).
|
|
279
|
+
//
|
|
280
|
+
// clamp_circle_x(3, 4, 10) == 3 (point at dist 5, inside r=10)
|
|
281
|
+
// clamp_circle_x(600, 0, 500) == 500
|
|
282
|
+
fn clamp_circle_x(x: int, y: int, r: int) -> int {
|
|
283
|
+
// length2d_fixed returns dist × 1000; compare with r × 1000
|
|
284
|
+
let dist: int = length2d_fixed(x, y);
|
|
285
|
+
if (dist <= r * 1000) { return x; }
|
|
286
|
+
return normalize2d_x(x, y) * r / 1000;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Y component of circle clamp.
|
|
290
|
+
// clamp_circle_y(0, 600, 500) == 500
|
|
291
|
+
fn clamp_circle_y(x: int, y: int, r: int) -> int {
|
|
292
|
+
let dist: int = length2d_fixed(x, y);
|
|
293
|
+
if (dist <= r * 1000) { return y; }
|
|
294
|
+
return normalize2d_y(x, y) * r / 1000;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Newton's method integer square root (alternative to isqrt).
|
|
298
|
+
// Converges quadratically; validates our while loop + division.
|
|
299
|
+
// newton_sqrt(25) == 5, newton_sqrt(100) == 10, newton_sqrt(2) == 1
|
|
300
|
+
fn newton_sqrt(n: int) -> int {
|
|
301
|
+
if (n <= 0) { return 0; }
|
|
302
|
+
if (n == 1) { return 1; }
|
|
303
|
+
let x: int = n / 2;
|
|
304
|
+
let prev: int = 0;
|
|
305
|
+
while (x != prev) {
|
|
306
|
+
prev = x;
|
|
307
|
+
x = (x + n / x) / 2;
|
|
308
|
+
}
|
|
309
|
+
return x;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Digital root: repeatedly sum digits until single digit.
|
|
313
|
+
// digital_root(493) == 7 (4+9+3=16 → 1+6=7)
|
|
314
|
+
// digital_root(9) == 9
|
|
315
|
+
// digital_root(0) == 0
|
|
316
|
+
fn digital_root(n: int) -> int {
|
|
317
|
+
if (n == 0) { return 0; }
|
|
318
|
+
let r: int = n % 9;
|
|
319
|
+
if (r == 0) { return 9; }
|
|
320
|
+
return r;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Ulam spiral ring number: which concentric square ring is n on?
|
|
324
|
+
// Ring 0: n=1; Ring 1: n=2..9 (3×3 square); Ring 2: n=10..25 (5×5); etc.
|
|
325
|
+
// Formula: floor((isqrt(n-1) + 1) / 2)
|
|
326
|
+
// spiral_ring(1) == 0, spiral_ring(9) == 1, spiral_ring(25) == 2
|
|
327
|
+
fn spiral_ring(n: int) -> int {
|
|
328
|
+
if (n <= 1) { return 0; }
|
|
329
|
+
return (isqrt(n - 1) + 1) / 2;
|
|
330
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
// bigint.mcrs — Arbitrary precision integer arithmetic for RedScript.
|
|
2
|
+
//
|
|
3
|
+
// Representation:
|
|
4
|
+
// 8 limbs, base B = 10000 (10^4) per limb.
|
|
5
|
+
// Limb[0] = least significant (ones place in base 10000).
|
|
6
|
+
// Maximum value: 10^32 - 1 (32 decimal digits).
|
|
7
|
+
// Stored in NBT int arrays inside data storage ("rs:bigint").
|
|
8
|
+
//
|
|
9
|
+
// Registers: "a", "b", "c" (three independent BigInt values).
|
|
10
|
+
//
|
|
11
|
+
// Usage example:
|
|
12
|
+
// bigint_init();
|
|
13
|
+
// bigint_from_int_a(12345678); // a = 12345678
|
|
14
|
+
// bigint_from_int_b(87654321); // b = 87654321
|
|
15
|
+
// bigint_add(); // c = a + b = 99999999
|
|
16
|
+
// let limb0: int = bigint_get_c(0); // → 9999 (c[0])
|
|
17
|
+
// let limb1: int = bigint_get_c(1); // → 9999 (c[1])
|
|
18
|
+
//
|
|
19
|
+
// Multiply overflow note:
|
|
20
|
+
// bigint_mul uses grade-school O(n^2) algorithm.
|
|
21
|
+
// Per-product max: 9999 * 9999 + 9999 + 9999 = 99,999,999 < INT32 ✓
|
|
22
|
+
|
|
23
|
+
module library;
|
|
24
|
+
|
|
25
|
+
// ── Initialization ────────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
// Initialize (or reset) all BigInt registers to zero.
|
|
28
|
+
// Must be called once before using any bigint operation.
|
|
29
|
+
fn bigint_init() {
|
|
30
|
+
storage_set_array("rs:bigint", "a", "[0,0,0,0,0,0,0,0]");
|
|
31
|
+
storage_set_array("rs:bigint", "b", "[0,0,0,0,0,0,0,0]");
|
|
32
|
+
storage_set_array("rs:bigint", "c", "[0,0,0,0,0,0,0,0]");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ── Load from int32 ───────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
// Set register a from a 32-bit integer (splits into up to 3 limbs).
|
|
38
|
+
// Supports any n in [0, 999999999999] (12-digit safe limit).
|
|
39
|
+
fn bigint_from_int_a(n: int) {
|
|
40
|
+
storage_set_array("rs:bigint", "a", "[0,0,0,0,0,0,0,0]");
|
|
41
|
+
storage_set_int("rs:bigint", "a", 0, n % 10000);
|
|
42
|
+
storage_set_int("rs:bigint", "a", 1, n / 10000 % 10000);
|
|
43
|
+
storage_set_int("rs:bigint", "a", 2, n / 10000 / 10000);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Set register b from a 32-bit integer.
|
|
47
|
+
fn bigint_from_int_b(n: int) {
|
|
48
|
+
storage_set_array("rs:bigint", "b", "[0,0,0,0,0,0,0,0]");
|
|
49
|
+
storage_set_int("rs:bigint", "b", 0, n % 10000);
|
|
50
|
+
storage_set_int("rs:bigint", "b", 1, n / 10000 % 10000);
|
|
51
|
+
storage_set_int("rs:bigint", "b", 2, n / 10000 / 10000);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── Read limb ─────────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
fn bigint_get_a(i: int) -> int { return storage_get_int("rs:bigint", "a", i); }
|
|
57
|
+
fn bigint_get_b(i: int) -> int { return storage_get_int("rs:bigint", "b", i); }
|
|
58
|
+
fn bigint_get_c(i: int) -> int { return storage_get_int("rs:bigint", "c", i); }
|
|
59
|
+
|
|
60
|
+
// ── Copy between registers ────────────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
fn bigint_copy_a_to_b() {
|
|
63
|
+
let i: int = 0;
|
|
64
|
+
while (i < 8) {
|
|
65
|
+
storage_set_int("rs:bigint", "b", i, storage_get_int("rs:bigint", "a", i));
|
|
66
|
+
i = i + 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn bigint_copy_b_to_a() {
|
|
71
|
+
let i: int = 0;
|
|
72
|
+
while (i < 8) {
|
|
73
|
+
storage_set_int("rs:bigint", "a", i, storage_get_int("rs:bigint", "b", i));
|
|
74
|
+
i = i + 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn bigint_copy_c_to_a() {
|
|
79
|
+
let i: int = 0;
|
|
80
|
+
while (i < 8) {
|
|
81
|
+
storage_set_int("rs:bigint", "a", i, storage_get_int("rs:bigint", "c", i));
|
|
82
|
+
i = i + 1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fn bigint_copy_c_to_b() {
|
|
87
|
+
let i: int = 0;
|
|
88
|
+
while (i < 8) {
|
|
89
|
+
storage_set_int("rs:bigint", "b", i, storage_get_int("rs:bigint", "c", i));
|
|
90
|
+
i = i + 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── Addition: c = a + b ───────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
// c = a + b (carry propagated across all 8 limbs)
|
|
97
|
+
fn bigint_add() {
|
|
98
|
+
let carry: int = 0;
|
|
99
|
+
let i: int = 0;
|
|
100
|
+
while (i < 8) {
|
|
101
|
+
let s: int = storage_get_int("rs:bigint", "a", i)
|
|
102
|
+
+ storage_get_int("rs:bigint", "b", i)
|
|
103
|
+
+ carry;
|
|
104
|
+
carry = s / 10000;
|
|
105
|
+
storage_set_int("rs:bigint", "c", i, s % 10000);
|
|
106
|
+
i = i + 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── Subtraction: c = a - b (assumes a ≥ b) ──────────────────────────────────
|
|
111
|
+
|
|
112
|
+
fn bigint_sub() {
|
|
113
|
+
let borrow: int = 0;
|
|
114
|
+
let i: int = 0;
|
|
115
|
+
while (i < 8) {
|
|
116
|
+
let d: int = storage_get_int("rs:bigint", "a", i)
|
|
117
|
+
- storage_get_int("rs:bigint", "b", i)
|
|
118
|
+
- borrow;
|
|
119
|
+
if (d < 0) {
|
|
120
|
+
d = d + 10000;
|
|
121
|
+
borrow = 1;
|
|
122
|
+
} else {
|
|
123
|
+
borrow = 0;
|
|
124
|
+
}
|
|
125
|
+
storage_set_int("rs:bigint", "c", i, d);
|
|
126
|
+
i = i + 1;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── Comparison: returns 1 (a>b), 0 (a==b), -1 (a<b) ─────────────────────────
|
|
131
|
+
|
|
132
|
+
fn bigint_compare() -> int {
|
|
133
|
+
let i: int = 7;
|
|
134
|
+
while (i >= 0) {
|
|
135
|
+
let ai: int = storage_get_int("rs:bigint", "a", i);
|
|
136
|
+
let bi: int = storage_get_int("rs:bigint", "b", i);
|
|
137
|
+
if (ai > bi) { return 1; }
|
|
138
|
+
if (ai < bi) { return -1; }
|
|
139
|
+
i = i - 1;
|
|
140
|
+
}
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Multiply by small constant: c = a × k (k < 10000) ───────────────────────
|
|
145
|
+
// Max per-limb: 9999 × 9999 + 9999 = 99,989,999 < INT32 ✓
|
|
146
|
+
|
|
147
|
+
fn bigint_mul_small(k: int) {
|
|
148
|
+
let carry: int = 0;
|
|
149
|
+
let i: int = 0;
|
|
150
|
+
while (i < 8) {
|
|
151
|
+
let p: int = storage_get_int("rs:bigint", "a", i) * k + carry;
|
|
152
|
+
carry = p / 10000;
|
|
153
|
+
storage_set_int("rs:bigint", "c", i, p % 10000);
|
|
154
|
+
i = i + 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ── Multiply: c = a × b (grade-school O(n²), n=8) ───────────────────────────
|
|
159
|
+
// Per-product max: 9999 × 9999 + 9999 (prev c) + 9999 (carry) = 99,999,999 < INT32 ✓
|
|
160
|
+
|
|
161
|
+
fn bigint_mul() {
|
|
162
|
+
storage_set_array("rs:bigint", "c", "[0,0,0,0,0,0,0,0]");
|
|
163
|
+
let i: int = 0;
|
|
164
|
+
while (i < 8) {
|
|
165
|
+
let ai: int = storage_get_int("rs:bigint", "a", i);
|
|
166
|
+
if (ai != 0) {
|
|
167
|
+
let j: int = 0;
|
|
168
|
+
let carry: int = 0;
|
|
169
|
+
while (j < 8) {
|
|
170
|
+
let k: int = i + j;
|
|
171
|
+
if (k < 8) {
|
|
172
|
+
let p: int = ai * storage_get_int("rs:bigint", "b", j)
|
|
173
|
+
+ storage_get_int("rs:bigint", "c", k)
|
|
174
|
+
+ carry;
|
|
175
|
+
carry = p / 10000;
|
|
176
|
+
storage_set_int("rs:bigint", "c", k, p % 10000);
|
|
177
|
+
}
|
|
178
|
+
j = j + 1;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
i = i + 1;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ── Fibonacci: F(n) → register a (n ≤ 150 before 32-digit overflow) ─────────
|
|
186
|
+
//
|
|
187
|
+
// Invariant: a=F(k), b=F(k+1). After n iterations: a=F(n).
|
|
188
|
+
//
|
|
189
|
+
// F(50) = 12,586,269,025 → a[0]=9025, a[1]=8626, a[2]=125
|
|
190
|
+
// F(100) = 354,224,848,179,261,915,075 → 21 digits, fits in 6 limbs
|
|
191
|
+
|
|
192
|
+
fn bigint_fib(n: int) {
|
|
193
|
+
bigint_init(); // a=0=F(0), b=0
|
|
194
|
+
bigint_from_int_b(1); // b=1=F(1)
|
|
195
|
+
let i: int = 0;
|
|
196
|
+
while (i < n) {
|
|
197
|
+
// Invariant entering iteration: a=F(i), b=F(i+1)
|
|
198
|
+
bigint_add(); // c = F(i) + F(i+1) = F(i+2)
|
|
199
|
+
bigint_copy_b_to_a(); // a = F(i+1)
|
|
200
|
+
bigint_copy_c_to_b(); // b = F(i+2)
|
|
201
|
+
// Invariant restored: a=F(i+1), b=F(i+2)
|
|
202
|
+
i = i + 1;
|
|
203
|
+
}
|
|
204
|
+
// result: a = F(n)
|
|
205
|
+
}
|
package/src/stdlib/math.mcrs
CHANGED
|
@@ -71,16 +71,29 @@ fn lerp(a: int, b: int, t: int) -> int {
|
|
|
71
71
|
// Uses Newton's method, converges in ≤16 iterations for all int32.
|
|
72
72
|
// isqrt(9) == 3, isqrt(10) == 3, isqrt(0) == 0
|
|
73
73
|
fn isqrt(n: int) -> int {
|
|
74
|
-
if (n <= 0) {
|
|
75
|
-
|
|
74
|
+
if (n <= 0) { return 0; }
|
|
75
|
+
if (n == 1) { return 1; }
|
|
76
|
+
// Bit-length of n: how many bits needed to represent n.
|
|
77
|
+
let bits: int = 0;
|
|
78
|
+
let tmp: int = n;
|
|
79
|
+
while (tmp > 0) {
|
|
80
|
+
tmp = tmp / 2;
|
|
81
|
+
bits = bits + 1;
|
|
76
82
|
}
|
|
77
|
-
|
|
83
|
+
// Initial guess: 2^((bits+1)/2). Always ≥ sqrt(n), so Newton converges
|
|
84
|
+
// monotonically from above — the standard floor-sqrt Newton iteration.
|
|
85
|
+
let half: int = (bits + 1) / 2;
|
|
86
|
+
let x: int = 1;
|
|
87
|
+
let j: int = 0;
|
|
88
|
+
while (j < half) {
|
|
89
|
+
x = x * 2;
|
|
90
|
+
j = j + 1;
|
|
91
|
+
}
|
|
92
|
+
// Newton–Raphson floor-sqrt: converges in ≤ 8 iterations from a 2× overestimate.
|
|
78
93
|
let i: int = 0;
|
|
79
94
|
while (i < 16) {
|
|
80
95
|
let next: int = (x + n / x) / 2;
|
|
81
|
-
if (next >= x) {
|
|
82
|
-
return x;
|
|
83
|
-
}
|
|
96
|
+
if (next >= x) { return x; }
|
|
84
97
|
x = next;
|
|
85
98
|
i = i + 1;
|
|
86
99
|
}
|