【问题标题】:optimal Java Random seed最佳 Java 随机种子
【发布时间】:2011-12-20 07:38:20
【问题描述】:

关于将long 提供给种子java.util.Random,如果我将对象实例化一次,似乎只要花时间作为种子,就可以满足程序的生命周期,这对我来说目的意味着对nextDouble() 的一系列调用的结果看起来是随机的。

假设为了代码简单,我实例化Random,多次使用,然后重新实例化,重复。如果种子以类似方式提供,则种子将相似并增加,因为它是基于时间的。如果它是自 1970 年 1 月 1 日以来的秒数,则与该值相比,增加的幅度很小。(编辑:这个问题是在 2011 年提出的。)

如果我链接nextDouble() 的输出,是否使用非随机基于时间的种子重新实例化Random 会导致在nextDouble() 的复合输出链中出现微妙的模式。表达这个问题的另一种方式是:我是否需要从long 集合中统一抽取一个种子。

【问题讨论】:

    标签: java random


    【解决方案1】:

    您可能会遇到这样的情况,即它们确实会被分配相同的种子,特别是如果它们是在同一毫秒内创建的。有些机器的分辨率低至 15 毫秒或更多,因此它成为一个更大的问题。

    解决此问题的一种方法是使用Math.random()。它使用系统范围的随机实例,该实例仅在第一次使用时才被实例化。我不相信您可以访问底层实例,因此您不能使用它来获取 nextInt() 但您可以使用 Math.random() 进行双打,或者如果您真的想要自己的 Random 对象,请获取 double来自Math.random(),将其位转换为long,并将long用作新Random的种子。

    可以在 here 找到随机的 Oracle 文档。

    // create new random with seed from system random
    Random r = new Random(Double.doubleToLongBits(Math.random()));
    

    【讨论】:

    • 哇,谢谢谷歌。您将我链接到 1.4.2 文档。显然你从来没有收到过 Java 7 已经发布的备忘录?
    • 我已经养成了将 java6 添加到我所有的 Java 谷歌搜索查询中的习惯 :-) 不管怎样,至少更新到 java6 链接。
    • 也许你可以解释一下这比 Random 默认做的更好。 ;)(见我的回答)
    • @PeterLawrey 你完全正确。我的印象是它使用了System.currentTimeMillis(),我完全不知道它保留的内部种子。我想我可以看到以这样一种方式重构它的一些好处,即出于测试目的,您始终获得相同的种子,但这是一个延伸。我绝对承认这个答案是基于一个有缺陷的假设。但我们都是来学习的,对吧? :-)
    • @Peter :-( 不完全是我想要的开始我的一天!!但至少我不会发疯。我想他们决定使用nanoTime 和计数器来实现这一点目的?所以人们不必为了获得好的随机生成器而做这种愚蠢的特技?
    【解决方案2】:

    自动生成的随机种子使用 System.nanoTime 和一个计数器来确保其始终不同。恕我直言,没有必要玩种子来提高随机性

    public Random() {
        this(seedUniquifier() ^ System.nanoTime());
    }
    
    private static long seedUniquifier() {
        // L'Ecuyer, "Tables of Linear Congruential Generators of
        // Different Sizes and Good Lattice Structure", 1999
        for (;;) {
            long current = seedUniquifier.get();
            long next = current * 181783497276652981L;
            if (seedUniquifier.compareAndSet(current, next))
                return next;
        }
    }
    

    Random 使用 48 位种子并每 2^48 次调用重复一次,这意味着它无法生成所有可能的 long 或 double 值。

    搞乱种子听起来有点像三重随机策略,实际上并没有帮助。 http://thedailywtf.com/Articles/Random-Char-and-TriplyRandom-Double.aspx

    如果您想要更大的随机性,请使用 SecureRandom,即使您每次都给它一个种子 1,它也不会给出相同的随机序列。这可以产生所有可能的long 和double 值。

    【讨论】:

      【解决方案3】:

      这当然取决于生成器,但根据我的经验,对种子的微小更改会对生成的值产生很大影响。

      通过一些工作很可能可以检测到它,但除非您正在进行高端统计工作或密码学,否则它不会产生任何影响。

      在任何情况下,如果您在该类型的域中,您将生成基于硬件的随机数,很可能使用诸如 3 开尔文背景辐射之类的东西作为源 :-)

      【讨论】:

      • 或者一个坐在山洞里大喊Nine. Nine. Nine. Nine. Nine.的巨魔,这就是随机的问题,你永远无法分辨!
      • 尝试Random random = new Random(441287210); for(int i=0;i<10;i++) System.out.print(random.nextInt(10)+" "); } 打印1 1 1 1 1 1 1 1 1 1
      • 而且,如果您继续前进,您将开始获得不同的数字。 @Peter,我不完全确定您的意思是什么,除非它是为了说明 Java PRNG 中使用的表达式的一个有趣属性,因为 1 1 1 1 1 1 1 1 1 1 与 3 1 4 1 5 9 2 6 5 3 或 2 7 1 8 2 8 1 8 2 8 具有相同的概率。
      猜你喜欢
      • 2016-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-09
      • 1970-01-01
      相关资源
      最近更新 更多