Gaucheのmath.mt-randomにバグがあるかどうか検証

結論: なんか別のバグが見付かったが、偏りの方は起こってなさそう。
(または、自分の書いたコード側に問題があるか)


頭と腹はずっと痛くて、全然眠れない。
この前のノロっぽい症状だ。


寝れないので、検証方法を考えてみた。
要は、同じ数値が連続で出る可能性が高いという事は、エントロピーが低いという事で、データ圧縮が可能である可能性が高い、という事になる。
そこで、以下のような一行スクリプトで比較してみる事にした。

SEED=98765;
gosh -umath.mt-random -e"
(let1 mt (make <mersenne-twister> :seed $SEED)
  (let loop ((i 1000000))
    (write (mt-random-integer mt 9))
    (if (zero? i)
      (exit)
      (loop (- i 1)))))
"|bzip2 -9|wc -c; gosh -umath.mt-random -e"
(let1 mt (make <mersenne-twister> :seed $SEED)
  (let loop ((i 1000000))
    (write (inexact->exact (floor (* 9 (mt-random-real0 mt)))))
    (if (zero? i)
      (exit)
      (loop (- i 1)))))
"|bzip2 -9|wc -c

最初に、mt-random-integerが生成した、0-8の数値しか出ない文字列をbzip2 -9にかけた後のサイズを表示し、次に、同様にmt-random-real0が生成した文字列を表示させる。
これをSEEDの値を変更して何回か実行し、常にmt-random-integerの方が数値が小さいなら、バグがあると考えてよさそうだ。多分。


やってみた。

SEED=98765;
411261
411098
SEED=987654321;
411195
411434
SEED=9876543211;
411354
411290
SEED=9754321113;
411354
411290
SEED=9999955511111;
411354
411290

有意な差は見られないようだ……と思っていたが、なんか途中から様子がおかしい。
SEED値に関わらず、一定の値が出ているようだ。

SEED=9999955511111;
echo $SEED;
gosh -umath.mt-random -e"
(let1 mt (make <mersenne-twister> :seed $SEED)
  (let loop ((i 10))
    (write (mt-random-integer mt 9))
    (if (zero? i)
      (exit)
      (loop (- i 1)))))
"; echo; gosh -umath.mt-random -e"
(let1 mt (make <mersenne-twister> :seed $SEED)
  (let loop ((i 10))
    (write (inexact->exact (floor (* 9 (mt-random-real0 mt)))))
    (if (zero? i)
      (exit)
      (loop (- i 1)))))
"; echo;
SEED=9999955511111;
echo $SEED;
9999955511111
01857476028
08770851848

SEED=99999555111119;
echo $SEED;
99999555111119
01857476028
08770851848

どうやら、これが原因のようだ?

これっぽい。
しかし、mt-lib.stubの該当箇所を見る限りでは、直ってるっぽいように見える。
そして、自分の書いた初期化コードでは

(define *mt*
  (receive (epoch micro) (sys-gettimeofday)
      (make <mersenne-twister>
                :seed (+ epoch micro (sys-getpid)))))

のようになっているので、まだbignumに到達していないと思し、実際にコンソールから試行しても、ちゃんと乱数を返しているように見える。
結局、偏りの方は謎のまま。

とりあえず、bignumの方だけ報告して寝よう。