【问题标题】:Uniform distribution of integers using floating point source使用浮点源均匀分布整数
【发布时间】:2015-09-02 18:33:21
【问题描述】:

在 JavaScript 或任何其他仅提供 random() 函数返回 [0,1) 范围内的浮点数的语言中,获取 [0, n) 范围内的随机整数的标准方法是使用Math.floor(Math.random() * n)

现在,假设我们正在对有理数集进行运算,这背后的数学是微不足道的。问题是:由于 IEEE-754 浮点数的所有复杂性,得到的分布实际上真的均匀吗?

考虑到一个浮点数和下一个更高的浮点数之间的差距随着它们的变大而增加,我认为这应该会引入某种对较小数字的偏见。

【问题讨论】:

  • 这个查询一般吗?或者你想解决什么问题?
  • @Richard 求知欲。
  • 不太可能完全一致:在 Math.random 以相等概率生成 2^53 个不同结果的合理假设下,我们只能得到准确的 n 值的一致结果2^53 的除数。例如,对于n=5,如果我们将2^53 不同的元素分成5 个bin,那么无论我们怎么做,这些bin 中的元素数量都不可能相同。
  • 另请参阅bugs.python.org/issue23974,了解 Python 2 中的相关问题,其中存在严重的偏差,因为 n 接近 2^53。 (该问题已在 Python 3 中修复。)

标签: javascript algorithm random floating-point statistics


【解决方案1】:

不,对于n 的大多数值,生成的分布不会完全一致。对于较小的值,它将非常接近均匀分布,以至于您很难检测到与均匀分布的任何差异,但随着 n 变大,偏差会变得明显。

为了说明,这里有一些 Python 代码(不是 JavaScript,对不起,但原理是一样的):

from collections import Counter
from random import random

def badrand(n):
    return int(random() * n)

print(Counter(badrand(6755399441055744) % 3 for _ in range(10000000)))

这将在[0, 6755399441055744) 范围内生成 1000 万个随机整数,将这些整数中的每一个以 3 取模,并计算余数为 0、1 或 2 的次数。如果我们统一生成这些整数,我们希望余数模 3 大致均匀分布,因此我们希望计数相似。

这是在我的机器上运行的示例结果:

Counter({1: 3751915, 0: 3334643, 2: 2913442})

也就是说,1 的剩余部分显着0 更可能发生,而0 的剩余部分又比2 的剩余部分更可能发生。这里的差异方式太大了,无法用随机变化来解释。

所以出了什么问题? Python 的random() 函数质量相对较高,基于Mersenne Twister,因此我们不太可能看到由基本随机数生成器导致的统计问题。正在发生的事情是random() 生成 2^53 个(大致)同样可能的结果之一 - 每个结果都是x / 2^53 形式的数字,用于x 范围内的某个整数[0, 2^53)。现在在badrand 调用中,我们有效地将这些结果映射到6755399441055744 可能的输出。现在该值不是随机选择的(哈!);它正好是 2^53 的 3/4。这意味着在可能的最均匀分布下,可能的 badrand 输出值的 2/3 恰好被 2^53 个可能的 random() 输出值之一命中,而其他 1/3 被 两个 2^53 个可能的random() 输出值。也就是说,某些潜在输出发生的可能性是其他输出的 两倍。所以我们离制服还有很长的路要走。

您将在 JavaScript 中看到相同的效果。在 Chrome 的情况下,there are only 2^32 distinct results 似乎来自Math.random(),因此您应该能够找到类似上述的效果,n 小于(但接近)2^32。

当然,同样的效果也适用于小的n:如果n = 5,那么因为5 不是2^32 的除数,我们不可能完美地均匀分布所有2^32 可能的@ 5 个期望结果之间的 987654350@ 结果:我们可以希望的最好结果是,5 个结果中的 4 个出现在可能的 random() 结果中的 858993459 个中,而第五个出现在 random() 结果中的 858993460 个中。但是这种分布将非常接近均匀,几乎不可能找到任何统计测试来告诉你不同的情况。因此,出于实际目的,您应该使用小的n 安全。

http://bugs.python.org/issue9025 上可能有一个相关的 Python 错误。通过摆脱计算这些数字的int(random() * n) 方法,Python 3 解决了该错误。不过,Python 2 中的错误仍然是 remains

【讨论】:

  • 无需道歉 - 我发现 python 方式 比 JavaScript 或 TypeScript 更有吸引力 - Python 的“包含电池”部分只是不会让我考虑诸如此类的问题一个是因为有一个很好的random.randInt() 函数(我们可以看到不一定)会处理它:-)
【解决方案2】:

