每次使用RNG时都播种一个好主意

Good idea to seed a RNG each time you use it?

本文关键字:好主意 一个 RNG      更新时间:2023-10-16

我正在使用Mersenne twister算法来洗牌。每次牌组需要洗牌时,我都会用time(NULL) + deckCutCardNumber(即用户选择切割牌组的位置)来输入它。我是否会得到更好的结果,从只播种它的第一手和继续产生他们与相同的种子还是这种方法更随机?

谢谢

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

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

假设用户没有弄乱时钟(或者仔细地根据已经过去的时间减少他们的切割数),他们无论如何都不会看到PRNG的重复状态,所以您做什么都没有太大区别。您将从任何种子值[*]中获得合理的梅森捻线分布,并且在重新播种后的任何可行步数。

如果您希望重新播种,那么您可以将这两种方法结合起来,使用时间加上用户选择的数字,再加上在重新播种之前从生成器获取的输出。这将PRNG的当前状态(部分,而不是全部)与新的种子数据结合起来,因此在某种程度上,所有过去的时间和cut值(以及PRNG的使用次数)都可以影响状态,而不仅仅是最近的状态。以这种方式向种子值中注入更多的信息可以被认为比包含更少信息的种子"更随机",因此可信的值更少。

关于Mersenne Twister的唯一特别之处在于,如果你能观察到它的600多个输出,那么你就可以推断出它的内部状态,并预测剩下的输出,直到它被重新播种。不过,您可能不会将MT用于此类事情很重要的应用程序:如果您以任何方式依赖于reseed,那么您可能应该首先使用更安全的PRNG。显然,对于您的应用程序来说,用户能否预测PRNG的值并不重要,因为用户和您一样知道时间。所有这些都告诉你,它的种子方式并不重要,只要它的种子值不完全相同,这样两款游戏就会完全相同。因此,是否重新播种也无关紧要。

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

每次都对用户的选择进行播种比只播种一次要少一些随机性。原因是切牌的选择可能会有一个倾斜的分布(也许在第10张牌上切牌是最有可能的)。如果你想要连续地播种,你应该使用像系统时间这样的东西作为种子。

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

在这种特殊情况下,第一个值只会随着你等待洗牌的时间而增加,而连续应用的rng会给你整个范围内的数字。

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

然而,我建议不要这样做,因为time返回一个无符号int,所以如果你在同一秒内调用它两次,你会得到相同的数字,因此从RNG得到相同的数字。然后是分布和所有这些

我建议为每次洗牌初始化PRNG有一个完全不同的原因:它允许您仅使用种子来量化牌组的状态,这意味着您可以向用户提供种子,或记录它,或任何套装,并且能够在稍后阶段轻松地重新创建处理的手牌。

你真的应该避免基于时间的播种,尽管-通常使用随机源(如/dev/urandom)来代替是一个更好的主意。

编辑:如果你担心玩家猜测内部状态,从而知道未来会发什么牌,那么重新播种的另一个理由就出现了。在观察了梅森扭扭机的624个输出后(至少根据维基百科),这是可能的;这只有在重用相同的PRNG时才有可能。但是,如果这很重要,那么您当然不应该基于时间进行播种,并且无论如何都应该使用加密安全的PRNG。

重新播种随机数生成器不会给你任何更高质量的随机数比播种它一次(完全相反,在许多情况下,取决于你的种子值)。