php - 重複 - random_int




mt_rand()とrand()の違い (4)

アップデート(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

Periodicityentropy が、 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拡張機能がありますが、必要でない場合は使用しないことをお勧めします。

mt_rand($min, $max)rand($min, $max) の速度の違いは何ですか?


更新

PHP 7.1以降、 mt_randrand 完全に取って代わり、 randmt_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_randrand よりも高速であることを意味するものではありません。これは 、数値の生成方法が高速であることを意味するだけであり、関数のパフォーマンスに実際の影響はないようです。
いずれにしても 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倍の速度で乱数を生成します。





random