/ proof-of-concept / cymplay
Sign in
proof-of-concept / cymplay
cymplay / src / model / rng.ts
39 lines · 1.3 KBBlameHistoryRaw
1// Seedable pseudo-random generator for the imperfections: xoshiro128** seeded through splitmix32.
2// It is not numpy's PCG64, so a seed gives a different dent pattern than the Python package
3// (same statistics, different sample); within the web app a seed is reproducible.
5export class Rng {
6 private s = new Uint32Array(4);
8 constructor(seed: number) {
9 let x = (seed >>> 0) ^ 0x9e3779b9;
10 for (let i = 0; i < 4; i++) {
11 x = (x + 0x9e3779b9) >>> 0;
12 let z = x;
13 z = Math.imul(z ^ (z >>> 16), 0x85ebca6b) >>> 0;
14 z = Math.imul(z ^ (z >>> 13), 0xc2b2ae35) >>> 0;
15 this.s[i] = (z ^ (z >>> 16)) >>> 0;
16 }
17 }
19 next32(): number {
20 const s = this.s;
21 const r = Math.imul(rotl(Math.imul(s[1], 5) >>> 0, 7), 9) >>> 0;
22 const t = (s[1] << 9) >>> 0;
23 s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3];
24 s[2] ^= t;
25 s[3] = rotl(s[3], 11);
26 return r;
27 }
29 /** Uniform double in [0, 1) with 53 random bits. */
30 random(): number {
31 const hi = this.next32() >>> 5, lo = this.next32() >>> 6;
32 return (hi * 67108864 + lo) / 9007199254740992;
33 }
35 uniform(lo: number, hi: number): number { return lo + (hi - lo) * this.random(); }
36 sign(): number { return this.random() < 0.5 ? -1 : 1; }
39function rotl(x: number, k: number): number { return ((x << k) | (x >>> (32 - k))) >>> 0; }
↑↓ move↵openescclose