Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么使用相似种子时初始随机数相似?_Java_Random - Fatal编程技术网

Java 为什么使用相似种子时初始随机数相似?

Java 为什么使用相似种子时初始随机数相似?,java,random,Java,Random,我发现使用Java的random类生成随机数有些奇怪。 基本上,如果使用close seeds创建多个随机对象(例如,在1到1000之间),每个生成器生成的第一个值几乎相同,但下一个值看起来很好(我没有进一步搜索) 以下是第一次生成的两个双精度,种子数从0到9: 0.730967787376657 0.24053641567148587 1 0.7308781907032909 0.41008081149220166 2 0.7311469360199058 0.901447624030054

我发现使用Java的random类生成随机数有些奇怪。 基本上,如果使用close seeds创建多个随机对象(例如,在1到1000之间),每个生成器生成的第一个值几乎相同,但下一个值看起来很好(我没有进一步搜索)

以下是第一次生成的两个双精度,种子数从0到9:

  • 0.730967787376657 0.24053641567148587
  • 1 0.7308781907032909 0.41008081149220166
  • 2 0.7311469360199058 0.9014476240300544
  • 3 0.731057369148862 0.07099203475193139
  • 4 0.7306094602878371 0.918714013855101
  • 5 0.730519863614471 0.08825840967622589
  • 6 0.7307886238322471 0.5796252073129174
  • 7 0.7306990420600421 0.7491696031336331
  • 8 0.73025113910172 0.5968915822372118
  • 9 0.7301615514268123 0.7664359929590888
从991年到1000年:

  • 991 0.7142160704801332 0.9453385235522973
  • 992 0.7109015598097105 0.21848118381994108
  • 993 0.7108119780375055 0.38802559454181795
  • 994 0.7110807233541204 0.8793923921785096
  • 995 0.7109911564830766 0.048936787999225295
  • 996 0.7105432327208906 0.896658767102804
  • 997 0.7104536509486856 0.066201629235198
  • 998 0.7107223962653005 0.5575699754613725
  • 999 0.7106328294922568 0.72711437112820883
  • 1000 0.7101849056320707 0.574836350385667
这是一个显示种子从0到100000生成的第一个值的图

基于种子生成的第一个随机双精度:

我搜索了有关这方面的信息,但没有看到任何与这个精确问题相关的信息。我知道LCGs算法有很多问题,但我不知道这个问题,我想知道这是否是一个已知的问题

另外,您知道这个问题是只针对第一个值(或前几个值),还是更一般,应该避免使用相近的种子


谢谢。

通过生成随机种子(例如,在System.currentTimeMillis()或System.nanoTime()上使用一些数学函数生成种子),您可以获得更好的随机结果。也可以查看更多信息

我不会把这称为“问题”

另外,您知道这个问题是只针对第一个值(或前几个值),还是更一般,应该避免使用相近的种子

连续数字之间的相关模式是非加密PRNG的常见问题,这只是一种表现形式。相关性(严格自相关)是算法的数学基础中固有的。如果你想了解这一点,你应该先阅读Knuth的《计算机编程艺术》第3章的相关部分

如果您需要不可预测性,您应该为
random
使用(真)随机种子。。。或者让系统为你挑选一个“非常随机”的;e、 g.使用无参数构造函数。或者更好的方法是,使用真实随机数源或加密质量PRNG,而不是
random


记录在案:

  • javadoc(Java7)没有指定Random()如何对自身进行种子设定
  • Java 7 for Linux上的
    Random()
    的实现是从纳秒时钟开始的,用一个“uniquifier”序列进行异或。“uniquifier”序列是使用不同乘法器的LCG,其状态为静态。这是为了避免种子的自相关
    这是伪随机种子的一种相当典型的行为——它们不需要提供完全不同的随机序列,它们只提供了一种保证,即如果使用相同的种子,您可以再次获得相同的序列

    这种行为的发生是因为PRNG的数学形式——Java one使用了一个线性同余生成器,所以您只看到通过一轮线性同余生成器运行种子的结果。这还不足以完全混合所有的位模式,因此您可以看到类似种子的类似结果


    您最好的策略可能只是使用非常不同的种子-一种选择是通过散列您当前使用的种子值来获得这些种子。

    您最好下载并阅读
    随机
    源代码,以及一些关于伪随机生成器的论文,但这里是一些相关部分的来源。首先,有三个恒定参数控制算法:

    private final static long multiplier = 0x5DEECE66DL;
    private final static long addend = 0xBL;
    private final static long mask = (1L << 48) - 1;
    
    您提供了一个非常接近于零的种子,因此设置的初始种子值由
    乘法器控制,当二者相加时。在所有种子接近零的测试用例中,内部使用的种子大约为2^34;但很容易看出,即使您提供了非常大的种子数量,类似的用户提供的种子也会产生类似的内部种子

    最后一部分是
    next(int)
    方法,该方法实际上根据当前种子生成请求长度的随机整数,然后更新种子:

    protected int next(int bits) {
        long oldseed, nextseed;
        AtomicLong seed = this.seed;
        do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
        } while (!seed.compareAndSet(oldseed, nextseed));
        return (int)(nextseed >>> (48 - bits));
    }
    
    这被称为“线性全等”伪随机生成器,这意味着它通过将当前种子乘以常数乘法器,然后添加常数加数(在这种情况下,然后掩蔽以获取较低的48位)来生成每个连续种子。发生器的质量取决于乘法器和加数的选择,但所有此类发生器的输出都可以根据当前输入轻松预测,并且在重复之前有一个设定的周期(因此建议不要在敏感应用中使用它们)

    在给定类似种子的情况下,从
    nextDouble
    看到类似的初始输出的原因是,因为下一个整数的计算只涉及乘法和加法,所以下一个整数的大小是
    protected int next(int bits) {
        long oldseed, nextseed;
        AtomicLong seed = this.seed;
        do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
        } while (!seed.compareAndSet(oldseed, nextseed));
        return (int)(nextseed >>> (48 - bits));
    }