SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

乱数生成について・・xorshiftすげぇ

モンテカルロ法で計算するときには、乱数の質についての話題がよく出てきます。
乱数に偏りがあると、正確な推定ができなくなるためです。
で、C言語標準のrand関数はあまり乱数の質が良くなくて、サンプリングする方向に偏りができてしまうとのことです。
そこで、別の乱数生成法を用いるのですが、レンダラ関係ではメルセンヌツイスタがよく用いられています。


が、今回はコチラ↓の記事で見かけたxorshift法というのを試してみました。
http://lucille.atso-net.jp/wiki/index.php?%CD%F0%BF%F4

xorshift法はxorとシフト演算のみで超高速に疑似乱数を生成するものです。
パストレなどでは、ロシアンルーレットで反射方向を決める際など、多くの場所で乱数を生成する必要があります。なので、xorshiftを用いることで高速化ができないかな、と思いxorshiftがどの程度早いのか実際に試してみました。
(まだレンダラに組み込んではいませんが・・)


ちなみにxorshiftによる乱数生成ルーチンはたったコレだけ。

unsigned long xor128(){
    static unsigned long x=123456789,y=362436069,z=521288629,w=88675123;
    unsigned long t;
    t=(x^(x<<11));x=y;y=z;z=w; return( w=(w^(w>>19))^(t^(t>>8)) );
}


このルーチンとC言語標準のrand関数それぞれで、1億回乱数を生成する時間を比較してみました。

関数 デバッグ リリース
rand() 4.078秒 3.5秒
xor128() 5.359秒 0.25秒

最初、デバッグモードで比較したところ、rand関数の方が速くてアレ??と思ったのですが、xorshift法はリリースモードにすると一気に速くなります。
xorとシフト演算は最適化がうまく働くってことなのかな。

ロシアンルーレットで比較

一応、randとxorshiftそれぞれでロシアンルーレットを作って三次元空間にプロットして比較してみました。
周囲角と仰角を乱数で生成して、球座標から直行座標に直した座標を10000点プロットしました。




見た感じだと、xorshiftで生成しても問題なさそうなので、今度レンダラに組み込んでみようと思います。
(rand関数に偏りがあるとは聞いていたけど、こうやって見てみるとそんな偏りがあるような気はしない・・・コレは見方が悪いのかなぁ・・・)