SICPを読む(91) 3.1.2 - 乱数

randの解説があるけど、randのソースが書いてなくてハマった。

(define random-init 12345)

(define rand
  (let ((x random-init))
       (lambda ()
         (set! x (rand-update x))
         x)))

(define (rand-update x)
  (modulo (+ (* 214013 x) 253011) 32767))

(rand) ; 10917

線形合同法なら、ax + bの余りを取る。数値は適当にやると、偏りがかなり出るので、数値に関してはCの仕様を使うといいと思う。

とりあえず進めそうだ。



他のアルゴリズムについて調べてみると、M系列やらメルセンヌ・ツイスタなんかがあるけど、案外複雑。


M系列について理解したところまでメモっておく。


pはメルセンヌ素数のM(p)を選ぶ。qの選定はイマイチ不明だけど、p > q。

M(n) = M(n-p) xor M(n-q)

  • とりあえずp個のテーブルに適当な値をセットし、xorを使って計算する。
  • 線形合同法とは違い、nは1個づつ進めるのが特徴。
  • 2^p-1回で全てのパターンを回るので、擬似乱数を作成することが出来ると。頭いい。
  • 初期値が全て0では無い限り、0以外のパターンは全て試すことになる。
  • テーブルp個に対して、2^p - 1という長い周期を持てるようになるというのは凄いかも。
  • サンプルはC言語による実用アルゴリズム辞典に載ってるけど、イマイチ理解できてない。後で写経しよう。

メルセンヌツイスタは、M系列を行列に発展させたバージョンらしい。


乱数も素数も深いな。