本当の乱数とは(弱い乱数・強い乱数・真の乱数)

本当の乱数とは(弱い乱数・強い乱数・真の乱数)

現実にランダムな値が欲しい時は、サイコロでも降れば事足りるのですが、ソフトウェアだけで真の乱数は作り出せません。
(ハードウェアを使えば出来る。物理的な温度や気圧の僅かな変化を利用する)
擬似乱数(pseudoradam number)は、人間の目には充分ランダムに見えるが、実際には時間を元にしているので、アルゴリズムと正確な時間が測定できれば予測可能。

「真の乱数」とは、以下の3条件が必要です。(情報セキュリティスペシャリストの試験の時に勉強したな…。)
1,偏りが無い(出目が偏っていると乱数として使えないので…。これだけだと「弱い乱数」)
2,規則性が無い(予想できない。1の条件も持っていれば「強い乱数」)
3,再現性が無い(ログを使わない限り、同じ乱数列は再現不可能。以上の3条件が揃っていれば「真の乱数」)

普通に売っているサイコロも厳密に言えば、穴の数が違ったり1の出目に大きな穴が開いているので、厳密な測定では偏りが発生します。
上記の定義によるとサイコロを振る事は、なんと「弱い乱数」ですらなかったという(^_^;)

ラスベガスのカジノなど、サイコロの出目に大金が動くような場合では「プレシジョン・ダイス(Precision Dice = 正確なサイコロ)」という穴を同じ比重で埋めた高価なサイコロを使ったりするそうです。
dice
一個で1000円~1500円もするので、普通の人には無縁なサイコロですね。
こちらに詳しい説明が書いてありました。
http://yaplog.jp/drosselmeyers/archive/23

話をプログラミングに戻すと、昔ながらのCライクな言語では乱数を生成する時にrand()という関数を使うのですが、何も考えずに使うといつも同じ乱数列を返してきます(なにせ擬似変数という位ですから…。)
それだと流石に困るので、乱数の種(シード)を指定します。通常は時間を渡します。まあ乱数の初期化みたいなものですね。大抵はsrand(time)といった関数です。(PHP4.2以上なら宣言不要)

これで時間が異なれば、異なった乱数列が返ってくるので良かった良かった…。とは、なりません!!
時間をベースにしているので、for文で一気に乱数列を取ってくると割りと分布の偏りを感じます。
なので、最終的には以下のようにしましょう(言語はPHP)

mt_srand()/mt_rand()って何?という感じですが、基本的にはsrand/randの上位互換(メルセンヌ・ツイスター法)です。
それよりも重要なのは、openssl_random_pseudo_bytes()という関数です。
これはこの関数はSSLに使う暗号論的擬似乱数生成器なのですが、まあ「強い乱数」と同義と思っていて大丈夫です。
とりあえず、PHP5.3以上なら使えるので、現状では乱数発生にはこれが一番!というのが自分の結論です。