【发布时间】:2013-07-24 10:03:22
【问题描述】:
也就是说,它永远不会使用某些特定的upperBound 参数连续生成超过 16 个偶数:
Random random = new Random();
int c = 0;
int max = 17;
int upperBound = 18;
while (c <= max) {
int nextInt = random.nextInt(upperBound);
boolean even = nextInt % 2 == 0;
if (even) {
c++;
} else {
c = 0;
}
}
在此示例中,代码将永远循环,而当upperBound 为例如 16 时,它会快速终止。
这种行为的原因可能是什么?该方法的javadoc中有一些注释,但我没有理解它们。
UPD1:代码似乎以奇数上限终止,但可能会卡在偶数上限
UPD2:
我修改了代码以按照 cmets 中的建议捕获 c 的统计信息:
Random random = new Random();
int c = 0;
long trials = 1 << 58;
int max = 20;
int[] stat = new int[max + 1];
while (trials > 0) {
while (c <= max && trials > 0) {
int nextInt = random.nextInt(18);
boolean even = nextInt % 2 == 0;
if (even) {
c++;
} else {
stat[c] = stat[c] + 1;
c = 0;
}
trials--;
}
}
System.out.println(Arrays.toString(stat));
现在它尝试在行中达到 20 偶数 - 以获得更好的统计数据,而 upperBound 仍然是 18。
结果令人惊讶:
[16776448, 8386560, 4195328, 2104576, 1044736,
518144, 264704, 132096, 68864, 29952, 15104,
12032, 1792, 3072, 256, 512, 0, 256, 0, 0]
起初它按预期减少了 2 倍,但请注意最后一行!在这里它变得疯狂,捕获的统计数据似乎完全奇怪。
这是一个对数刻度的条形图:
c 如何获得 17 256 次的值是另一个谜
【问题讨论】:
-
您能否在将
c设置为0之前打印出来,看看您可以连续获得的偶数数量是否有任何规律?另外,这如何表明它有偏见?奇数的行为是否不同?所有这些都表明它并不是真正随机的。但我们已经知道了。 -
不是答案,但如果您改用
SecureRandom,代码会按预期终止。 -
LCG 是出了名的糟糕,尤其是在它们的低位。对于任何严重使用随机数,如模拟或蒙特卡洛方法,LCG 是完全不可接受的。使用良好的外部 PRNG 库。
-
为什么它应该连续提供> 16个偶数,范围为18?你肯定不能合理地期望超过 18 个中的 9 个?
-
@EJP 如果它真的是随机的,17 个连续的偶数应该平均每 2^17 个数字或 130k 发生一次。这是使用更好的生成器时观察到的结果。