• に登録
  • 歴史・時代・伝奇

擬似乱数生成器の線形合同法はなぜ悪いのか

1985年11月3日号の最後にぽそっと「線形合同法はよくない」とありますが、これは式の基本形を見ると、ああ……となります。

i=j+1として
Xi = (a x Xj + b) mod c

<ぼそ>ぐぉー MathJax が欲しい。</ぼそ>

前回値をa倍してbを足してcで割った余り。なので覚えておくのは前回値のみです。とても単純。
よく知られている式が以下。

Xi = (1103515245 x Xj ​+ 12345) mod 2^32

2^32 で割った余り、というのは32ビット整数演算の桁あふれを切り捨てるだけでいいのでものすごく楽なのです。
で、出てきた乱数をサイコロにするには6で割った余りに+1する、というのはまあ一瞬考える手ですね。
で、この疑似乱数。12345 を足しちゃってるので偶数奇数が交互に出ます。
ということは6で割った余りも偶数奇数が交互になります。それに1足しても偶数奇数が交互に。
有名なカルドセプトサーガのダイスバグはこれでしょうね。

古典的な Microsoft の C ランタイムの rand() は RAND_MAX が 32767 なんですが、これはビットシフト+マスクで最下位ビットの周期性を回避しようとしている工夫です。線形合同式も値がちょっと違っていて

Xi = (214013 x Xj ​+ 2531011) mod 2^32

最後に奇数を足してるんで最下位ビットは偶奇交互なんですがこれを避けるために rand() で返す値は (Xi>>16) & 0x7fff と処理をして戻します。下位 16 ビットを捨てる処理ですね。

とはいえ、これを 6 で割った余り+1にするのもよくないんですよ。0~32767 あるので6で割り切れない=確率分布に偏りが。

かように乱数って面倒なんです。本当に。

コメント

コメントの投稿にはユーザー登録(無料)が必要です。もしくは、ログイン
投稿する