mt_rand() 和 rand() 之间的区别

Difference between mt_rand() and rand()

关于速度,使用mt_rand($min, $max)rand($min, $max)有什么区别?

PHP mt_rand() 上的手册指出:

which will produce random numbers four times faster than what the average libc rand() provides.


以下是两者的速度差异:-
mt_rand($min, $max) 倍 [= =11=]

原因是,rand($min, $max)使用libc随机数生成器mt_rand($min, $max)使用Mersenne Twister 快四倍。

希望它能解决您的疑问。
谢谢。

它们的速度似乎相等:

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 的结果 Ubuntu 11:

Darwin 5.5.19
0.038038969039917
0.033117055892944

Linux 5.3.6-13ubuntu3.10
0.031459093093872
0.031935214996338

如果这些措施是正确的,应该考虑其他地方提到的人工评论wrong/obsolete。

更新

由于 PHP 7.1 mt_rand 已完全取代 randrand 成为 mt_rand 的别名。下面的回答主要针对老版本两个函数的区别,以及引入mt_rand.

的原因

速度不是引入 mt_rand 的原因!

rand 函数早在 mt_rand 之前就存在了,但它存在严重缺陷。 PRNG 必须获得一些熵,它从中生成一系列随机数。如果您打印出由 rand() 生成的十个数字的列表,如下所示:

for ($i=0;$i<10;++$i)
    echo rand(), PHP_EOL;

输出可用于计算出 rand 种子是什么,并用它预测下一个随机数。有一些工具可以做到这一点,所以 google 稍微测试一下。

rand 在其随机数 as demonstrated here 中相对快速地显示模式也存在问题。一个问题 mt_rand 似乎也解决得更好了。

mt_rand使用了更好的随机化算法(Mersenne Twist),需要知道更多的随机数才能确定种子速度更快。 这并不意味着 mt_rand 根据定义比 rand,这仅意味着生成的数字更快,并且似乎对函数的性能没有真正的影响,正如这里的其他答案所证明的那样。
不管怎样,看看 the mt_srand and the srand docs。我相信它们会包含更多信息

如果 mt_rand 的算法转化为性能的提高,那么这对您来说很好,但这是一个快乐的巧合。长话短说:

mt_rand的引入是为了修复rand!

中存在的问题

更新 (PHP 7.1):

rand() and srand() have now been made aliases to mt_rand() and mt_srand(), respectively. This means that the output for the following functions have changes: rand(), shuffle(), str_shuffle(), and array_rand().

这意味着从 7.1 版开始,两者之间没有实际区别,因为 rand calls mt_rand internally


之前 PHP 7.1:

如果不是出于安全目的,使用 rand() 并不是一个坏习惯,我通常使用 rand()(习惯?)。

如果您需要大量的随机数,您将需要 mt_rand 而不是 randmt_rand 的周期为 219937 − 1,远好于 rand (232)。查看 this article 关于使用 randmt_rand.

生成图形模式

Periodicity and entropy 是使用 mt_rand() 而不是 rand() 的唯一原因,而不是安全或速度改进。

在数学上 mt_randrandentropy and a greater periodicity (219937−1 对比 232).

如果您需要一些随机数并且安全性不是问题,rand 可以胜任(获取一个随机数来决定启动清理过程)。


测试速度改进

实际上这两个函数在速度上没有太大差异(可能是因为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);
}

PHP7.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

只有 6-9% 而不是声称的 400%。


出于安全目的使用

但是如果您的应用程序因为安全问题需要大量的熵,您将需要一种更安全的方式并且openssl_random_pseudo_bytes() possibly is the best solution, does its work (far better but slower? we need security over speed?) relying on openssl related issues

rand() nor mt_rand() 都不够安全:

Caution This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. If you need a cryptographically secure value, consider using random_int(), random_bytes(), or openssl_random_pseudo_bytes() instead.

有 PHP 个扩展,例如 random_compat,但如果没有必要,我不建议使用它们。

从 PHP 7.1 开始,完全没有区别。 rand() 现在是 mt_rand() 的别名。

http://php.net/manual/en/migration71.incompatible.php#migration71.incompatible.rand-srand-aliases

更多详情:https://wiki.php.net/rfc/rng_fixes