手元のマシンで乱数生成器の性質を TestU01 で調べてみた。
マシンは MacBook Pro (Retina, 15-inch, Mid 2015)。
OS は普通に macOS の最新。
コンパイラは g++-9 (Homebrew GCC 9.2.0_2) 9.2.0
TestU01 は、 repを10にして SmallCrush を実施。都合 15種類を10回ずつで 150回テスト。
処理時間は、$2^{28} $≒ 2億7千万 回乱数を振った時間。関数呼び出しやループ処理の時間を含む。
結果
名前 | エラー率 | 処理時間 | 補足 |
---|---|---|---|
rand48(libc) | 32.7% | 825ms |
mrand48 を利用 |
rand(libc) | 60.0% | 1686ms | man には「bad random number generator」とある |
random(libc) | 74.0% | 943ms | man には「better random number generator」とある |
std::knuth_b | 0.0% | 17182ms | KnuthのリオーダーアルゴリズムB |
std::minstd | 21.3% | 7837ms | 線形合同法 |
std::mt19937 | 0.0% | 1078ms | メルセンヌ・ツイスタ |
std::ranlux24 | 0.0% | 33509ms | RANLUX法のレベル3 |
std::ranlux48 | 0.7% | 47029ms | RANLUX法のレベル4 |
XorShift128 | 6.7% | 402ms | |
xoroshiro128++ | 0.0% | 327ms | |
xoroshiro128** | 0.0% | 315ms |
# まとめ
エラー率 0% の乱数がいくつかあるけど、それらの間の優劣は判断できない。
エラー率を見ると rand(libc) よりも random(libc) の方が悪い。意外。
速さとエラー率を見る限り、やはり xoroshiro128++ か xoroshiro128** を選ぶのが正解っぽい。