サイコロと擬似乱数について

日本語プログラミング言語「なでしこ」公式サイト

今回、取り上げるのは「乱数」です。乱数とは、サイコロのように、規則性がなく予測不能な数値のことです。一言で言うなら「デタラメな数」ですが、コンピューターでデタラメな数を生成するのは、なかなか難しいものです。

と言うのも、コンピューターの良いところは、どんな処理でも文句一つ言わずに繰り返し実行してくれるところなので、急にデタラメにして欲しいと言っても難しいものなのです。

それでも、ゲームや暗号など、乱数は様々な場面で使われています。コンピューターで乱数を生成する方法ですが、やはり、計算によって生成しています。つまり、本当の乱数ではなく、乱数っぽく見える「擬似乱数」というのが正確な表現です。

そして、この擬似乱数を得るために、様々な研究が行われています。擬似乱数をいかにして、「良い精度」でかつ「高速」に計算できるのかという点が重要です。もちろん、ここで言う「良い精度」というのは、同じパターンが繰り返し出現したり、値の出現頻度が偏ったりしないことです。そう考えると、なかなか難しいことが分かります。

なでしこで簡単に疑似乱数を使う方法

とは言え、既に、なでしこでは、システムが提供する疑似乱数関数を利用して、乱数を手軽に生成することができます。そのためには、「乱数」命令を使います。ここで、なでしこのWeb簡易エディタで試してみましょう。

 100回
   1000の乱数を表示。
 ここまで。

このプログラムを記述して「実行」ボタンを押すと、1000未満の乱数が100個表示されます。

なでしこで乱数を100個表示したところ

なでしこで、『Nの乱数』と書くと、0から(N-1)までの間のいずれかの整数を生成して返します。

そのため、1から6までのサイコロを再現したい場合には、以下のように、『乱数』命令で得た値に1を足して書くと良いでしょう。

 R = (6の乱数) + 1
 Rを言う。

このプログラムを記述して、「実行」ボタンを押すと、ダイアログにサイコロの目が表示されます。

ダイアログにサイコロの目が表示されます

どういう仕組み?

ところで、計算で擬似乱数を生成していると聞くと、一体、どうやって計算しているのだろうかと気になるものです。そこで、擬似乱数を生成する簡単なプログラムを、なでしこで実装してみましょう。

擬似乱数を得るには、いろいろな方法があり、少し前までよく使われていたのは、「線形合同法」と呼ばれる計算方法です。線形合同法は、以下のような計算を用いて疑似乱数を生成します。

線形合同法の計算式

これを実際になでしこで実装すると、以下のようになります。

 種 = システム時間

 ●(Nの)擬似乱数生成処理
   A=1103515245
   B=12345
   C=2147483647
   種=(A * 種 + B) % C
   (種%N)を戻す
 ここまで

 100回
   6の擬似乱数生成処理して表示
 ここまで

乱数の種(シード)を適当に決定し、その種に適当な数値を掛けたり足したりして、擬似的に値を生成します。そして、その後で乱数を生成する時には、前回計算した種を利用して、新たな乱数を生成するという仕組みになります。

この線形合同法が好まれたのは、掛けて足すだけで手軽に乱数を生成できるので、高速に擬似乱数を得られるという点です。とは言え、短所もあります。この方法で作った擬似乱数は、どうしても、規則的になってしまう点です。特に、下位ビットのランダム性が低くなる点が指摘されています。特に上の式でCに当たる値に偶数を与えた場合に規則的な値が生成されます。

よりモダンなXorshiftアルゴリズム

そこで、最近では、擬似乱数を得るために「Xorshift」というアルゴリズムが採用されることが多くなっています。Google Chromeでもバージョン49(2016年初めのリリース)以降では、このXorshiftが擬似乱数生成のために使われるようになりました。Xorshiftでは、ビット演算のXORとビットシフトの仕組みを利用して、擬似乱数を生成する手法です。

以下は、なでしこで、Xorshiftを実装したプログラムです。プログラムを実行すると、ランダムな数が100個表示されます。XORとSHIFT_L/SHIFT_Rを組み合わせた3行のプログラムで擬似乱数を生成できます。

 種=システム時間

 ●(Nの)擬似乱数処理
   種=XOR(種, SHIFT_L(種, 13))
   種=XOR(種, SHIFT_R(種, 17))
   種=XOR(種, SHIFT_L(種, 15))
   ABS(種%N)を戻す
 ここまで。

 100回
   1000の擬似乱数処理を表示。
 ここまで

擬似乱数を生成する関数を定義したところ

まとめ

以上、今回は、コンピューターで「疑似乱数」を計算する方法を紹介しました。ゲームを代表として、さまざまなプログラムで、乱数を利用する機会は多いと思います。そこで、どのような仕組みで乱数が生成されているのか、精度はどうなのか、興味を持って調べてみると面白いものです。

ちなみに、なでしこでは以前から乱数の生成にこだわっていました。なでしこv3以降は、ブラウザを信頼して標準乱数を利用していますが、2004年から開発しているなでしこv1では、OSが用意する簡易乱数を使うのではなく、メルセンヌ・ツイスタ(MT19937)という手法を利用した良質な乱数を生成するようにしていました。

自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2005年IPAスーパークリエイター認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。