JavaScript自定义伪随机数生成器连续调用产生0

3

我正在尝试将旧的 C 标准库函数 rand() 移植到 JavaScript 中,仅作测试之用。我不打算在实际场景中使用,所以请不要担心其安全性问题。
这是该函数的 C 语言实现:

seed = seed * 1103515245 + 12345;
return (seed/65536) % 32768;

在这个例子中,32768 是 RAND_MAX。因此,我尝试将其移植到 Javascript:

Random = function(p) {
  this.s = p;
  this.rand = function() {
    this.s = this.s * 1103515245 + 12345;
    return Math.floor((this.s / 65536) % 32768);
  };
};

let r = new Random(Math.floor(new Date() / 1000));
console.log(r.rand()); // gives expected results
console.log(r.rand()); // second call produces 0

当我第一次调用r.rand()时,它会产生预期的结果。但是每次连续调用r.rand()都只会给我返回0,我很好奇为什么...

2
我猜测,没有深入研究,数学计算在处理大数字时出现了错误。 - epascarello
1
@epascarello 你的理论是正确的。因为在C语言中,整数溢出只是将位数重新循环,而在JavaScript中我不认为会发生这种情况。所以添加一个%符号,这样就可以使用2^32-1来解决问题了。 - Irelia
1
你的数字已经超过了 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER - Lee Taylor
@Nina。如果你有一个可行的解决方案,请添加一个答案。 - Lee Taylor
1
是的 @LeeTaylor,我刚意识到现在位并没有像C语言中的数据类型那样受限制。 - Irelia
显示剩余2条评论
1个回答

4
问题在于这一行代码:this.s = this.s * 1103515245 + 12345; 显著地增加了 this.s 的值,因此通过添加模数 232 – 1,可以将数字限制在产生预期结果的范围内,就像在 C 中一样。
rand() {
  this.seed = (this.seed*1103515245 + 12345) % 4294967295;
  return (this.seed / 65536) % 32768;
}

这可能不是最好的解决方案,但似乎确实解决了问题。
在这种情况下,模数Number.MAX_SAFE_INTEGER也可以使用,但由于目标是与C同步,232 – 1也能正常工作。


1
不错的发现。这是我没有完全注意到的js的细微之处。 - Lee Taylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接