java.util.Random.nextInt的实现

时间:2014-12-16 13:06:08

标签: java random

此功能来自java.util.Random。它返回在int和给定0之间均匀分布的伪随机n。不幸的是我没有得到它。

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

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

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

我的问题是:

  1. 为什么它会特别处理n是2的幂的情况?这仅仅是为了表现吗?
  2. 为什么它会拒绝bits - val + (n-1) < 0
  3. 的数字

2 个答案:

答案 0 :(得分:7)

next生成随机

  1. n是2的幂时,只能通过生成随机位来生成该范围内的随机整数(我假设始终生成31并抛出一些是为了再现性)。这段代码路径更简单,我想这是一个更常用的案例,所以值得为这种情况制作一个特殊的“快速路径”。

  2. n不是2的幂时,它会抛弃范围“顶部”的数字,以便随机数均匀分布。例如。想象我们有n=3,想象我们使用3位而不是31位。所以bits是0到7之间随机生成的数字。如何在那里生成一个公平的随机数?答:如果bits为6或7,我们将其扔掉并生成一个新的。

答案 1 :(得分:7)

这样做是为了确保0n之间的值的均匀分布。你可能想做类似的事情:

int x = rand.nextInt() % n;

但这会改变值的分布,除非n是2^31的除数,即2的幂。这是因为模运算符会产生大小不相同的等价类。

例如,假设nextInt()生成0到6之间的整数(包括0和6),你想绘制0,1或2.简单,对吧?

int x = rand.nextInt() % 3;

没有。让我们看看为什么:

0 % 3 = 0
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
6 % 3 = 0

所以你有3个映射在0的值,只有2个映射在1和2上的值。你现在有偏差,因为0更可能被返回而不是1或2。

与往常一样,javadoc记录了这种行为:

  

树篱“大约”仅用于前面的描述中   因为下一个方法只是一个无偏见的来源   独立选择的位。如果它是随机的完美来源   选择的位,然后显示的算法将从中选择int值   所述范围具有完美的均匀性。

     

算法有点棘手。 拒绝可能产生的价值   分布不均(由于2 ^ 31不可分割的事实   由n)。值被拒绝的概率取决于n。该   最坏的情况是n = 2 ^ 30 + 1,拒绝的概率是1/2,   并且循环终止前的预期迭代次数为2。

     

算法处理n为2的幂的情况:it   从底层返回正确数量的高位   伪随机数发生器。在没有特殊待遇的情况下   将返回正确数量的低位。线性   同余的伪随机数生成器,如一个   众所周知,这个类实现了短期   它们的低位比特的值序列。因此,这种特殊情况   大大增加了返回的值序列的长度   如果n是2的小幂,则连续调用此方法。

重点是我的。