【问题标题】:Understanding Java Random next Integer with bound algorithm使用绑定算法理解 Java Random next Integer
【发布时间】:2021-06-06 21:05:07
【问题描述】:

我正在研究 Java Random 库在给定上限的情况下生成整数的方式,但我不太了解该算法。在文档中它说:

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

但我真的不明白这个实现是如何考虑到这一点的,特别是代码中的while 条件。对我来说,这似乎(几乎)总是会以 50% 的成功率成功。尤其是在查看 bound 的非常低的值时(我认为在施加界限时经常使用它)。在我看来,while 中的条件只是检查bits 的符号,那么为什么还要打扰他们使用的线路呢?

public int nextInt(int bound) {
   if (bound <= 0)
        throw new IllegalArgumentException("bound must be positive");

      if ((bound & -bound) == bound)  // i.e., bound is a power of 2
        return (int)((bound * (long)next(31)) >> 31);

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

【问题讨论】:

  • 有趣的是ThreadLocalRandom::nextInt的实现方式不同

标签: java random integer


【解决方案1】:

注意bits - val + (bound-1) &lt; 0实际上是在检查bits - val + (bound-1)是否溢出bits 总是等于或大于val,而bound 总是正数,所以正常情况下LHS 不可能是正数。

我们可以将&lt; 0 视为&gt; Integer.MAX_VALUE

让我们绘制bits - val + (bound - 1) 的图表。我在 desmos here 上做了一个。假设 bound 是 100(小范围):

x 轴是bits,y 轴是bits - val + (bound-1),我在x 轴和y 轴上都添加了线条来表示Integer.MAX_VALUE。请注意,bitsInteger.MAX_VALUE 为界。

在这个比例下,您可以看到bits - val + (bound-1) 似乎永远不会溢出。如果你放大很多,你会看到:

请注意,bits 的值范围很小,bits &lt; Integer.MAX_VALUE,但bits - val + (bound - 1) &gt; Integer.MAX_VALUE

对于b = (1 &lt;&lt; 30) + 1,图表如下所示:

任何大于1 &lt;&lt; 30b 都会溢出。因此,如文档所述,拒绝边界的可能性为 1/2。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-05
    • 2017-11-29
    • 1970-01-01
    • 2020-02-07
    • 2012-02-01
    • 2014-01-29
    • 1970-01-01
    相关资源
    最近更新 更多