今天,当我在各种浏览器中运行一些单元测试时,我遇到了一个奇怪的“bug”。我在今天之前已经多次在Firefox中运行测试,甚至IE,但显然还不是Chrome(v19-dev)。当我在Chrome中运行它时,它始终无法通过一次测试,因为我计算的两个值不匹配。
当我真正挖掘正在发生的事情时,我意识到问题在于我假设如果我填充了一个具有100,000 Math.random()
值的数组,那么它们将是唯一的(不会有任何碰撞) 。事实证明,在Chrome中并非如此。
在Chrome中,我始终获得至少两个对的值,这些值与100,000匹配。 Firefox和IE9从未发生过冲突。这是我写的一个jsfiddle,用于测试它在数组中创建1M Math.random()
个条目:http://jsfiddle.net/pseudosavant/bcduj/
有谁知道为什么用于Math.random
的Chrome伪随机数生成器实际上不是 随机?这似乎对任何使用Math.random
的客户端js加密例程都有影响。
答案 0 :(得分:28)
显然是V8 only works with 32 bit values中的Math.random()(并且甚至没有正确地随机化所有这些过去)。并且对于32位,碰撞的概率在2 ^ 16 = 65k值附近达到50%......
答案 1 :(得分:4)
其他答案解释了这个问题。如果您在JavaScript中使用更好的伪随机数生成,我建议将此页面作为开始的好地方:
http://baagoe.com/en/RandomMusings/javascript/
我改编了one of the algorithms on this page用于在浏览器中生成UUID的脚本,并且在我的测试中没有碰撞。
上面链接的页面不再有效。这是来自Wayback Machine的快照的链接:
http://web.archive.org/web/20120502223108/http://baagoe.com/en/RandomMusings/javascript/
这是一个包含Alea.js的Node.js模块的链接:
答案 2 :(得分:4)
请参阅https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d:
如果我们独立分析第一个子生成器,我们会发现它有32位的内部状态。它不是一个全周期发生器 - 它的实际周期长度约为5.9亿(18,030 *2¹-1,数学很棘手,但它在这里和这里都有解释,或者你可以相信我)。因此,我们只能使用此生成器生成最多5.9亿个不同的请求标识符。如果它们是随机选择的,那么在生成30,000个标识符之后会有 50%的碰撞机会。