乱数とは何か(疑似乱数と暗号学的乱数、再現性)

サイコロで試す

コインで表が3回続いても、それだけで投げ方に偏りがあるとは判断できません。画面の抽選も同じです。結果の並びが偏って見えるかどうかと、次の結果を前もって知れるかどうかは、別々に考えます。

真の乱数と疑似乱数

乱数には「真の乱数」と「疑似乱数」があります。真の乱数は、電気的な揺らぎや放射線の到達間隔のような物理現象から取り出す数で、原理的に予測できません。疑似乱数は、計算式で乱数のように見える数の列を作るもので、コンピュータで使う乱数のほとんどはこちらです。

疑似乱数にも二つの系統があります。一つは、偏りが少なく速く作れることを重視したものです。もう一つは暗号学的乱数と呼ばれ、過去の出力から次の値を予測できないことを重視しています。暗号学的乱数は、物理現象から得た値を種にして、予測しにくいと確かめられた計算方法で値を作ります。

くじ引きやルーレットなら、どちらの系統でも出る数の均一さは足ります。違いが出るのは「誰かが結果を先読みして操作できないか」と聞かれたときで、暗号学的乱数なら先読みできないと答えられます。

ブラウザの二つの乱数機能

Webブラウザで乱数を得る方法は、主に次の二つです。

  • Math.random は、0以上1未満の小数を返す手軽な関数です。ゲームやアニメーションで広く使われます。多くのブラウザで偏りは小さいものの、先読みできないことまでは保証されていません。
  • crypto.getRandomValues は、暗号学的乱数を返す機能です。パスワードや認証用の値を作るときに使われます。

ルーレットどんの名前ルーレットは、crypto.getRandomValues で当選者を選びます。それでも、同じ名前を二度入れていたり、「当たりやすさと除外を設定」で重みを変えていたりすれば、確率はその分変わります。全員を同じ確率にしたいときは、回す前に候補の欄と重みを確かめてください。

シードと再現性

疑似乱数は計算で作るので、計算の出発点である「シード(種)」が同じなら、まったく同じ数の列が出ます。これを再現性と呼びます。ゲームの対戦記録を再生したり、プログラムの動きを確かめたりするときに使われます。

くじ引きで再現性を使うと、「このシードで引きました」と公開すれば誰でも同じ結果を確かめられます。反対に、シードを先に知っている人には結果も先に分かります。そこで、参加者が決めた数と主催者が決めた数を組み合わせてシードにし、どちらか一方だけでは結果を決められないようにするやり方があります。

名前ルーレットには、利用者が指定できるシードはありません。同じ候補で同じように回しても、毎回違う結果が出ます。これは故障ではなく、その場で誰にも予測できない結果を出すための作りです。

あみだくじは扱いが違います。横線の配置はシードから作られ、「名簿・設定付きURLをコピー」で渡したURLにもそのシードが入ります。受け取った人の画面にも同じ線が引かれるので、同じくじを複数の端末で確かめられます。配置を変えたいときは「線を引き直す」を押します。

同じ人が続けて当たるのは珍しくない

ルーレットで同じ人が続けて当たると、偏っているように見えます。乱数が正しく動いていても、連続当選は普通に起こります。

10人を毎回同じ重みで、当たった人も外さずに引くとします。前もって決めた特定の人が2回続けて当たる確率は、10分の1 × 10分の1 で100分の1です。ところが「誰でもいいので同じ人が2回続く」確率は、1回目が誰でもよく、2回目がその人と同じなら成り立つので10分の1です。続けて2回引くたびに、10回に1回ほどは同じ人が続きます。

3回続けて引いて、3回とも同じ人が当たる確率は100分の1です。逆に、30回回しても一度も当たらない人が出ることもあります。乱数の均等さは、たくさん回したときに当たった回数がそろってくるという意味です。順番に当たるという意味ではないので、数回だけを見ると偏って見えます。

利用者が確かめられること

ツールが公平かどうかは、使う側でも次の方法で確かめられます。

  1. ツールの説明に、乱数の作り方、重みの有無、除外の仕組みが書かれているかを読みます。
  2. 候補を2〜3個にして数十回回し、極端な偏りがないかを見ます。細かい検証にはなりませんが、明らかな不具合なら気づけます。
  3. 回す前に、重みがすべて同じか、同じ名前が二度入っていないかを全員で見ます。乱数に問題がなくても、設定の見落としがあれば確率は変わります。
  4. 結果が出たあとに引き直したり、候補を入れ替えたりしないと決めておきます。

関連ツール