@amritk/nish-x86_64-linux 0.21.0 → 0.22.1

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/std/random.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * import { Rng } from "nish/random";
6
6
  *
7
7
  * const r = new Rng(42);
8
- * const die: i32 = 1 + (r.nextI32() >>> 1) % 6;
8
+ * const die: i32 = r.nextInt(1, 6); // 1 to 6, each with equal chance
9
9
  * const u: f64 = r.nextF64(); // in [0, 1)
10
10
  *
11
11
  * The state is one 32-bit integer. Each step adds the odd constant
@@ -24,8 +24,11 @@
24
24
  * two's-complement wrap natively and answer `(a + b) | 0` and `Math.imul(a, b)`
25
25
  * under Node (docs/LANGUAGE.md, "nish:unsafe"); every shift has a constant
26
26
  * count, and `^` and `>>> 16` answer the same 32 bits in JavaScript as in the
27
- * compiled program. `nextF64` builds its double from integers below 2^53, so
28
- * its products and sums are exact both ways. The program a test prints under
27
+ * compiled program. `nextInt` reads its span and its draws as unsigned
28
+ * counts with no `u32` (whose conversions saturate under Node): the sign bit
29
+ * flipped orders them under a signed compare, and the remainder is taken in
30
+ * pieces that stay below 2^31. `nextF64` builds its double from integers
31
+ * below 2^53, so its products and sums are exact both ways. The program a test prints under
29
32
  * Node is the one it prints compiled (docs/RUN_UNDER_NODE.md).
30
33
  *
31
34
  * It is not for cryptography: a key or a nonce comes from
@@ -37,7 +40,7 @@
37
40
  * would be a write their caller can see, and is refused as any such write is;
38
41
  * give each task its own, seeded from its index.
39
42
  */
40
- import { wrappingAdd, wrappingMul } from "nish:unsafe"
43
+ import { wrappingAdd, wrappingMul, wrappingSub } from "nish:unsafe"
41
44
 
42
45
  /** 0x9E3779B9 as an `i32`: the Weyl increment, odd, so the walk visits every state. */
43
46
  const GOLDEN: i32 = -1640531527
@@ -54,6 +57,35 @@ const TWO_26: f64 = 67108864.0
54
57
  /** 2^53, which scales a 53-bit integer into [0, 1). */
55
58
  const TWO_53: f64 = 9007199254740992.0
56
59
 
60
+ /** The sign bit: `x ^ SIGN` orders the bits of `x` as an unsigned count under a signed compare. */
61
+ const SIGN: i32 = -2147483648
62
+
63
+ /** 2^31 - 1, the `i32` just below 2^31, from which `remainder` finds 2^31 mod m. */
64
+ const MAX: i32 = 2147483647
65
+
66
+ /** Whether `a < b` when both are read as unsigned 32-bit counts. */
67
+ const below = (a: i32, b: i32): boolean => (a ^ SIGN) < (b ^ SIGN)
68
+
69
+ /**
70
+ * `a mod m` with both read as unsigned 32-bit counts and `m` not 0. A count
71
+ * of 2^31 or more is a negative `i32`, so it is taken apart into pieces a
72
+ * signed `%` answers the same in JavaScript, and every sum stays below 2^31.
73
+ */
74
+ const remainder = (a: i32, m: i32): i32 => {
75
+ if (m < 0) {
76
+ // m is 2^31 or more, so a is less than 2m: at most one m comes off.
77
+ return below(a, m) ? a : wrappingSub(a, m)
78
+ }
79
+ if (a >= 0) {
80
+ return a % m
81
+ }
82
+ // a is 2^31 + low, so a mod m is low plus 2^31 mod m, added mod m.
83
+ const low: i32 = (a ^ SIGN) % m
84
+ const high: i32 = wrappingAdd(MAX % m, 1) % m
85
+ const room: i32 = wrappingSub(m, high)
86
+ return low >= room ? wrappingSub(low, room) : wrappingAdd(low, high)
87
+ }
88
+
57
89
  /** MurmurHash3's `fmix32`: every bit of `h` into every bit of the answer, a bijection on 32 bits. */
58
90
  const mix = (h: i32): i32 => {
59
91
  let x: i32 = h
@@ -91,4 +123,34 @@ export class Rng {
91
123
  const lo: i32 = this.nextI32() >>> 6
92
124
  return (toF64(hi) * TWO_26 + toF64(lo)) / TWO_53
93
125
  }
126
+
127
+ /**
128
+ * An integer in [lo, hi], both ends included, each with equal chance;
129
+ * `nextInt(1, 6)` is a die. It panics when `lo` is greater than `hi`, and
130
+ * the whole `i32` range, `nextInt(-2147483648, 2147483647)`, is one
131
+ * `nextI32()`.
132
+ *
133
+ * There is no modulo bias: where the span `hi - lo + 1`, an unsigned count
134
+ * up to 2^32, does not divide 2^32 evenly, a draw among the lowest
135
+ * 2^32 mod span is refused and drawn again, and what is left holds every
136
+ * answer equally often. Fewer than half the draws are ever refused, so an
137
+ * answer takes one `nextI32()` step usually and fewer than two on average,
138
+ * and a sequence is still the seed's.
139
+ */
140
+ nextInt(lo: i32, hi: i32): i32 {
141
+ if (lo > hi) {
142
+ panic("Rng.nextInt: lo is greater than hi")
143
+ }
144
+ const span: i32 = wrappingAdd(wrappingSub(hi, lo), 1)
145
+ if (span === 0) {
146
+ return this.nextI32()
147
+ }
148
+ // 2^32 mod span, as (2^32 - span) mod span.
149
+ const refused: i32 = remainder(wrappingSub(0, span), span)
150
+ let draw: i32 = this.nextI32()
151
+ while (below(draw, refused)) {
152
+ draw = this.nextI32()
153
+ }
154
+ return wrappingAdd(lo, remainder(draw, span))
155
+ }
94
156
  }