如果Math.random(或等效项)从与 [0, 1) 范围内的浮点数对应的那些位模式中生成了一个均匀分布的位模式,那么它将产生一个非常有偏差的样本。 [0.25, 0.5) 中的可表示浮点数与 [0.5, 1.0) 中的浮点数一样多,这与 [0.125, 0.25) 中的可表示值的数量相同。等等。简而言之,均匀分布的位模式将导致千分之一的值介于 0.5 和 1.0 之间。 (假设双精度浮点数。)

幸运的是,Math.random 不是这样做的。获得均匀分布数(而不是位模式)的一种简单方法是在 [1.0, 2.0) 中生成均匀分布的位模式,然后减去 1.0;这是一个相当普遍的策略。

无论如何,由于量化偏差,Math.floor(Math.random() * n) 的最终结果不是很均匀分布,除非n 是 2 的幂。 Math.random 可以返回的可能浮点值的数量是 2 的幂,如果 n 不是 2 的幂,那么不可能将可能的浮点值精确均匀地分布在[0, n) 中的整数。如果Math.random 返回一个双精度浮点数,而n 不大,那么这个偏差很小,但它肯定存在。

【讨论】:

    【解决方案3】:

    根据http://es5.github.io/x15.8.html#x15.8.2.14

    Math.random 的功能

    返回一个大于等于 0 的正号数值 但小于 1,随机或伪随机选择,大约 在该范围内均匀分布,使用 依赖于实现的算法或策略。这个函数不需要 论据。

    查看这篇文章: https://stats.stackexchange.com/questions/40384/fake-uniform-random-numbers-more-evenly-distributed-than-true-uniform-data

    这已经超出了我的想象,对不起,我没有什么可以贡献的了

    【讨论】:

    • 给出高斯分布(也称为正态分布)。均匀分布要简单得多:每个数字都应该同样频繁地出现。
    【解决方案4】:

    假设 random() 返回一个介于 0..1 之间的数字。

    如果结果是单精度浮点数,那么基于尾数的熵只有 23 位。

    如果结果是双精度浮点数,那么基于尾数的熵只有 52 位。

    所以 floor(random() * N) 只会在 N 小于 2^24 或 2^53 时是统一的。

    编辑这里有一些关于浮点http://www.mathworks.com/help/matlab/ref/flintmax.html的最大连续整数的信息

    【讨论】:

    • 双精度数是 53 位的熵:通常的方法是产生x / 2^53 形式的数字,其中x 是一个(大致)均匀分布在[0, 2^53) 中的整数。是的,如果排除隐藏位,有效位只有 52 位,但您还需要考虑指数。
    • @MarkDickinson - 当你发表评论时,我正在编辑它并添加最大的连续整数引用。
    • 我应该更清楚一点:没错,即使在最好的情况下,只要双精度数甚至可以代表每个数字,这也可以工作。我想知道的是它是否实际上是统一的。
    【解决方案5】:

    我假设您所说的“一个浮点数与下一个更高的浮点数之间的差距随着它们的变大而增加”是基于以下几点:

    在 IEEE-754 中,您有一个固定大小的尾数,它允许在 [1,2) 范围内统一“随机”值,并且在 [2,4) 中有相同数量的可能值,这是两倍尽可能大的范围,所以我们在可能的值之间得到 2 倍的间距,对于 [4,8) 等也是两倍大。

    现在,当他们谈论为 [0,1) 生成的随机数的属性时,我还没有查看“..,使用依赖于实现的算法或策略”背后的技术细节,但由于上述考虑是如此微不足道,我确实假设随机生成器程序员已经意识到这一点并使用“依赖于实现的算法......”来处理它。

    因此,作为一个天真的人,我相信对于(我的假设)你的怀疑理由没有什么可担心的。事实上,我可能会认为,如果您可以为尾数生成统一和随机的值,然后始终设置相同的指数,使得这些值属于 [1,2),那么您从所有内容中减去 1 并具有适当的分布对于 [0,1)。

    【讨论】:

    • 问题是在假设 [0,1) 是均匀的情况下应用该变换时,[0, n) 上的分布是否均匀。
    • 是什么让您怀疑“简单地”乘以 n 会破坏一致性?当然,舍入可能会影响精确的“复制”,但舍入也可能是相当均匀的,例如,如果 n 是 2 的倍数,整个事情就相当于只移动指数,均匀性不会受到影响全部。
    • 阅读 Mark 的回答,了解为什么会发生这种情况,包括显示偏差的代码。是的,如果 n 是 2 的倍数,您将不会遇到问题,但在任何其他情况下您都会遇到问题。这里的见解是,这只是一个整数随机生成器,周期为 [0, 2^(k+1)),其中 k 是浮点数的重要部分,所有相同的限制都适用。
    猜你喜欢
    • 2020-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-10
    • 2021-03-30
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多