redscript-mc 2.2.1 → 2.3.0

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +18 -2
  3. package/dist/src/__tests__/tuner/engine.test.d.ts +4 -0
  4. package/dist/src/__tests__/tuner/engine.test.js +232 -0
  5. package/dist/src/tuner/adapters/ln-polynomial.d.ts +23 -0
  6. package/dist/src/tuner/adapters/ln-polynomial.js +142 -0
  7. package/dist/src/tuner/adapters/sqrt-newton.d.ts +28 -0
  8. package/dist/src/tuner/adapters/sqrt-newton.js +125 -0
  9. package/dist/src/tuner/cli.d.ts +5 -0
  10. package/dist/src/tuner/cli.js +168 -0
  11. package/dist/src/tuner/engine.d.ts +17 -0
  12. package/dist/src/tuner/engine.js +215 -0
  13. package/dist/src/tuner/metrics.d.ts +15 -0
  14. package/dist/src/tuner/metrics.js +51 -0
  15. package/dist/src/tuner/simulator.d.ts +35 -0
  16. package/dist/src/tuner/simulator.js +78 -0
  17. package/dist/src/tuner/types.d.ts +32 -0
  18. package/dist/src/tuner/types.js +6 -0
  19. package/docs/STDLIB_ROADMAP.md +142 -0
  20. package/editors/vscode/package-lock.json +3 -3
  21. package/editors/vscode/package.json +1 -1
  22. package/package.json +1 -1
  23. package/src/__tests__/tuner/engine.test.ts +260 -0
  24. package/src/stdlib/bigint.mcrs +155 -192
  25. package/src/stdlib/bits.mcrs +158 -0
  26. package/src/stdlib/color.mcrs +160 -0
  27. package/src/stdlib/geometry.mcrs +124 -0
  28. package/src/stdlib/list.mcrs +125 -0
  29. package/src/stdlib/math.mcrs +90 -0
  30. package/src/stdlib/math_hp.mcrs +65 -0
  31. package/src/stdlib/random.mcrs +67 -0
  32. package/src/stdlib/signal.mcrs +112 -0
  33. package/src/stdlib/vec.mcrs +27 -0
  34. package/src/tuner/adapters/ln-polynomial.ts +147 -0
  35. package/src/tuner/adapters/sqrt-newton.ts +135 -0
  36. package/src/tuner/cli.ts +158 -0
  37. package/src/tuner/engine.ts +272 -0
  38. package/src/tuner/metrics.ts +66 -0
  39. package/src/tuner/simulator.ts +69 -0
  40. package/src/tuner/types.ts +44 -0
  41. package/docs/ARCHITECTURE.zh.md +0 -1088
  42. package/docs/COMPILATION_STATS.md +0 -142
  43. package/docs/IMPLEMENTATION_GUIDE.md +0 -512
@@ -1,205 +1,168 @@
1
- // bigint.mcrs — Arbitrary precision integer arithmetic for RedScript.
1
+ // bigint.mcrs — Multi-precision integer arithmetic for RedScript.
2
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").
3
+ // Representation: "万进制" (base-10000) int array stored in NBT storage.
4
+ // [1, 2345, 6789] represents 1_0002345_6789 = 100,023,456,789
5
+ // Each element is 0-9999 (4 decimal digits).
6
+ // First element is the most significant (big-endian).
7
+ // Leading zeros in non-first elements must be preserved conceptually.
8
8
  //
9
- // Registers: "a", "b", "c" (three independent BigInt values).
9
+ // NBT path: storage rs:bigint <varname>
10
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])
11
+ // Operations use raw() to emit NBT commands. All operations are on stored values.
12
+ // This module provides:
13
+ // 1. Helper functions for single-chunk arithmetic (within int32)
14
+ // 2. raw()-based macros for NBT-backed multi-chunk operations
15
+ // 3. Conversion utilities
18
16
  //
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 ✓
17
+ // NOTE: Full arbitrary-precision ops (like kaer's library) require
18
+ // complex NBT recursion not yet expressible in RedScript.
19
+ // This module provides a 96-bit (3 × 4-digit) max precision layer,
20
+ // which covers values up to ~10^12 (1 trillion).
22
21
 
23
22
  module library;
