もくじ
はじめに
どうも! みなため(@MinatameT)です。
PHPで乱数を生成する方法はいくつかありますが、ここでは「メルセンヌ・ツイスター法」と「暗号論的に安全な疑似乱数の生成法」の2つを紹介します。
どちらも整数値の乱数を出します。また、最小値と最大値を決めることができますが、最大値は限界値(後述)をオーバーしない範囲にする必要があります。
名前から難しいイメージがあると思いますが、実際は簡単に実施できます。そう、PHPならね。
メルセンヌ・ツイスター法
概要と文法
まずは、メルセンヌ・ツイスター法からです。これは、ソーシャルゲームのガチャにも利用されている乱数生成法です。
しかし、この方法は生成される乱数を予測できてしまうため、暗号に利用してはいけないとされています。
まずは、文法から確認していきます。以下は、メルセンヌ・ツイスター法で乱数を生成することができる「mt_rand関数」のコードです。
mt_rand(最小値,最大値);
そのままですが、最小値には生成される乱数の最小値を、最大値には生成される乱数の最大値を入れます。
ただし、最大値は限界値を超えないように設定する必要があります。限界値を確認するためには、以下のコードを実行してください。
<?php
echo mt_getrandmax(); /*乱数の限界値を表示する。*/
?>
ちなみに、私の使っている環境では、限界値は2147483647でした。
文法と限界値のチェックはここまでです。
サンプルコードと実行結果の例
それでは、メルセンヌ・ツイスター法を使った乱数生成のコードの具体例(サンプル)を紹介します。
<?php
$L; /*ループ用変数L*/
for($L=0; $L<10; $L=$L+1) /*10回ループする。*/
{
echo mt_rand(0,100); /*0から100までの乱数を表示。*/
echo "<br>"; /*改行*/
}
?>
mt_rand関数で0から100までの乱数を表示し、改行します。これをfor文で10回繰り返しています。
これを実行してみると、次のようになりました。
1
37
3
37
51
97
20
29
71
26
範囲内の乱数が表示されていることがわかりますね。
暗号論的に安全な疑似乱数の生成法
概要と文法
メルセンヌ・ツイスター法では生成される値を予測できてしまうため、暗号論的に安全ではありません。
そこで、PHPで使える「暗号論的に安全な疑似乱数の生成法」を紹介します。この方法では、偏りのない予測不可能な乱数が生成できます。これで安全ですね。
まずは、文法から確認していきます。以下は、暗号論的に安全な疑似乱数の生成法で乱数を生成することができる「random_int関数」のコードです。
random_int(最小値,最大値);
そのままですが、最小値には生成される乱数の最小値を、最大値には生成される乱数の最大値を入れます。
ただし、最大値は限界値を超えないように設定する必要があります。限界値を確認するためには、以下のコードを実行してください。
<?php
echo PHP_INT_MAX; /*乱数の限界値を表示する。*/
?>
ちなみに、私の使っている環境では、限界値は2147483647でした。
文法と限界値のチェックはここまでです。
サンプルコードと実行結果の例
それでは、暗号論的に安全な疑似乱数の生成法を使った乱数生成のコードの具体例(サンプル)を紹介します。
<?php
$L; /*ループ用変数L*/
for($L=0; $L<10; $L=$L+1) /*10回ループする。*/
{
echo random_int(0,100); /*0から100までの乱数を表示。*/
echo "<br>"; /*改行*/
}
?>
random_int関数で0から100までの乱数を表示し、改行します。これをfor文で10回繰り返しています。
これを実行してみると、次のようになりました。
13
77
1
5
43
53
35
8
43
92
範囲内の乱数が表示されていることがわかりますね。
処理速度の比較
最後に、両者の10万回の乱数生成にかかる時間を計測して比較してみました。試行回数は20回で、結果は小数第6位まで表示しています。
mt_rand関数 | random_int関数 |
0.083005秒 | 2.398137秒 |
0.093006秒 | 2.220126秒 |
0.107006秒 | 2.383137秒 |
0.096006秒 | 2.369135秒 |
0.050003秒 | 0.545032秒 |
0.184010秒 | 2.334134秒 |
0.123007秒 | 2.091120秒 |
0.130008秒 | 2.351134秒 |
0.109006秒 | 2.378136秒 |
0.130007秒 | 2.376136秒 |
0.181010秒 | 2.326133秒 |
0.040002秒 | 2.359135秒 |
0.107006秒 | 2.390137秒 |
0.148008秒 | 2.352135秒 |
0.116007秒 | 0.721041秒 |
0.130008秒 | 2.364135秒 |
0.124007秒 | 2.387137秒 |
0.113007秒 | 2.338134秒 |
0.122007秒 | 2.402138秒 |
0.052003秒 | 1.195069秒 |
この結果から、10万回の乱数生成をするために、mt_rand関数は平均で「0.111906秒」、random_int関数は平均で「2.114071秒」かかったことがわかります。
よって、random_int関数はmt_rand関数の約18.89倍の処理時間がかかる……ということがわかりました。
random_int関数は暗号に使えて安全なものですが、処理速度は比較的遅いです。そのため、超高速で乱数を生成する必要があれば、mt_rand関数を使ったほうが良さそうです。