Mersenne Twister シーケンスは 2 ** ( 624 * 32 - 1 ) - 1
長く、シード値は、そのシーケンス内の位置に直接関連する PRNG の内部状態を設定するために使用されます。
最も見つけやすい繰り返しは every2 ** ( 624 * 32 )
のようで、次のように動作することを示すことができます。
repeat_every = 2 ** ( 624 * 32 )
start_value = 5024214421 # Try any value
r1 = Random.new( start_value )
r2 = Random.new( start_value + repeat_every )
r17 = Random.new( start_value + 17 * repeat_every )
r23 = Random.new( start_value + 23 * repeat_every )
r1.rand == r2.rand
# true
r17.rand == r23.rand
# true
またはこれを試してください:
repeat_every = 2 ** ( 624 * 32 )
start_value = 5024214421 # Try any value
r1 = Random.new( start_value )
r2 = Random.new( start_value + repeat_every )
Array.new(10) { r1.rand(100) }
# => [84, 86, 8, 58, 5, 21, 79, 10, 17, 50]
Array.new(10) { r2.rand(100) }
# => [84, 86, 8, 58, 5, 21, 79, 10, 17, 50]
リピート値は、メルセンヌ ツイスターがどのように機能するかに関連しています。MT の内部状態は、624 個の 32 ビット符号なし整数の配列です。リンクした Ruby ソース コードは、Ruby Fixnum を配列にパックします。魔法のコマンドは次のとおりです。
rb_integer_pack( seed, buf, len, sizeof(uint32_t), 0,
INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER );
ただし、これは簡単に操作できるものではなく、 で定義されてinternal.h
いるため、Ruby インタープリター自体で作業している場合にのみ実際にアクセスできます。通常の C 拡張内からこの関数にアクセスすることはできません。
パックされた整数は、関数によって MT の内部状態にロードされますinit_by_array
。これは非常に複雑に見える関数です。パックされたシード値は文字通り状態に書き込まれるのではなく、状態が項目ごとに生成され、提供された配列値を追加し、さまざまな xor、追加、および相互参照を使用して、以前の値 (ここの Ruby ソースは、パック配列のインデックス位置にも追加され、「非線形」とコメントされています。これは、標準 MT への参照された変更の 1 つだと思います)
MT シーケンスのサイズは以下よりも小さいことに注意してください。ここに2 ** ( 624 * 32 )
示す値は、repeat_every
一度に 2 つのシーケンスをスキップしていますが、内部状態を正確に設定する方法を簡単に確認できるため、繰り返しのシード値を見つけるのが最も簡単です。同じです (シードの配列表現の最初の 624 項目は同一であり、それが後で使用されるすべてであるため)。他のシード値も同じ内部状態を生成しますが、その関係は、19938 ビット空間の各整数を別の整数とペアにする複雑なマッピングであり、MT に同じ状態を作成します。