我能否从 Mersenne Twister 中获取当前种子?

4
我正在我的应用程序中适应Mersenne Twister,具体来说是从http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.htmlmt19937ar.c - 代码在https://gist.github.com/mstum/8367363上做了镜像。这被用作游戏中的确定性随机数生成器,并且为了使保存游戏按预期工作,我需要从MT中获取当前种子(而不是最初的种子),以便我可以继续进行。
例如,假设我使用种子12345初始化它,并调用genrand_int31 5次。这将产生序列1996335345、1911592690、679411342、280691776、394962642
现在,想象一下,在第三个数字(679411342)之后,我保存了游戏,然后重新加载并获得两个随机数。我希望这些数字是序列的下两个数字(280691776、394962642),为此我需要知道第三轮迭代后的种子。
作为一种解决方法,我有最初的种子和我调用随机数生成器(genrand_int31)的次数,因此现在加载游戏会使用初始种子启动MT,并“重放”genrand_int31多少个几百或几千次——这有点愚蠢:)
我试图简单地使用mt[N]数组的第一个元素,但那真的行不通。不幸的是,我不理解Mersenne Twister背后的数学原理,以找出它实际上是如何工作的。
1个回答

4

这两个是MT生成器的状态,你可以保存它们并恢复它们:

static unsigned long mt[N]; /* the array for the state vector  */
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */

也许您需要修改原始的C源代码。
此外,我不相信存在任何与MT的任意状态等效的种子:种子本身包含64位,这使得它具有多达2^64个可能的值,远远少于MT可能具有的状态(其周期为2^19937-1)。
作为解决方法,我有初始种子和调用RNG的次数,因此现在加载游戏会使用初始种子启动MT,并“重放”genrand_int31多少次 - 这有点愚蠢:)
嗯,这并不太愚蠢。:) 让我告诉您,在MT的数学背后,您可以恢复其连续输出周期的内部状态,确切的数字是624-您只需要保存来自genrand_int32的最近的624个数字。我正在寻找任何现有的相关资料。

破解随机数生成器 - 第三部分展示了如何通过一些(至少624个)输出数字来推断MT生成器的内部状态。这并不是完全意外的,因为MT旨在提供强大的统计随机性而不是用于加密等安全目的。
然而,在这种情况下,我认为解决您的问题最简单的方法是将自己的代码添加到MT生成器中以保存/恢复其内部状态。


你可以将genrand_int32的返回值传递到一个向量中,但是“tempering”需要被移动。 - user3125280
谢谢,那也是一个很好的解决方法,因为这意味着625 * 4个字节的存储空间,这完全没问题(2500字节的存储空间)。 - Michael Stum
那个链接很棒,解释得很好,谢谢!对于我的目的来说,保存整个数组和mti是最简单的。 - Michael Stum
如果保存整个状态不切实际,您也可以在每n代之后生成和持久化一个新的种子。这样,您就可以控制必须进行的“重放”数量。 - Patrick Klug

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接