php - 重複 - random_int
mt_rand()とrand()の違い (4)
mt_rand($min, $max)
と
rand($min, $max)
の速度の違いは何ですか?
アップデート(PHP 7.1):
rand()
およびsrand()
は、それぞれmt_rand()
およびmt_srand()
エイリアスになりmt_srand()
た。 これは、次の関数の出力に変更があることを意味します:rand()
、shuffle()
、str_shuffle()
、およびarray_rand()
。
つまり、バージョン7.1以降では、
rand
は内部で
mt_rand
呼び出す
ため、両者の間に実際的な違いはありません。
PHP 7.1より前:
rand()
を使用することは、セキュリティ目的で使用しないのであれば悪い習慣ではありません。通常は
rand()
を使用しています(習慣?)。
大量の乱数が必要な場合、
rand
代わりに
mt_rand
が必要に
mt_rand
ます。
mt_rand
の周期は2
mt_rand
− 1で、
rand
(2
32
)よりもはるかに優れています。
rand
および
mt_rand
を使用したグラフィカルパターン生成については、
この記事
を
mt_rand
。
Periodicity
と
entropy
が、
rand()
代わりに
mt_rand()
を使用する唯一の理由であり、セキュリティや速度の改善ではありません。
数学的に
mt_rand
は、
rand
よりも
entropy
が大きく、
Periodicity
が大きくなっています(2
19937
-1対2
32
)。
いくつかの乱数が必要で、セキュリティが問題にならない場合、
rand
はジョブを実行します(クリーンアッププロセスの起動を決定するために乱数を取得します)。
テスト速度の改善
実際には、2つの関数の速度に大きな違いはありません(おそらくPHP⇔Cラッパーのオーバーヘッドですか?)。
PHPテストコード:
<?php
for ($c = 0; $c < 3; $c++) {
$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 100000000; $i++) {
$sum += rand();
}
printf('[rand %d] Time: %.3f s%s', $c, microtime(true) - $start, PHP_EOL);
}
for ($c = 0; $c < 3; $c++) {
$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 100000000; $i++) {
$sum += mt_rand();
}
printf('[mt_rand %d] Time: %.3f s%s', $c, microtime(true) - $start, PHP_EOL);
}
PHP 7.0.19でのテスト:
$ php timing.php
[rand 0] Time: 4.658 s
[rand 1] Time: 4.664 s
[rand 2] Time: 4.654 s
[mt_rand 0] Time: 4.267 s
[mt_rand 1] Time: 4.255 s
[mt_rand 2] Time: 4.261 s
PHP 5.4.45(低速マシン)でのテスト:
$ php timing.php
[rand 0] Time: 10.862 s
[rand 1] Time: 10.889 s
[rand 2] Time: 10.615 s
[mt_rand 0] Time: 10.948 s
[mt_rand 1] Time: 9.883 s
[mt_rand 2] Time: 10.190 s
主張どおり400%ではなく6-9%のみ。
セキュリティ目的で使用する
しかし、セキュリティの問題のためにアプリケーションが多くのエントロピーを必要とする場合は、より安全な方法が必要であり、
openssl_random_pseudo_bytes()
おそらく最善の解決策です。
関連する問題
。
rand()
も
mt_rand()
も十分に安全ではありません
:
注意 この関数は暗号的に安全な値を生成しないため、暗号化の目的には使用しないでください。 暗号的に安全な値が必要な場合は、
random_int()
、random_bytes()
、またはopenssl_random_pseudo_bytes()
使用を検討してrandom_int()
。
random_compat
ようなPHP拡張機能がありますが、必要でない場合は使用しないことをお勧めします。
更新
PHP 7.1以降、
mt_rand
は
rand
完全に取って代わり、
rand
は
mt_rand
エイリアスに
mt_rand
。
以下の答えは、古いバージョンの2つの関数の違いと、
mt_rand
を導入する理由に焦点を当てています。
mt_rand
が導入された理由は速度ではありません!
rand
関数は
mt_rand
前に存在していましたが、深く欠陥がありました。
PRNGは、何らかのエントロピー、つまり乱数のシーケンスを生成する数値を取得する必要があります。
次のように
rand()
によって生成された10個の数値のリストを出力する場合:
for ($i=0;$i<10;++$i)
echo rand(), PHP_EOL;
出力を使用して、
rand
シードが何であるかを計算できます。これを使用して、次の乱数を予測できます。
これを行うツールがありますので、少しグーグルでテストしてください。
また、
ここで
示すように、ランダムにランダムにパターンをすばやく表示するという問題もあり
ます
。
mt_rand
の問題も、はるかによく解決するようです。
mt_rand
は、より良いランダム化アルゴリズム(Mersenne Twist)を使用します。これは、シードを決定する前に、より多くの乱数を知る必要があり、より高速です。
これは、定義により
mt_rand
が
rand
よりも高速であることを意味するものではありません。これは
、数値の生成方法が高速であることを意味するだけであり、関数のパフォーマンスに実際の影響はないようです。
いずれにしても
、
mt_srand
および
srand
docsを
mt_srand
ください。
きっともっと情報が入っていると思います
mt_rand
のアルゴリズムがパフォーマンスの向上に
mt_rand
場合、それはあなたにとって素晴らしいことですが、それは幸せな偶然です。
TL; TR:
mt_rand
は、
rand
存在する問題を修正するために導入されました。
それらは速度が等しいように見えます:
function timeit($times, $func) {
$t = microtime(1);
while($times--) $func();
return microtime(1) - $t;
}
echo PHP_OS, " ", phpversion(), "\n";
echo timeit(100000, function() { rand(0,1000); }), "\n";
echo timeit(100000, function() { mt_rand(0,1000); }), "\n";
OSX MavericksおよびVirtualBox'ed Ubuntu 11の結果:
Darwin 5.5.19
0.038038969039917
0.033117055892944
Linux 5.3.6-13ubuntu3.10
0.031459093093872
0.031935214996338
これらの対策が正しい場合、他の場所で言及されているマニュアルのコメントは間違っている/時代遅れであると考えられるべきです。
mt_rand()
PHPマニュアルには、次のように記載されています。
これは、平均的なlibc rand()が提供するものの4倍の速度で乱数を生成します。