【问题标题】:Why 2^31 is not divisible by n?为什么 2^31 不能被 n 整除?
【发布时间】:2013-11-24 15:27:47
【问题描述】:

http://docs.oracle.com/javase/6/docs/api/java/util/Random.html#nextInt%28int%29 说:

算法有点棘手。它拒绝可能导致的值 分布不均匀(由于 2^31 不可整除 由 n)。一个值被拒绝的概率取决于 n。这 最坏的情况是 n=2^30+1,拒绝的概率是 1/2, 循环终止前的预期迭代次数为 2。

算法:

int bits, val;
do {
    bits = next(31);
    val = bits % n;
} while (bits - val + (n-1) < 0);

代码测试n &gt; 2^30bits &gt; n 的情况。然后设置最高有效位并将条件中的结果变为负数。

我知道bits 最多是2^31-1 => 有 50% 的概率。 bits 可以是


不管怎样,

  1. 为什么 2^31 不能被 n 整除
  2. 为什么只有两个数都>2^30才有效?

我猜是一些二进制除法魔法,一种破坏均匀分布的溢出?

谢谢!

【问题讨论】:

  • 2^31 是 2147483648 ,在您可以为 n 选择的所有 2147483648 个值中,2147483648 只能除以其中的 32 个。

标签: java random division


【解决方案1】:

当您想从较大范围内的随机数生成较小范围内的随机数时,就会出现此问题,其中较小范围的大小不能被较大范围的大小整除。

如果您有一个介于 0 和 9(含)之间的随机数并想将其更改为介于 0 和 3 之间的一个,如果您只是以 n%4 的方式简单地执行此操作,那么您将有 3/10 的机会获得0(0、4 或 8)%4,但有 2/10 的机会获得 3(3 或 7)%4。解决这个问题的最简单方法是重新生成大于 7 的随机数。

它所说的最坏情况是较小范围的大小刚刚超过较大范围大小的一半,因此您将不得不重新生成超过一半的时间。

【讨论】:

  • 嗯,谢谢,听起来很有趣。为什么它只测试n &gt; 2^30 而不是,例如n=13?因为范围(2^31)太大以至于每个数字0..12的概率差异没有影响?
  • @topolik:测试 n>2^30 在哪里?我没有看到这样的代码行。代码测试 n 是否是 to 的幂。
  • @DanielR 对n&gt;2^30 的测试来自while 条件(bits - val + (n-1) &lt; 0)。为了能够设置最高有效位,n > 2^30
  • 你误解了这一行。该行检查是否 val 不应该使用的上段部分。
  • 你能解释一下吗?我不明白这句话:/
【解决方案2】:

2^31 只能被一个幂或 2 整除。当您检查代码时,这种特殊情况将单独处理,无需循环。描述与拒绝过程有关,n不是2的幂。

【讨论】:

    【解决方案3】:

    关于第一个问题:

    按照我的理解,据说2^31不能被n整除时会导致分布不均。

    很抱歉,我不知道第二个问题。

    【讨论】:

      猜你喜欢
      • 2013-12-09
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 2012-05-27
      • 1970-01-01
      • 2014-01-17
      相关资源
      最近更新 更多