【问题标题】:Java RNG seedingJava RNG 播种
【发布时间】:2017-01-15 18:51:04
【问题描述】:

我的问题是关于 Java RNG;使用以下代码:

for (int s = 0; s < 600; s++) {
   Random r = new Random(s);
   System.out.println(r.nextDouble());
   System.out.println(r.nextDouble() + "\n-----");
}

这将导致生成 600 个随机数。我知道这有点奇怪,但在我的实际项目中每次都需要一个新的随机数生成器。我收到的种子是连续的。对于任何种子,生成的第一个随机双精度数都非常接近,这是因为用作初始化的线性同余公式吗?

生成的第二个 double 实际上看起来确实是随机的,这样假设是否安全?是否可以先生成一个未使用的随机数,然后根据创建它的实际原因开始使用它?

提前谢谢你

编辑:

让我澄清一下:

int possibleRoutes = 7;
void handlePacket(Packet p) {

    int chosenRoute = p.hash % possibleRoutes;
    // ...Other code...

}

对比

int possibleRoutes = 7;
void handlePacket(Packet p) {

    Random r = new Random(p.hash);
    int chosenRoute = r.nextInt() % possibleRoutes;
    // ...Other code...
}

}

对比

int possibleRoutes = 7;
void handlePacket(Packet p) {

    Random r = new Random(p.hash);
    r.nextInt();
    int chosenRoute = r.nextInt() % possibleRoutes;
    // ...Other code...

}

保证每个数据包必须采用相同的路由。目前,数据包哈希本质上是顺序的。有太多可能的哈希值无法保持任何类型的状态来加快速度。

【问题讨论】:

  • 我不明白这种用法。 PRNG 有一个状态。只需创建一个(外部;如果需要,根据时间)并在循环内采样。第二次调用将基于与第一次不同的状态。无需重新播种。 (在几乎所有用例中,在循环中重新播种都是不好的做法)。扔掉RNG-numbers也只是在一些非常复杂的环境下才会做的,不是这里要追求的方法。
  • 为了安全起见:告诉我们,为什么在每个循环中都需要一个新的 PRNG 对象(如果这是你想要的),或者每次调用程序时只需要新的数字。跨度>
  • 为什么您认为每次迭代都需要一个新的随机数生成器?像这样的陈述往往反映了对 PRNG 的深刻误解。
  • 我在原题中添加了真实案例的伪代码
  • 感谢讨论,不胜感激

标签: java random numbers seed


【解决方案1】:

为什么要给一个特殊的数字作为种子?把它留空,这样 Random 构造函数会为你选择一个种子。

for (int s = 0; s < 600; s++) {
     Random r = new Random();
     System.out.println(r.nextDouble());
     System.out.println(r.nextDouble() + "\n-----");
   }

Role of seed in random number generation

【讨论】:

  • 它必须再次确定性地运行
【解决方案2】:

调用使用 nanoTime 作为种子的默认构造函数。这样您就无需在每次迭代时生成新种子来创建对象。

//loop through number of numbers needed
for(int i = 0; i < 100; i +)
    //Calls default constructor
    Random r = new Random();
    System.out.println(r.nextDouble()*.5);

【讨论】:

  • 那么为什么不重用随机对象呢? (=在循环之外创建它)。这看起来非常低效(尤其是对于 MersenneTwister 或任何使用巨大状态的东西)。
  • 据我了解,该用户希望为生成的每个数字重新播种(我同意你的观点,我永远不会在循环内重新播种,甚至不会经常重新播种)我要取消这句话“我需要在我的实际项目中每次都有一个新的随机数生成器”
  • 很公平。我不知道他是不是缺少一些基础知识,还是有什么误解。
  • @sascha Java 的默认 Random 实现不是 Mersenne Twister,而是 48 位线性同余生成器。
  • @pjs 很有趣。感谢您的提示!
【解决方案3】:

另一种方法是使用主随机数为循环中的所有辅助随机数播种:

Random masterRand = new Random();
for (int s = 0; s < 600; s++) {
  Random r = new Random(masterRand.nextLong());
  System.out.println(r.nextDouble());
  System.out.println(r.nextDouble() + "\n-----");
}

【讨论】:

  • 为什么这比在循环外使用单个 Random 更好?两者都是完全可预测的,但这个更复杂和昂贵。
  • 我假设提问者想要Random 的多个副本。如果循环处理足够快,有时基于时间的播种可以提供相同的种子/序列。这种方法避免了这种情况。此外,此方法允许可重复性:如果您为 masterRand 提供显式种子,您可以根据需要重复完全相同的种子运行。这对于调试和其他目的很有用。
  • 是的,但是您只需将masterRand 用于您的nextDouble()s,就可以避免重复播种和可重复性,而无需创建一堆一次性Randoms。仍在等待听到为什么 OP 认为他们每次都想要一个新的生成器......
  • 我在原题中添加了真实案例的伪代码
猜你喜欢
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-12
  • 1970-01-01
  • 2013-12-09
相关资源
最近更新 更多