Difference between mt_rand() and rand()

2020-01-28 08:55发布

问题:

What is the difference between using mt_rand($min, $max) and rand($min, $max) about the speed?

回答1:

Update

Since PHP 7.1 mt_rand has superseded rand completely, and rand was made an alias for mt_rand. The answer below focuses on the differences between the two functions for older versions, and the reasons for introducing mt_rand.


Speed was not why mt_rand was introduced!

The rand function existed way before mt_rand, but it was deeply flawed. A PRNG must get some entropy, a number from which it generates a sequence of random numbers. If you print out a list of ten numbers that were generated by rand() like so:

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

The output can be used to work out what the rand seed was, and with it, you can predict the next random numbers. There are tools out there that do this, so google a bit and test it.

There's also an issue with rand relativily quickly showing patterns in its random numbers as demonstrated here. A problem mt_rand seems to solve a lot better, too.

mt_rand uses a better randomization algorithm (Mersenne Twist), which requires more random numbers to be known before the seed can be determined and is faster. This does not mean that mt_rand is, by definition, faster than rand is, this only means that the way the numbers are generated is faster, and appears to have no real impact on the function's performance, as other answers here have demonstrated.
Either way, have a look at the mt_srand and the srand docs. I'm sure they'll contain some more info

If mt_rand's algorithm translates in an increase in performance, then that's great for you, but it's a happy coincidence. TL;TR:

mt_rand was introduced to fix the problems that exist in rand!



回答2:

Update (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().

That means that since version 7.1 there is no practical difference between both of them because rand calls mt_rand internally.


Before PHP 7.1:

Using rand() is not a bad practice if it not used for security purposes, I'm usually using rand() (habit?).

If you need an enormous amount of random numbers you will need mt_rand instead rand. mt_rand has a period of 219937 − 1, far better than rand (232). Take a look to this article about graphical pattern generation using rand and mt_rand.

Periodicity and entropy are the only reasons for using mt_rand() instead rand() and not security or speed improvements.

Mathematically mt_rand have more entropy and a greater periodicity than rand (219937−1 vs. 232).

If you need a few random numbers and security is not a problem, rand will do the job (get a random number to decide firing a cleanup process).


Testing speed improvements

In practice there is not much difference in speed between the two functions (maybe because PHP⇔C wrapper overhead?).

PHP test code:

<?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);
}

Tests in 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

Tests in PHP 5.4.45 (slower machine):

$ 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

Only 6-9% and not 400% as claimed.


Using for security purposes

But if your application needs a lot of entropy because security issues, you'll need a more secure way and 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.

Neither rand() nor mt_rand() are safe enough:

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.

There is PHP extensions like random_compat, but I didn't recommend using them if it not necessary.



回答3:

PHP Manual on mt_rand() states that it:

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



回答4:

As of PHP 7.1 there is no difference at all. rand() is now an alias for mt_rand().

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

And more details: https://wiki.php.net/rfc/rng_fixes



回答5:


Following is the difference in speed for both of them :-
mt_rand($min, $max) is four times faster as compared to rand($min, $max)

The reason is that,rand($min, $max) uses libc random number generator while mt_rand($min, $max) uses Mersenne Twister which is four times faster.

Hope it will solve your doubt.
Thanks.



回答6:

They appear to be equal in speed:

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";

Results for OSX Mavericks and VirtualBox'ed Ubuntu 11:

Darwin 5.5.19
0.038038969039917
0.033117055892944

Linux 5.3.6-13ubuntu3.10
0.031459093093872
0.031935214996338

If these measures are correct, the manual comment mentioned elsewhere should be considered wrong/obsolete.