24
23
 
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]");
24
+ // ─── Constants ───────────────────────────────────────────────────────────────
25
+
26
+ // BIGINT_BASE: base for 万进制 representation
27
+ fn bigint_base(): int { return 10000; }
28
+
29
+ // ─── Single-precision helpers ────────────────────────────────────────────────
30
+ // These work on individual 4-digit chunks.
31
+
32
+ // chunk_hi(n): upper 4 digits of an 8-digit product (n must fit in int32)
33
+ // chunk_hi(12345678) = 1234
34
+ fn chunk_hi(n: int): int {
35
+ return n / 10000;
36
+ }
37
+
38
+ // chunk_lo(n): lower 4 digits
39
+ // chunk_lo(12345678) = 5678
40
+ fn chunk_lo(n: int): int {
41
+ return n % 10000;
42
+ }
43
+
44
+ // ─── 96-bit (3-chunk) addition ────────────────────────────────────────────────
45
+ // Represents number as (hi, mid, lo) where value = hi*10^8 + mid*10^4 + lo
46
+
47
+ // bigint3_add_lo(alo, blo): low chunk sum (carry handled by mid)
48
+ fn bigint3_add_lo(alo: int, blo: int): int {
49
+ return (alo + blo) % 10000;
50
+ }
51
+
52
+ // bigint3_carry_lo(alo, blo): carry from low to mid chunk (0 or 1)
53
+ fn bigint3_carry_lo(alo: int, blo: int): int {
54
+ return (alo + blo) / 10000;
55
+ }
56
+
57
+ // bigint3_add_mid(amid, bmid, carry): mid chunk sum
58
+ fn bigint3_add_mid(amid: int, bmid: int, carry: int): int {
59
+ return (amid + bmid + carry) % 10000;
60
+ }
61
+
62
+ fn bigint3_carry_mid(amid: int, bmid: int, carry: int): int {
63
+ return (amid + bmid + carry) / 10000;
64
+ }
65
+
66
+ fn bigint3_add_hi(ahi: int, bhi: int, carry: int): int {
67
+ return (ahi + bhi + carry) % 10000;
68
+ }
69
+
70
+ // ─── 96-bit subtraction (a >= b assumed) ─────────────────────────────────────
71
+
72
+ fn bigint3_sub_lo(alo: int, blo: int): int {
73
+ if (alo >= blo) { return alo - blo; }
74
+ return alo + 10000 - blo;
75
+ }
76
+
77
+ fn bigint3_borrow_lo(alo: int, blo: int): int {
78
+ if (alo >= blo) { return 0; }
79
+ return 1;
80
+ }
81
+
82
+ fn bigint3_sub_mid(amid: int, bmid: int, borrow: int): int {
83
+ let v: int = amid - bmid - borrow;
84
+ if (v < 0) { v = v + 10000; }
85
+ return v;
86
+ }
87
+
88
+ fn bigint3_borrow_mid(amid: int, bmid: int, borrow: int): int {
89
+ if (amid - borrow >= bmid) { return 0; }
90
+ return 1;
33
91
  }
34
92
 
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
- }
93
+ fn bigint3_sub_hi(ahi: int, bhi: int, borrow: int): int {
94
+ return ahi - bhi - borrow;
95
+ }
96
+
97
+ // ─── Multiplication (int × int → 96-bit) ─────────────────────────────────────
98
+
99
+ // bigint3_mul_lo(a, b): low chunk of a × b (a, b each up to 10^12 / 10^8)
100
+ // For a, b 9999 (one chunk each):
101
+ fn bigint3_mul1_lo(a: int, b: int): int {
102
+ return (a * b) % 10000;
103
+ }
104
+
105
+ fn bigint3_mul1_hi(a: int, b: int): int {
106
+ return (a * b) / 10000;
107
+ }
108
+
109
+ // int32 × int32 → 96-bit: a*b where both 9999
110
+ // Result fits in 8 decimal digits (max 9999*9999 = 99,980,001)
111
+ fn bigint3_mul1_mid(a: int, b: int): int {
112
+ // No mid chunk needed for 1×1; return 0
141
113
  return 0;
142
114
  }
