首页 > 解决方案 > 将 C++ 程序翻译成 JavaScript/asm.js 不会产生相同的数字序列

问题描述

我从 Agner Fog 的库中获取了所有随机数生成器的母亲,并尝试制作它的 JavaScript 版本。我希望位模式是相同的,但情况似乎并非如此,我想知道为什么或者我是否犯了错误?

我使用的 C++ 代码可以在这里找到。它来自 Agner Fog 的网站

这是我的 TypeScript 版本的代码

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()
    }
  }
}

我设法把它归结为状态初始化,但我不明白为什么 C++ 程序的输出是4294967295, 4265023466, 1627457073, 3925469700,2226377299但是 TypeScript 程序给了我4294967295, 4265023466, 1627457073, 3925868544, 0. 只有前 3 个数字的计算结果完全相同。非常感谢任何试图理解这一点的帮助。

标签: javascriptc++v8low-levelasm.js

解决方案


啊,我想通了。我必须使用Math.imul才能获得正确的结果。没有它就不能做类似 C 的整数乘法。

所以这:

for (let i = 0; i < 5; i++) {
  s = s * 29943829 - 1
  x[i] = s
}

...更改为:

for (let i = 0; i < 5; i++) {
  s = Math.imul(s, 29943829) - 1
  x[i] = s
}

我尝试过类似的东西,(s * 29943829) >>> 0但这还不足以强制 C 风格的整数乘法。


推荐阅读