【发布时间】:2013-12-03 07:00:17
【问题描述】:
Ruby 将 PRNG 实现为“经过修改的 Mersenne Twister,周期为 2**19937-1”。 1
我理解 MT 的方式是它对 2^32 个不同的种子进行操作。让我困惑的是Random.new(seed) 接受任意大的数字,例如Random.new(2**100)。
但是,我无法找到(逻辑)冲突:
Random.new(1).rand(10**5) == Random.new(2**32-1).rand(10**5) => false
Random.new(1).rand(10**5) == Random.new(2**32).rand(10**5) => false
Random.new(1).rand(10**5) == Random.new(2**32+1).rand(10**5) => false
鉴于我们想利用 MT 的最大种子范围,即我们希望使用尽可能多的不同种子,同时仍然避免与两个不同的种子发生冲突,那么什么种子范围可以实现这一点?
我尝试了解 Ruby 的随机实现内部发生了什么,但没有走得太远。 https://github.com/ruby/ruby/blob/c5e08b764eb342538884b383f0e6428b6faf214b/random.c#L370
【问题讨论】:
-
它在内部使用 624 个 32 位整数的向量(我 认为 - 至少这是 MT 的默认实现会使用的)。您链接的代码将大整数拆分为一个由 32 位整数组成的数组,该数组提供初始状态向量。
-
注 624 * 32 = 19968 。 . . “种子”也是 MT 的“状态”
-
@NeilSlater:等等。这是否意味着 Random.new(1) 将在某个时候开始生成与 Random.new(1000) 相同的序列?
-
我想知道
rb_to_int(vseed);是否做了一些规范化? -
是的,有一个重复的序列,种子只是在不同的位置拾取。但是,这些州通常不像小种子那样紧密。在实践中您不太可能看到碰撞 - 如果您只是将生成器设置为从
srand(1)与srand(1000)运行并每秒获得十亿个结果,那么当两者之间存在重叠时,我们都已经死了序列。可用空间很大。这与知道“我在序列中的位置”不同,后者是关于看到足够的变化来识别状态。
标签: ruby random mersenne-twister random-seed