Java Random类,使用相同的种子和nextBytes()生成重复的数字?

时间:2011-06-24 02:22:04

标签: java random duplicates random-seed

假设我通过使用新的Random()实例化静态最终Random对象来使用相同的种子,是否可以通过在同一实例中调用nextBytes来获得相同的数字两次?

我知道对于任何给定的种子,可以确定所有可能的“随机”数字,它实际上更像是一个序列:

  synchronized protected int next(int bits) {
     seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
     return (int)(seed >>> (48 - bits));
}

所以基本上如果我有这个代码:

private static final Random random = new Random();

 public void doSomething() {
   for (int i=0; i < 1000000000; i++) {
      byte byteArray[] = new byte[8];
      random.nextBytes(byteArray)
   }
 }

nextBytes在通过它可以生成的所有可能数字之前生成相同字节的可能性有多大??

在返回给定位的所有可能组合之前,它会返回相同的值吗?我猜是的,但这种情况多久发生一次?。

3 个答案:

答案 0 :(得分:5)

Random使用具有非常大周期的线性同余生成器。它很长时间都不会重复int值。使用8字节数组调用nextBytes会生成两个int值,并将每个值分成四个8位值来填充数组。

我认为连续调用nextBytes不可能生成相同的值。这意味着随机数生成器的周期为2. docs指定next的特定行为,这使得这不可能。 (当然,Random的子类可以有任何你喜欢的病态行为,但java.util.Random的实例会表现得很好。)

答案 1 :(得分:0)

nextBytes返回与前一次迭代中返回的值相同的值的概率与nextBytes返回任何特定随机八字节的概率完全相同。

一个好的随机数生成器不会对将返回的位做出任何保证,除了这些位是随机的这一事实。有时需要让一个生成器以随机顺序返回所有可能的值,但这通常不是随机生成器的目标。

答案 2 :(得分:0)

上面的答案表明重复相同的值不会发生似乎忘记了Java.Random的周期长度为2 ^ 48。因此,nextInt()完全有可能在RNG周期中的所有值之前生成完全相同的整数。实际上是2 ^ 16次。

此外,由于整数被分成四个,即使我们必须遍历所有整数,也会出现相同的字节。实际上,如果是这种情况,在我们遍历所有整数值之前,每个字节值将出现2 ^ 24次。但是,我知道原始问题涉及一个由8个字节组成的字节数组。对于这种情况,我们将在2 ^ 31(对于Java的Random)调用nextByte之后得到相同的数组(因为我们需要两个整数)。

正如我之前所说,我们不需要经历所有整数。

话虽如此,如果我们假设nextInt()返回的值的均匀分布,那么在一系列n个样本中获得完全相同的整数的概率是 约1 - ((2 ^ 32 -1)/ 2 ^ 32)^(n(n-1)/ 2)。见http://en.wikipedia.org/wiki/Birthday_problem

我们需要绘制的样本数大于50%的样本数才有两个匹配的整数只有77000多一点。如果我们现在假设我们改为统一绘制一个2 ^ 64的数字,或者两个2 ^ 32个整数(对于8个字节),然后我们在5 * 10 ^ 9个样本之后得到相同的概率,大约是2 ^ 32。请注意,即使到那个时候,我们可以看到所有整数,这仍然比Random的周期短得多。事实可能介于两者之间。无论如何,概率非常低,但并不完全为零,如上文所述。

我错过了什么吗?