3

这可能看起来更像是一个数学问题,但由于它专门链接到 Javascript 的伪随机数生成器,我想它非常适合 SO。如果没有,请随时将其移至其他地方。

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

15.8.2.14 随机( )

返回一个带正号的数值,大于或等于 0 但小于 1,随机或伪随机选择,在该范围内近似均匀分布,使用与实现相关的算法或策略。此函数不接受任何参数。

到现在为止还挺好。现在我最近偶然发现了来自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)

考虑到上面的代码,具有舍入到最近偶数行为的 IEEE 754 浮点数,在Math.random()范围均匀分布的评估下,我得出结论,它返回通常被排除的上限(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 的(我希望它是前者)。=]任何输入表示赞赏。

4

1 回答 1

2

您不必担心将 Math.random() 中的数字四舍五入到 1。

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

Chrome:这里很简单。它通过生成 32 位数字并将其除以 1 << 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 没有问题。

于 2013-01-12T14:26:59.647 回答