最新

val it : α → α = fun

<<  2005/07  >>

2005/07/30 乱数のランダムネス

http://www.fastwave.gr.jp/diarysrv/arino/200507c.html#20050730-2

この話はなかなか示唆的なような気がするが、指摘している個数の問題については、乱数用の関数は整数の範囲(0-2**32とか)等になっているので、lの値がこの範囲に比べてごく狭い場合(1000以下とか)ではそれは誤差の範囲内という気がする。

それより気になるのは、たとえばlが16とかのような2進法的に「綺麗な」数の時。あーつまり、乱数はすべてのビットについて一様にランダムなのかということがわからない。偏りの生じるビットはないのだろうか。

ごく簡単に考えると、仮に偏りのあるビットがあるとすると、最終的な値の分布にも偏りが生じるはずであり、一様分布である乱数発生アルゴリズムなら偏りのあるビットは存在せず、等しくランダムだという気がするが、さてどうなのだろうか。

たとえば、「半々の確率」を表現したいとする。このとき、一番下のビットが0か1かでチェックしていいのだろーか?というのが疑問。仮に、一番下のビットは均等に分布していても、現在の乱数値から次の乱数値の予測が可能だったりしないのだろうか(線型合同法とか特に……いや今は線型合同法は使ってないんだろうけど)。一番下ビットはナイーブすぎるとして、下位4ビットとかが意外に周期的だったりしないのだろうか。

でまぁそういうわけで、こういう場合はなんとなく100で割った余りを利用して0-49と50-99 を使ってみたりするのだけど、こっちの方が安全という保証はどこにあるんだろうか。この方が逆に怪しいケースもあるのかも。

……ということを mixi に書いておいたら鍋谷さんに http://www001.upp.so-net.ne.jp/isaku/rand.html を紹介された。まとめると、

  • UNIX の rand は今でも線型合同法
    • 線型合同法の場合、下位ビットは乱数としてけっこう怪しい
      • random は統計的に怪しいらしい
        • けっきょくメルセンヌ・ツイスターが最強ということで

          つうことみたい。半々の確率を rand でやる場合には、100とかよりはもっと因数が少ない数(素数×2とか)を使ってみたり、真ん中あたりのビットを利用するように、乱数生成→右シフトした上で割ったりすると良いのではないかという気がしてきた。

          まぁメルセンヌ・ツイスターを使えってことですかね。じゃ、どうやって使うかというと。

          http://www.jp.freebsd.org/QandA/HTML/2228.html によると、 boost の乱数はメルセンヌ・ツイスターらしい。さらには、 wikipedia によればruby、PHP、それに glib でメルセンヌ・ツイスターが使われているのだとか。 ruby は耳にしたことがあったけど、けっこう使われているのだね。ってか glib から使えるのかー。ううむ知らなかった。

          …… OCaml では Mathlib から使える模様。

          Haskell では、まず言語規格上特に規定はなく、 ghc/hugs の実装上は randomIvalInteger という関数が主に担っているところまではわかったんだが、この関数の定義がちょっとよくわからない。けれどもこれは線型合同法をすごく一般化したもののように見える。たぶん。ぐぐってみると、いちおうここに実装した人はいるっぽい。

          他の言語については、きっと誰かが調査していることだろう。