I took the mother of all random number generators from Agner Fog's library and attempted to make a JavaScript version of this. I expect the bit pattern to be identical but this doesn't seem to be the case and I wonder why or if I made a mistake?
The C++ code I use can be found here. It's from Agner Fog's website.
Here's my TypeScript version of this code
const u = (function () {
const b = new ArrayBuffer(8)
return {
u32: new Uint32Array(b),
u64: new BigUint64Array(b),
}
})()
export class Random {
state = new Uint32Array(5)
constructor(seed?: number) {
this.seed(seed ?? +new Date())
}
b() {
const { state: x } = this
u.u64[0] =
2111111111n * BigInt(x[3]) +
1492n * BigInt(x[2]) +
1776n * BigInt(x[1]) +
5115n * BigInt(x[0]) +
BigInt(x[4])
console.debug(u.u64[0])
x[3] = x[2]
x[2] = x[1]
x[1] = x[0]
x[4] = u.u32[1]
x[0] = u.u32[0]
return x[0]
}
next() {
return (1 / 4_294_967_296) * this.b()
}
seed(seed: number) {
const { state: x } = this
let s = seed >>> 0
// make random numbers and put them into the buffer
for (let i = 0; i < 5; i++) {
s = s * 29943829 - 1
x[i] = s
}
console.debug(x)
// randomize some more
for (let i = 0; i < 19; i++) {
this.b()
}
}
}
I managed to get it down to the the state initialization but I cannot understand why the output from the C++ program is 4294967295, 4265023466, 1627457073, 3925469700, 2226377299 but the TypeScript program is giving me 4294967295, 4265023466, 1627457073, 3925868544, 0. Only the first 3 numbers get computed exactly the same. Any help trying to understand this is much appreciated.
Ah, I figured it out. I have to use
Math.imulto get correct results. Can't do C-like integer multiplication without it.So, this:
...changes into:
I tried stuff like
(s * 29943829) >>> 0but this is not enough to force C style integer multiplication.