いろいろと検証コード書いて試してみた結果、こんな感じで行くことにしました:
コード全文: http://ideone.com/RQ4KB
struct Xor128 { // ... // 種を元に乱数を初期化する explicit Xor128( int_type seed ) : x(123456789), y(362436069), z(521288629), w(88675123) { x ^= seed; y ^= rotate_left<17>(seed); z ^= rotate_left<31>(seed); w ^= rotate_left<18>(seed); // あるいは // x ^= rotate_left<14>(seed); // y ^= rotate_left<31>(seed); // z ^= rotate_left<13>(seed); // w ^= seed; } // ... };
いろいろと試しましたが、前回までの記事の基準による「偏りの無さ」、つまり、
初期状態(今回は内部状態ではなく種)を 1 bit 変化させた場合に何回読み飛ばせばよいか、
という基準だと、試した限りでは rotate するのがベストだったので、 rotate することに。
問題は rotate 幅ですが、これは厳正な審査(オレオレ評価関数による総当りチェック)により、
種 1 bit の変化が内部状態全体へ伝搬する速度が早かったものを採用しています。
この方法だと、大雑把に言って 20 回程度読み飛ばせば問題ないレベルです。
さて、本当はここで、このローテート幅を割り出すために使ったオレオレ評価関数を紹介し、
評価するときに気にしたこととかを、ずらーっと書くつもりだったわけですが、
正直もう面倒になったので、やっぱどうでもいいやー的に流すことにします。
とりあえずコードだけは gist に上げておいたので、興味のある方は解読してください:
http://gist.github.com/604721
しっかし gist は便利だにゃー。