为什么谷歌Chrome;s Math.random数字生成器不是随机的

Why is Google Chrome's Math.random number generator not *that* random?

本文关键字:随机 数字 Chrome 谷歌 random Math 为什么      更新时间:2023-09-26

我今天在各种浏览器中运行一些单元测试时遇到了一个奇怪的"bug"。在今天之前,我已经在Firefox中运行了很多次测试,甚至在IE中也运行过,但显然还没有在Chrome(v19dev)中运行。当我在Chrome中运行它们时,它一直没有通过一次测试,因为我计算的两个值不匹配。

当我真正深入了解发生了什么时,我意识到问题是我假设如果我用100000个Math.random()值填充一个数组,它们都是唯一的(不会有任何冲突)。在Chrome中发现这不是真的。

在Chrome中,我一直得到至少两对的值,这些值在100000中匹配。Firefox和IE9从未发生过冲突。下面是我为测试这一点而写的一个jsfiddle,它在数组中创建了1M个Math.random()条目:http://jsfiddle.net/pseudosavant/bcduj/

有人知道为什么用于Math.random的Chrome伪随机数生成器真的不是随机的吗?这似乎对任何使用Math.random的客户端js加密例程都有影响。

显然,V8中的Math.random()只适用于32位值(过去甚至没有正确地随机化所有这些值)。使用32位,碰撞的概率在2^16=65k值左右达到50%。。。

其他答案已经解释了这个问题。如果你想在JavaScript中生成更好的伪随机数,我推荐这个页面作为一个好的起点:

http://baagoe.com/en/RandomMusings/javascript/

我将这个页面上的一个算法用于在浏览器中生成UUID的脚本,并且在测试中没有发生冲突。

2013年10月22日更新

链接到上面的页面不再有效。以下是Wayback Machine的快照链接:

http://web.archive.org/web/20120502223108/http://baagoe.com/en/RandomMusings/javascript/

这里有一个指向Node.js模块的链接,其中包括Alea.js:

https://npmjs.org/package/alea

请参阅https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d:

如果我们独立分析第一个子生成器,我们会发现它有32位内部状态。它不是全循环发电机—其实际循环长度约为5.9亿(18030*2⁵-1,数学很难,但这里和这里都有解释,或者你可以相信我)。因此,使用此生成器,我们最多只能生成5.9亿个不同的请求标识符。如果它们是随机选择的,那么在仅生成30000个标识符后,碰撞的几率将50%