【问题标题】:Good idea to seed a RNG each time you use it?每次使用 RNG 时播种一个好主意?
【发布时间】:2011-09-06 13:37:51
【问题描述】:

我正在使用 Mersenne twister 算法来洗牌。每次需要洗牌时,我都会用 time(NULL) + deckCutCardNumber 播种,这是用户选择切割牌组的地方。仅通过第一手播种并继续使用相同的种子生成它们,或者这种方法更随机,我会得到更好的结果吗?

谢谢

【问题讨论】:

  • 呃,你知道切割是在洗牌之后发生的,对吧?无论如何,当您信任洗牌器时,这毫无意义。
  • 扑克牌和梅森捻线机不能混合(梅森捻线机的输出是可预测的)。您需要一个加密 PRNG。并用痛苦收集的熵来初始化它,因此很昂贵,这意味着你应该只初始化一次。

标签: c++ algorithm random


【解决方案1】:

只播种 PRNG 一次。生成序列的统计属性只有在种子之后才能保证。如果您每次都重新播种,则生成的序列可能没有任何可预测的统计特性。

例如,考虑一个 PRNG,它始终将种子值本身作为序列中的第一个数字返回,但在其范围内完全一致。只要您不使用第一个数字,这就构成了一个很好的 PRNG。但是,如果您在每次使用前重新播种,例如递增的计数器值,则根本没有随机性!

【讨论】:

  • “这构成了一个伟大的 PRNG”——这构成了一个几乎伟大的 PRNG,但由于设计中的一个关键缺陷而瘫痪。它所需要的只是种子进程将状态向前推进一次,然后我们就可以交谈了:-)
  • 是的,当然 - 这只是一个思想实验,展示了每次重新播种可能遇到的最坏情况,如果只播种一次,这几乎可以忽略不计。
  • 不过,对于合理的 PRNG,这并不是最坏的情况。合理 PRNG 的最坏情况会更好,不合理 PRNG 的最坏情况会变得更糟(return 4;)。不过,我会在我的回答中添加一些关于 MT 播种弱点的内容。
  • 第二个 52 位数字始终相同的 PRNG 会怎样?总是有可能设计出一种病态的情况,即给定的使用不是最理想的。
【解决方案2】:

假设用户没有弄乱时钟(或小心地将他们的切割数量精确地减少已经过去的时间),他们无论如何都不会看到 PRNG 的重复状态,所以它没有太大区别你做什么。您将从任何种子值 [*] 以及重新播种后的任何可行步数中从 Mersenne Twister 中获得合理的分布。

但是,如果您热衷于重新播种,您可以通过播种与时间、用户选择的数字以及在重新播种之前从生成器获取的输出来结合这两种方法。它将(部分,不是全部)PRNG 的当前状态与新的种子数据结合起来,所以在某种程度上,所有过去的时间和截断值(以及 PRNG 的使用次数)都会影响状态,而不仅仅是最近的。以这种方式将更多信息注入种子值可以被认为比包含较少信息的种子“更随机”,因此可能的值也更少。

关于 Mersenne Twister 的唯一一件事是,如果您可以观察到它的 600 多个输出,那么您可以推断其内部状态并预测其余的输出,直到重新播种。再说一次,您可能不会将 MT 用于此类事情很重要的应用程序:如果您以任何方式依赖重新种子,那么您可能应该使用更安全的 PRNG 开始。显然,如果用户可以预测 PRNG 中的值,对您的应用程序来说并不重要,因为用户和您一样了解时间。所有这一切都告诉你,它是如何播种的并不重要,只要它没有以完全相同的值播种以使两个游戏相同即可。因此,是否重新播种也没关系。

[*] 这并不完全正确,MT 有一些弱种子类别。但只要您在播种时考虑到这一点(例如,在使用前对种子进行哈希处理,这样就不会偶然出现错误的值),您就可以解决这个问题。