143
115
 
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)
116
+ // ─── Comparison ──────────────────────────────────────────────────────────────
117
+
118
+ // bigint3_cmp(ahi, amid, alo, bhi, bmid, blo):
119
+ // Returns 1 if a > b, -1 if a < b, 0 if equal
120
+ fn bigint3_cmp(ahi: int, amid: int, alo: int,
121
+ bhi: int, bmid: int, blo: int): int {
122
+ if (ahi > bhi) { return 1; }
123
+ if (ahi < bhi) { return -1; }
124
+ if (amid > bmid) { return 1; }
125
+ if (amid < bmid) { return -1; }
126
+ if (alo > blo) { return 1; }
127
+ if (alo < blo) { return -1; }
128
+ return 0;
129
+ }
130
+
131
+ // ─── Conversion helpers ───────────────────────────────────────────────────────
132
+
133
+ // int32_to_bigint3_lo(n): low chunk of n (4 digits)
134
+ fn int32_to_bigint3_lo(n: int): int {
135
+ if (n < 0) { n = 0 - n; }
136
+ return n % 10000;
137
+ }
138
+
139
+ // int32_to_bigint3_mid(n): mid chunk (digits 5-8)
140
+ fn int32_to_bigint3_mid(n: int): int {
141
+ if (n < 0) { n = 0 - n; }
142
+ return (n / 10000) % 10000;
143
+ }
144
+
145
+ // int32_to_bigint3_hi(n): high chunk (digits 9+, usually 0 for int32)
146
+ fn int32_to_bigint3_hi(n: int): int {
147
+ if (n < 0) { n = 0 - n; }
148
+ return n / 100000000;
149
+ }
150
+
151
+ // bigint3_to_int32(hi, mid, lo): convert back to int32 (truncates if > 2^31)
152
+ fn bigint3_to_int32(hi: int, mid: int, lo: int): int {
153
+ return hi * 100000000 + mid * 10000 + lo;
154
+ }
155
+
156
+ // ─── Division (96-bit / 16-bit) ──────────────────────────────────────────────
157
+ // Divide 3-chunk bigint by a single small integer (≤ 9999).
158
+ // Algorithm: long division, chunk by chunk.
159
+
160
+ // bigint3_div_chunk(chunk, rem, divisor): quotient of (rem*10000 + chunk) / divisor
161
+ fn bigint3_div_chunk(chunk: int, rem: int, divisor: int): int {
162
+ return (rem * 10000 + chunk) / divisor;
163
+ }
164
+
165
+ // bigint3_rem_chunk(chunk, rem, divisor): new remainder after dividing (rem*10000+chunk)
166
+ fn bigint3_rem_chunk(chunk: int, rem: int, divisor: int): int {
167
+ return (rem * 10000 + chunk) % divisor;
205
168
  }
