【问题标题】:Arc4random modulo biasedArc4random 模偏
【发布时间】:2013-07-12 12:19:50
【问题描述】:

根据this documentation

建议arc4random_uniform() 优于arc4random() % upper_bound 之类的结构,因为当上限不是2 的幂时,它可以避免“模偏差”。

偏见有多严重?例如,如果我生成上限为 6 的随机数,使用 arc4random%arc4random_uniform() 有什么区别?

【问题讨论】:

    标签: objective-c random probability arc4random


    【解决方案1】:

    arc4random() 返回一个无符号的 32 位整数,表示值介于 0 和 2^32-1 = 4 294 967 295。

    现在,偏差是由以下事实造成的,即多个子区间是用 模不完全适合随机输出范围。 为了清楚起见,让我们想象一个随机生成器,它创建从 0 到 198 的数字 包括的。您想要从 0 到 99 的数字,因此您计算 random() % 100, 产生 0 到 99:

    0 % 100 = 0
    99 % 100 = 99
    100 % 100 = 0
    198 % 100 = 98

    你看到 99 是唯一一个只能出现一次的数字,而所有 其他可能会在一次运行中出现两次。这意味着 99 的概率 正好减半,这也是偏倚中的最坏情况,其中至少 涉及2个子区间。
    因为所有小于范围间隔的 2 的幂都非常适合 2^32 间隔,这种情况下偏差就消失了。

    其含义是模数越小,结果集越高 随机输出范围越小,偏差越小。在您的示例中, 6 是您的上限 bound(我假设 0 是下限),所以你使用 % 7,结果是 0-3 出现 613 566 757 次,而 4-6 出现 613 566 756 次。
    所以 0-3 是 613 566 757 / 613 566 756 = 1.0000000016298 倍的可能性 超过 4-6。

    虽然看起来很容易忽略,但一些实验(尤其是蒙特卡洛 实验)是有缺陷的,正是因为这些看似不可思议的小 差异非常重要。

    如果所需的输出范围大于,则偏差会更糟 随机目标范围。请阅读Fisher-Yates shuffle 条目 因为许多扑克网站都以艰难的方式学习了正常的线性 同余随机生成器和糟糕的洗牌算法导致 不可能或非常可能的套牌或更糟,可预测的套牌。

    【讨论】:

    • 对问题的出色解释。读者也可能对公开可用的实现感兴趣:opensource.apple.com/source/Libc/Libc-825.26/gen/FreeBSD/… 确实,在许多应用程序中,偏见并不重要,但在程序员确实重要的情况下,它是如此具有破坏性应该始终养成使用_uniform的习惯。
    • 如何避免偏见?
    • @android,通过将您的选择范围缩小到您想要的倍数,然后滚动随机数直到您在范围内。如果你想要一个六面骰子中的随机数 1-4,正确的获得方法是滚动它直到数字在 1 和 4 之间。原理相同。
    • 最简单的方法是在输入“禁止”范围时重新运行随机生成器。例如do { result = arc4random() % 7 } while (result > 4 294 967 292)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    相关资源
    最近更新 更多