通过Math.random()获得通常排除的上限的几率

时间:2013-01-11 23:02:37

标签: javascript

这可能看起来更像是一个数学问题,但由于它与Javascript的伪随机数生成器完全相关,我认为它非常适合SO。如果没有,请随意将其移至其他地方。

首先,我知道ES没有指定在伪随机数生成器中使用的算法 - Math.random() - ,但它确实指定范围应该具有近似均匀分布:< / p>

  

15.8.2.14 random ( )

     

使用依赖于实现的算法或策略,返回具有正号,大于或等于0但小于1的Number值,随机或伪随机选择在该范围内近似均匀分布 。这个函数不带参数。

到目前为止,这么好。现在我最近偶然发现了来自MDN的这段数据:

  

请注意,由于JavaScript中的数字是具有舍入到最近偶数行为的IEEE 754浮点数,因此这些范围(不包括Math.random()本身的范围)并不精确,并且取决于它的界限在非常罕见的情况下(大约 1 in 2 ^ 62 )可以计算通常排除的上限。

好。它让我进行了一些测试,结果显然在Chrome控制台和Firefox的Firebug上是相同的:

>> 0.99999999999999995
1
>> 0.999999999999999945
1
>> 0.999999999999999944
0.9999999999999999

让我们用一个简单的实际例子来说明我的问题:

Math.floor(Math.random() * 1)

考虑到上面的代码,在Math.random()范围均匀分布的评估下,IEEE 754浮点数具有舍入到最接近的行为,我得出结论,它返回通常被排除的上层的可能性绑定(我上面的代码中的1)将是0.000000000000000055555...,大约为1/18,000,000,000,000,000

现在查看MDN号码,1/2^62评估为1/4,611,686,018,427,387,904,即比我的计算结果小200多倍。

我做错了数学吗? Firefox的伪随机数生成器是不是均匀分布不足以产生这200倍的差异?

我知道如何解决这个问题,而且我知道每天的使用都不应该考虑这么小的几率,但是我很想知道这里发生了什么,如果我的数学被打破了或者Mozilla的(我希望它是前者)。 =]感谢任何意见。

1 个答案:

答案 0 :(得分:2)

您不应该担心将数字从Math.random()舍入到1。

当我在当前版本的IE,Chrome和FF中查看实现(从我得到的结果推断)时,有几个观察结果几乎肯定意味着你应该总是在0到0的间隔内得到一个数字。 0.11111111111111111111111111111111111111111111111111111二进制(0.999999999999999944.toString(2)和一些较小的十进制数字也是btw。)。

Chrome:这里很简单。它通过生成32位数并将其除以1&lt;&lt;&lt; 32.(你可以看到(1 << 30) * 4 * Math.random()总是返回一个整数。)

FF:这里似乎总是生成的数字最多为0.11 ...(53x 1),它实际上只使用了那些53位小数。 (您可以看到Math.random().toString(2).length - 2的返回次数不超过53次。

IE:这里与FF非常相似,只是如果小数点后面的第一个数字是0,那么位数可以更多,而且肯定不会舍入到1。 (您可以看到Math.random().toString(2).match(/1[01]*$/)[0].length的返回次数不超过53次。

我认为(虽然我现在无法提供任何证据),任何实施都应落到其中一个描述的组中,并且没有问题可以舍入到1。