C++で利用可能な乱数発生オプションを知ろう。

やあ子供たち。rand()使ってるか。おじさんはこれまでコンピュータが発生してくれる乱数についてあまり深く考えたことなかったけど、世の中にはランダムに何かを決めて統計的に正しい結果を出そうというアルゴリズムが結構あるね。モンテカルロシミュレーションなんてのはその代表格なんだろう。
さてところで「ランダム」にといっても本当にランダムになってしまってはダメなのでして。同じ入力に対して1回目の出力と2回目の出力とが、違う結果になったりするようでは困るよな。使う側からしてみれば、別にランダムでもランダムでなくてもプログラムの中身はどうでもよくて、要は同じ入力に対しては同じ計算結果が帰ってこないと、モノとして、計算機として、絶対に使い物にならない。
でも心配することはない。幸か不幸かコンピュータは、元来、決められた数式を処理する能力しかない決定論的な機械なので、コンピュータに真のランダム性を持たせることは不可能だ。
昔、PC-8801という8ビットコンピュータで、線や円のグラフィックス表示をするプログラムを書いていたりした中で、色の値を、ランダムに決めるプログラムを描いたりしてたけど、電源を入れた直後にそのプログラムを実行すると、必ず、最初の色は青になることに気付き、乱数とは結局はそういうものか、たしかに機械なのだから決定論的な乱数しか出せないのだなと子供心にも拍子抜けした気持ちになったりしたものだ。
では、実行するたびに、真にランダムな値を取り出す方法はないのかといえば、例えばプログラムの実行時の時刻の数値を使うという方法もある。じゃ真の意味での乱数は全部時刻由来にすれば良いと思うかもしれないがそれでは処理速度的な問題も出て来て実用に耐えない。だから乱数発生アルゴリズムの初期化時のみ指定するシード値だけは、時刻に由来した数字を与えるというテクニックが使われたりする。この方法でも毎回予測出来ない違う結果を返すプログラムを作成可能だ。
さてrand()のシード値は、srand()というAPIで指定可能だ。このsrand()に現在時刻を設定して呼び出している処理が、プログラムの初期化処理の奥深いところにないとも限らないから、rand()を使う際はくれぐれも、srand()がどこでどう呼ばれているか、あるいはいないのかを、チェックしておくとよいかも知れません。
さて、ここからは、再現性のある乱数発生アルゴリズムについてのメモだよ。どうやら今熱いとされるのは「メルセンヌ・ツイスター」という名前のアルゴリズムだ。日本人の人たちが考えたものらしい。同じ日本人として実に誇り高くも有り難いことだね。これが最近では最もいい感じの最新の乱数アルゴリズムらしい。C++では、を#includeすることによって利用可能だよ。これは古くからC言語APIとして存在しているrand()よりも、統計的にバランスのよい、ランダムな数値を、しかも高速に返してくれるというすぐれものだ。C++の他にもPythonなどさまざまな言語で実装されているようだからチェックしてみてくれ。
最後に、C++メルセンヌツイスターをテストしてみた結果だよ。どういうわけか、引数なしでシード値を暗黙のデフォルト値にした場合と、シード値に5489を指定した場合とで結果が同じになった。しかもその場合は、1万回目の値が、必ず、4123659995 になるというわけらしい。


では、今日はこれで失礼するよ。チャオ!