来自Java.Random.nextInt()的令人费解的行为

时间:2017-11-04 23:11:12

标签: java

我正在实施一个SkipList。在算法的某一点上,我们要扔一枚硬币,并且只要它不断出现就一遍又一遍地做一些事情,并在我们看到尾巴时立即停止。我通过使用:

让奇数代表“头”
while (R.nextInt() % 2 == 1)

但是这只产生了大约25%的时间(在50,000次呼叫中)。将其更改为

while (R.nextBoolean())
正如预期的那样,

产生头部的一半时间。 R被实例化为随机,用System.currentTimeMillis()播种。看来,Random生成的比特流毕竟不是那么均匀分布的。有没有人见过这种行为?

我也尝试过:

while (Math.random() >= 0.5)

并获得了我期待的50/50(给予或接受)行为。

它似乎也适用于:

while (R.nextInt(2) == 1)

在一半的时间内,LSB 0似乎没有生成32位整数。似乎在比特级别,我们也应该能够期待随机性。也许这是他们正在使用的线性一致性;也许我错过了什么,但这似乎是一个问题。我意识到有更好的PRNG可用,我已经有一些完全可行的解决方案;我只是想报告我观察到的内容。

2 个答案:

答案 0 :(得分:6)

  

nextInt()
  返回下一个伪随机数,从该随机数生成器的序列中均匀分布的int值。

整数类型用Java签名,模式2操作的可能结果是:-1(负奇数),0(偶数),1(正数)奇)。

nextInt() % 2仅对正奇数整数等于1,这就是为什么你只得到25%。您需要对条件进行一些小改动:

 while (R.nextInt() % 2 != 0)

答案 1 :(得分:2)

如果(n*2+1) % 2为负数,则n为-1。 (这很烦人,因为它没有多少数学意义,但它就是它。它与/运算符的工作方式一致,因此(a/b)*b+(a%b)=a对所有ab,除非发生整数溢出。)

由于Random.nextInt()返回带符号的随机数,因此模数将为50%的时间,-1 25%的时间和1 25%的时间。

当然,您可以切换到r.nextInt() % 2 != 0r.nextInt() == 0,但最易读的解决方案确实只是使用r.nextBoolean()