【讨论】:

  • 关键问题是哪个更重要,不可预测性或正确分布...
  • @Kerrek:我猜。如果不可预测性很重要,那么时间播种的 MT 是史诗般的失败,所以我假设玩家是真诚的。所以我们想要的只是数据是正确分布的,并且不是那么容易预测到破坏游戏,因为玩家会忍不住识别序列。随时间播种可以实现这一点,无论您是否在每次洗牌时重新播种。
  • 好吧,无论如何我都不会从时间中播种,而是从一些不错的随机来源中播种。但不知何故,我想知道将 600 个纸牌游戏决策转化为 MT 的正确初始状态是否真的是一件如此微不足道的事情……也许人们甚至不必担心这一点。
  • @Kerrek: 不,我不担心,在游戏中MT输出可能在使用前被破坏的情况下,通过猜测获得种子要容易得多(你知道毕竟,它是什么时候播种的)而不是试图从观察到的甲板顺序中恢复。我只是提出更广泛的观点,即使对于不同的用途,您也不应该依赖非加密 PRNG 的种子。
  • 另一种看待它的方式:用户是否关闭程序并再次运行它是否重要?不?然后,如果您重新播种也没关系。它没有帮助,但它不会比重新启动程序更糟糕。相反,如果不重新播种有帮助,也就是说,如果不重新播种,您的游戏在第三场或第十二场比赛中的行为比第一场比赛“更随机”,那么您可能无论如何都想修复第一场比赛,例如,在初始种子之后稍微搅动生成器。
【解决方案3】:

与只播种一次相比,每次播种用户选择的随机性会更少。原因是切的选择可能会有一个倾斜的分布(也许在第 10 张牌切是最有可能的等等)。如果你想连续播种,你应该使用系统时间之类的东西作为种子。

【讨论】:

  • 定义“更少的随机性”——总熵肯定更少,只播种一次而不是多次。
  • “较少随机”将是一个倾斜的分布。人们倾向于选择某些模式,因此人工选择会显着降低初始值的随机性。
  • 不过,像 MT 这样好的 PRNG 的分布不受所选种子的影响。
  • @Nick Johnson 这没有抓住我的意思。每次如果给定相同的种子,任何 PRNG 都会生成相同的数字,我断言人类选择会使种子选择偏向于一组初始种子。
  • 他并没有让用户设置整个种子,但是,只是贡献它。
【解决方案4】:

是的,如果不是每次都播种,您会得到更好的结果。这就是(好的)随机数生成器的目的。

在这种特殊情况下,第一个值只会随着您在 shuffle 之间等待的时间而增加,而连续应用的 rng 会为您提供整个范围内的数字。

【讨论】:

  • [需要引用]。对于一个好的 PRNG,MT 是,你不会通过重新播种得到更差的结果。
【解决方案5】:

它既不是更多也不是更少随机。无论如何,它根本不是真正随机的,但如果你每次都重新播种,你不会注意到任何差异。

但是,我建议不要这样做,因为time 返回一个无符号整数,因此如果您在同一秒内调用它两次,您将获得相同的数字,因此来自 RNG 的数字也相同。然后是分发等等。

【讨论】:

    【解决方案6】:

    出于完全不同的原因,我建议为每次洗牌初始化 PRNG:它允许您仅使用种子来量化牌组的状态,这意味着您可以将种子提供给用户,或记录它,或其他任何方式花色,并且能够轻松地在稍后阶段重新创建手牌。

    不过,您确实应该避免基于时间播种 - 通常最好使用随机源,例如 /dev/urandom

    编辑:如果您担心玩家猜测内部状态并因此知道将来会发什么牌,则会出现另一种重新播种的论点。在观察到 Mersenne Twister 的 624 个输出后,这是可能的(至少根据维基百科);这只有在您重复使用相同的 PRNG 时才有可能。但是,如果这确实很重要,那么您当然不应该根据时间播种,而且您可能应该使用加密安全的 PRNG。

    【讨论】:

      【解决方案7】:

      重新播种随机数生成器不会为您提供比播种一次更高质量的随机数(在许多情况下恰恰相反,具体取决于您的种子值)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-05
        • 1970-01-01
        • 2021-01-22
        • 2012-01-13
        • 2013-03-01
        • 2012-12-01
        • 1970-01-01
        • 2011-10-21
        相关资源
        最近更新 更多