在使用Java创建地图生成器时,我发现它们的随机数生成器存在一个相当令人不安的问题,要指定当两个RNG具有非常相似的种子(小整数不同)时,它们的第一个输出值将变得非常相似!
示例代码:
Random r = new Random();
long n = 100000; //Choose any number
r.setSeed(n);
System.out.println(r.nextInt());
r.setSeed(n+1);
System.out.println(r.nextInt());
这几乎打破了我对原始Java RNG的信心,因为我使用坐标为地图生成器播种。
有人可以建议重新定义Random.next(int bits)
方法,还是针对此问题进行其他修复?
感谢您的帮助!
答案 0 :(得分:8)
您是否比较了从100000和100001得到的前20个值的序列?
这是种子100000和100001的第20个下一个种子。在第三列中有不同位的数量(2之间的xor的bitcount)
这最后一列应保持在16左右
-1986972922 -1987357671 13
-1760380366 -604895790 16
-1057894078 -329706441 15
-363772240 -1218064509 15
1545317691 -300240831 14
271304166 -900428132 21
1208561582 273461468 16
-1257783052 1069490639 16
-1549884799 40157720 15
-1514737808 -1818800021 17
-1030569735 1859508545 15
1310070992 880402584 18
-1513092400 971613287 19
-1993219517 354161779 16
-10847170 -204018237 15
-965377044 1488135032 14
802471291 1094582308 22
-539776032 -1021376555 15
2088199751 2070302462 12
-1271582124 64627614 19
在3-5次迭代后不太相似
除了标准的Random之外,还实现了一个线性同余RNG,它已知不是现有的最佳伪随机实现,但对存储器的效率最高(2^48
周期只有一个64位字)
感兴趣的乘数为0x5deece66dL
,c为0xbL
答案 1 :(得分:2)
你的两粒种子(PRNG州)只有最低位才有所不同。考虑到PRNG通常只做一些xor-ing和转移,这不应该太令人惊讶。
无论如何,你不应该像这样使用Random
。在每个nextInt
方法上,PRNG的状态将被更新(状态/种子将改变48个可用位的约50%)。这就是你应该关心的一切。
答案 2 :(得分:1)
据我所知,您需要一系列依赖于某些计算种子的随机数,这样您就可以在给定相同种子时随时重新生成序列。是吗?
由类似种子生成的随机数序列开始相似,但很快就会发散。如果只跳过前k个值,您可能会得到更符合您需求的结果。在这里,k是你必须根据你对序列的不同程度和计算速度的需要来确定的数字。
答案 3 :(得分:0)
java.util.Random
中的问题,例如问题中描述的问题。 SecureRandom
没有表现出相同的可预测性(至少,它并不是那么明显)。您可以在代码中使用SecureRandom
而不是Random
来解决问题,因为前者是后者的子类。
有人可能想知道为什么Sun在发现此问题后不仅修复了Random
。原因是向后兼容性 - Random
的行为无法更改,因为它会破坏依赖于任何给定种子生成的特定伪随机序列的现有代码。