Java 随机长,可以是同一个数字连续两次吗

Java 随机长,可以是同一个数字连续两次吗,java,random,Java,Random,我想知道,对于Random类的当前Java1.7实现,下面的代码是否可以生成两倍于相同随机长度的代码 Random rand = new Random((long) "some seed".hashCode()); while(rand.nextLong() != rand.nextLong()){ } System.out.println("Will this text ever be on the console?"); nextLong()和next()的Java源代码 public

我想知道,对于Random类的当前Java1.7实现,下面的代码是否可以生成两倍于相同随机长度的代码

Random rand = new Random((long) "some seed".hashCode());
while(rand.nextLong() != rand.nextLong()){

}

System.out.println("Will this text ever be on the console?");
nextLong()和next()的Java源代码

public long nextLong(){
返回((长)下一个(32)>(48位));
}

我会用false来回答这个问题,因为我认为java使用的random方法不会在2^48周期内重复相同的数字,所以它永远不会在一行中生成两个相同的数字。这是对的吗?

我不这么认为。我相信生成器使用下一个数字作为后续数字的种子。所以,如果你得到一个值一次,如果它重复,你的数字生成器就会陷入一个循环

然而,许多应用程序都在寻找某个范围内的数字,这使得重复操作成为可能,因为后续的数字可能具有相同的范围模值

EDIT:由于您包含了
next
的源代码,您可以看到,如果它返回相同的数字,它将始终返回相同的数字。因此,您将陷入一个只有一个值的循环中。

要得到一个比我之前的答案“更长”的答案:

您已经链接了实现,它看起来像:

public long nextLong(){
    return ((long) next(32) << 32) + next(32);
}
返回部分可以简单地忽略,因为同样:相同的种子将导致 到相同的返回值-否则CPU损坏

所以,总的来说:我们只需要把重点放在线路上

seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
请注意,结尾[L]只会导致它是一个长值,而不是一个整数。

所以,用二进制的话来说,这意味着:

seed * 10111011110111011001110011001101101 + 1011
毕竟,函数看起来像

seed = (seed * 10111011110111011001110011001101101 + 1011) & (0111111111111111111111111111111111111111111111111)
(我省略了第一个值的前导零)

那么,
和(01111111111111111111111111111111111111)
做什么呢

按位and运算符,基本上比较两个二进制数的每个位置。只有当它们都是“1”时,结果二进制数中的位置才是1

这就是说,等式
(seed*10111011110111011001110011001101+1011)
中距离右侧大于48的每一位都将被忽略

第49位等于
2^49
562949953421312十进制
——这意味着&
(01111111111111111111111111)
基本上就是说 最大结果可以是
562949953421312-1
。 因此,与其结果
562949953421312
,它将再次产生0,
562949953421313
将产生1,依此类推

我上面写的所有东西都很容易验证:

而以下代码将生成随机种子*11*:

你看:种子562949953421312等于种子0

更容易证明:

Random r = new Random(0L);
Random r2 = new Random(562949953421312L);

if (r.nextLong()==r2.nextLong()){
    System.out.println("Equal"); //You WILL get this!
}
它当然是连续的:

Random r3 = new Random(1L);
Random r4 = new Random(562949953421313L);

if (r3.nextLong()==r4.nextLong()){
    System.out.println("Equal");
}
为什么这个“神奇数字”(562949953421312L)很重要

假设,我们从种子0开始

第一个新种子将是:
0*10111011111011000011001101+1011=1011(12月11日)

下一个种子是:
1011*10111011111011001110011001101+1011=1000000110100001010111100110111010(dec:277363943098)

下一个种子(调用3)将是:
1000001010100001010111100110110111010*10111011110111011001110011001101+1011=1000001010000010101010100000101010001001100101100111101(dec 2389171320405252413)

因此,超出了
562949953421312L
的最大数量,这将导致随机数小于上述计算值

此外,添加
1011
将导致结果在奇数和偶数之间交替。(不确定真正的含义——加上1也可以,imho)

因此,生成2个种子(不是随机数)可以确保它们不相等,因为选择了一个特定的“溢出”点——并且添加最大值(562949953421312L)不足以在两代内达到相同的数目

当两次相同的种子是不可能的时,4次也是不可能的,这意味着nextLong()函数在n代和n+1代中永远不会返回相同的值


我不得不说,我想证明相反的情况。从统计学的角度来看,2倍于同一个数字是可能的,但这可能就是为什么它被称为伪随机:)

这取决于你问的问题

正如其他人所说:伪随机数生成器的标准公式在重复之前充分探索了它们的值空间

然而:在大多数应用中,我们不使用PRNG的全部输出范围。我们通过将其划分或截断到与我们试图解决的问题相匹配的范围来减少它。事实上,我们这样做的大多数方式都会产生一系列的数字,其中包括即时重复

这可能是真的,即使你只是简单地使用一个整数随机数,而基础公式使用更多的位进行计算


因此:理论上,如果你直接看一个PRNG的输出,答案是“可能不是”。实际上,答案是“无论如何都不要指望它。”

不,用这种算法在一行中获得两个相同的长度是不可能的

当人们在写关于数学和其他巫术的长帖子时,我走了“代码猴子”的路线,在周末,brute强行推出了2^48个可能的种子。对于任何一粒种子来说,连续生产的两个龙眼都是不相等的



这在理论上是可能的。您有1:281474976710656(2^48)的机会获得特定号码。这意味着您有一个1:79228162514264337593543950336((2^48)^2)可以两次获得相同的数字(或者从技术上讲,两个数字的任何一组)。所以,理论上,是的。在循环中断之前,你可能需要运行几个世纪,但是
seed = (seed * 10111011110111011001110011001101101 + 1011) & (0111111111111111111111111111111111111111111111111)
private Long seed = 0L;

protected synchronized int next(int bits){
    seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
    System.out.println(seed);
    return (int) (seed >>> (48 - bits));
}
private Long seed = 562949953421312L - 0xBL / 0x5DEECE66DL;

protected synchronized int next(int bits){
    seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
    System.out.println(seed);
    return (int) (seed >>> (48 - bits));
}
Random r = new Random(0L);
Random r2 = new Random(562949953421312L);

if (r.nextLong()==r2.nextLong()){
    System.out.println("Equal"); //You WILL get this!
}
Random r3 = new Random(1L);
Random r4 = new Random(562949953421313L);

if (r3.nextLong()==r4.nextLong()){
    System.out.println("Equal");
}
long int seed = 0;

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

int main(int argc, char** argv) {
  long int step = atoi(argv[1]);
  long int i = step << 32;
  long int end = (step+1) << 32;
  while(i < end) {
    seed = i;
    if(nextLong() == nextLong()) {
      printf("Found seed %ld\n", i);
      return 0;
    }
    ++i;
  }
  printf("No seed in %ld\n", step);
  return 1;
}
echo {0..65535} | xargs -n 1 -P 12 ./executable