rand(), mt_rand() and limits
| From: | Andrea Faulds | Date: | Sun, 11 Jan 2015 22:12:42 +0000 |
| Subject: | rand(), mt_rand() and limits | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-80383@lists.php.net to get a copy of this message | ||
Hey internals,
As we’re moving to clean some things up in PHP 7, I think it might be worth looking at the
rand()/mt_rand() situation.
Currently, we have two standard-library functions to obtain a random number: rand() and mt_rand().
rand() uses the C standard library function, which on many stdlibs is slow or has a limited range
(e.g. Win32 rand()’s maximum return value is SHORT_MAX). As a result, a drop-in replacement was
added, mt_rand(), which uses Mersenne Twister-based random number generator that’s probably better
than what the C standard library provides.
Having two different random number functions is confusing to new users, and an oft-cited issue with
PHP’s standard library. Intuitively, a user would expect rand() to be the function to get a random
number, but actually they should be using mt_rand(), which is usually better.
Another issue is the fact we allow random numbers to be seeded with srand() and mt_srand(). We have
automatically seeded the random number generator for a while now, so there is no need to do it
manually. We also explicitly do not guarantee that the random number generator will always produce
the same output given the same seed, and in fact we’ve changed mt_rand()'s behaviour in the
past. This eliminates the primary use-case for manual seeding when there is automatic seeding:
predictable output for procedural generation.
Finally, a third issue is that mt_rand() does not produce good quality numbers on 64-bit platforms.
mt_rand() will always produce a 32-bit value internally, and scale it up or down to fit the
user-specified range. Unfortunately, this means that values for the $max parameter beyond 2^31 - 1
produce numbers with poor granularity.
Given all these, I would suggest that for PHP 7, we:
* Get rid of rand(), srand() and getrandmax()
* Rename mt_rand(), mt_srand() and mt_getrandmax() to rand(), srand(), and getrandmax() but add
mt_* aliases for backwards-compatibility
* Make mt_srand() and srand() do nothing and produce a deprecation notice
* Use a 64-bit random number generation algorithm on 64-bit platforms (or invoke the 32-bit
generator twice)
The end result should be that PHP has just one random number generation function, rand(), which can
produce the full range from PHP_INT_MIN to PHP_INT_MAX with no scaling. This would be far more
intuitive, I think.
Would that sound good?
Thanks!
--
Andrea Faulds
http://ajf.me/