@@ -0,0 +1,158 @@
1
+ // bits.mcrs — Bitwise operations simulated with integer arithmetic.
2
+ //
3
+ // MC scoreboard has no native bitwise ops. These are implemented using
4
+ // multiply/divide/modulo. Performance is O(32) per operation.
5
+ //
6
+ // For most game logic, these are fast enough. For hot paths (>1000 calls/tick),
7
+ // consider lookup tables or restructuring the algorithm.
8
+ //
9
+ // Supported operations:
10
+ // bit_and, bit_or, bit_xor, bit_not
11
+ // bit_shl (left shift), bit_shr (logical right shift)
12
+ // bit_get (test a single bit), bit_set, bit_clear, bit_toggle
13
+ // popcount (count set bits)
14
+
15
+ module library;
16
+
17
+ // ─── Core: single-bit operations ─────────────────────────────────────────────
18
+
19
+ // bit_get(x, n): return 1 if bit n is set, 0 otherwise. n ∈ [0, 30]
20
+ fn bit_get(x: int, n: int): int {
21
+ let mask: int = 1;
22
+ let i: int = 0;
23
+ while (i < n) { mask = mask * 2; i = i + 1; }
24
+ return (x / mask) % 2;
25
+ }
26
+
27
+ // bit_set(x, n): set bit n to 1. n ∈ [0, 30]
28
+ fn bit_set(x: int, n: int): int {
29
+ let mask: int = 1;
30
+ let i: int = 0;
31
+ while (i < n) { mask = mask * 2; i = i + 1; }
32
+ if ((x / mask) % 2 == 0) { return x + mask; }
33
+ return x;
34
+ }
35
+
36
+ // bit_clear(x, n): clear bit n to 0. n ∈ [0, 30]
37
+ fn bit_clear(x: int, n: int): int {
38
+ let mask: int = 1;
39
+ let i: int = 0;
40
+ while (i < n) { mask = mask * 2; i = i + 1; }
41
+ if ((x / mask) % 2 == 1) { return x - mask; }
42
+ return x;
43
+ }
44
+
45
+ // bit_toggle(x, n): toggle bit n. n ∈ [0, 30]
46
+ fn bit_toggle(x: int, n: int): int {
47
+ let mask: int = 1;
48
+ let i: int = 0;
49
+ while (i < n) { mask = mask * 2; i = i + 1; }
50
+ if ((x / mask) % 2 == 0) { return x + mask; }
51
+ return x - mask;
52
+ }
53
+
54
+ // ─── Shift operations ────────────────────────────────────────────────────────
55
+
56
+ // bit_shl(x, n): left shift x by n bits (x << n). n ∈ [0, 30]
57
+ fn bit_shl(x: int, n: int): int {
58
+ let result: int = x;
59
+ let i: int = 0;
60
+ while (i < n) { result = result * 2; i = i + 1; }
61
+ return result;
62
+ }
63
+
64
+ // bit_shr(x, n): logical right shift x by n bits (x >> n). n ∈ [0, 30]
65
+ // Note: divides by 2^n, truncating toward zero.
66
+ fn bit_shr(x: int, n: int): int {
67
+ let result: int = x;
68
+ let i: int = 0;
69
+ while (i < n) { result = result / 2; i = i + 1; }
70
+ return result;
71
+ }
72
+
73
+ // ─── Bitwise AND / OR / XOR ──────────────────────────────────────────────────
74
+ // These iterate over 31 bits (signed int32, bit 31 is sign).
75
+
76
+ // bit_and(a, b): bitwise AND
77
+ fn bit_and(a: int, b: int): int {
78
+ let result: int = 0;
79
+ let mask: int = 1;
80
+ let i: int = 0;
81
+ while (i < 31) {
82
+ if ((a / mask) % 2 == 1) {
83
+ if ((b / mask) % 2 == 1) {
84
+ result = result + mask;
85
+ }
86
+ }
87
+ mask = mask * 2;
88
+ i = i + 1;
89
+ }
90
+ return result;
91
+ }
92
+
93
+ // bit_or(a, b): bitwise OR
94
+ fn bit_or(a: int, b: int): int {
95
+ let result: int = 0;
96
+ let mask: int = 1;
97
+ let i: int = 0;
98
+ while (i < 31) {
99
+ if ((a / mask) % 2 == 1) {
100
+ result = result + mask;
101
+ }
102
+ if ((b / mask) % 2 == 1) {
103
+ if ((a / mask) % 2 == 0) {
104
+ result = result + mask;
105
+ }
106
+ }
107
+ mask = mask * 2;
108
+ i = i + 1;
109
+ }
110
+ return result;
111
+ }
112
+
113
+ // bit_xor(a, b): bitwise XOR
114
+ fn bit_xor(a: int, b: int): int {
115
+ let result: int = 0;
116
+ let mask: int = 1;
117
+ let i: int = 0;
118
+ while (i < 31) {
119
+ let ba: int = (a / mask) % 2;
120
+ let bb: int = (b / mask) % 2;
121
+ if (ba != bb) {
122
+ result = result + mask;
123
+ }
124
+ mask = mask * 2;
125
+ i = i + 1;
126
+ }
127
+ return result;
128
+ }
129
+
130
+ // bit_not(x): bitwise NOT (inverts all 31 bits, sign bit excluded)
131
+ fn bit_not(x: int): int {
132
+ let result: int = 0;
133
+ let mask: int = 1;
134
+ let i: int = 0;
135
+ while (i < 31) {
136
+ if ((x / mask) % 2 == 0) {
137
+ result = result + mask;
138
+ }
139
+ mask = mask * 2;
140
+ i = i + 1;
141
+ }
142
+ return result;
143
+ }
144
+
145
+ // ─── Popcount ────────────────────────────────────────────────────────────────
146
+
147
+ // popcount(x): count number of set bits (0-31)
148
+ fn popcount(x: int): int {
149
+ let count: int = 0;
150
+ let v: int = x;
151
+ let i: int = 0;
152
+ while (i < 31) {
153
+ if (v % 2 == 1) { count = count + 1; }
154
+ v = v / 2;
155
+ i = i + 1;
156
+ }
157
+ return count;
158
+ }