此功能来自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;
}
我的问题是:
n
是2的幂的情况?这仅仅是为了表现吗?bits - val + (n-1) < 0
?答案 0 :(得分:7)
next
生成随机位。
当n
是2的幂时,只能通过生成随机位来生成该范围内的随机整数(我假设始终生成31并抛出一些是为了再现性)。这段代码路径更简单,我想这是一个更常用的案例,所以值得为这种情况制作一个特殊的“快速路径”。
当n
不是2的幂时,它会抛弃范围“顶部”的数字,以便随机数均匀分布。例如。想象我们有n=3
,想象我们使用3位而不是31位。所以bits
是0到7之间随机生成的数字。如何在那里生成一个公平的随机数?答:如果bits
为6或7,我们将其扔掉并生成一个新的。
答案 1 :(得分:7)
这样做是为了确保0
和n
之间的值的均匀分布。你可能想做类似的事情:
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的小幂,则连续调用此方法。
重点是我的。