export class Rng { genU32() { throw new Error('not implemented'); } // precisely mirrors Rust's `rand::Rng::gen_range()` for `Range` genRange(min, max) { let range = max - min; let zone = (range << Math.clz32(range)) - 1 >>> 0; let v, lo, hi; do { v = this.genU32(); lo = Math.imul(v, range) >>> 0; // (u32) (v * range) } while (lo > zone); hi = BigInt(v) * BigInt(range) >> 32n; return min + Number(hi); } } export class SplitMix64 extends Rng { constructor(seed) { super(); this.seed = BigInt(seed); } clone() { return new this.constructor(this.seed); } genU32() { this.seed = BigInt.asUintN(64, this.seed + 0x9E3779B97F4A7C15n); let z = this.seed; z ^= BigInt.asUintN(64, z >> 33n); z = BigInt.asUintN(64, z * 0x62A9D9ED799705F5n); z ^= BigInt.asUintN(64, z >> 28n); z = BigInt.asUintN(64, z * 0xCB24D0A5C88C35B3n); return Number(z >> 32n); } }