Bug #69396 [Ver->Csd]: Strange behavior of rand function with specific big $max value
Edit report at https://bugs.php.net/bug.php?id=69396&edit=1
ID: 69396
Updated by: nikic@php.net
Reported by: mariusz at mariuszgil dot pl
Summary: Strange behavior of rand function with specific big
$max value
-Status: Verified
+Status: Closed
Type: Bug
Package: *Math Functions
Operating System: Mac, Linux
PHP Version: 5.5.23
-Assigned To:
+Assigned To: nikic
Block user comment: N
Private report: N
New Comment:
This has been fixed in PHP 7.1.
Previous Comments:
------------------------------------------------------------------------
[2015-04-08 13:54:26] cmb@php.net
At least in NTS builds, for $max > getrandmax() PHP calls the PRNG
of the C library and simply scales up the returned value, so some
values will be never be generated. For instance, rand(0, 2 *
getrandmax() + 1) will (usually) never return an odd value.
Instead of emitting a notice when $max > getrandmax(), or even
changing the behavior, it might be sufficient to change the
documentation accordingly.
------------------------------------------------------------------------
[2015-04-07 20:13:17] mariusz at mariuszgil dot pl
Description:
------------
With specific big $max value, rand(0, $max) function returns unexpected, strange values.
Test script creates an array with numbers of occurences rand(0, $max) % $n results. Expected result
is an array with all values (almost) equal, with big $iter value.
But when $max is equal:
- getrandmax() * 2
- getrandmax() * 2 + 1
- getrandmax() * 2 + 2
returned array looks like:
array(16) {
[0]=>
int(0)
[1]=>
int(124837)
[2]=>
int(0)
[3]=>
int(125168)
[4]=>
int(0)
[5]=>
int(124687)
[6]=>
int(0)
[7]=>
int(125015)
[8]=>
int(0)
[9]=>
int(124685)
[10]=>
int(0)
[11]=>
int(125265)
[12]=>
int(0)
[13]=>
int(125077)
[14]=>
int(0)
[15]=>
int(125266)
}
When $max is equal:
- getrandmax() * 2 + 4
- getrandmax() * 2 + 6
- getrandmax() * 2 + 8
- getrandmax() * 2 + 10
- ...
distribution of counters looks very strange, like:
array(16) {
[0]=>
int(83187)
[1]=>
int(41787)
[2]=>
int(83074)
[3]=>
int(41420)
[4]=>
int(83377)
[5]=>
int(41756)
[6]=>
int(83319)
[7]=>
int(41941)
[8]=>
int(83469)
[9]=>
int(41925)
[10]=>
int(83327)
[11]=>
int(41544)
[12]=>
int(83287)
[13]=>
int(41528)
[14]=>
int(83098)
[15]=>
int(41961)
}
Probably, when $max is greater then getrandmax(), an error/notice should be generated.
Test script:
---------------
<?php
$iter = 1000000;
$max = getrandmax() * 2;
$n = 16;
$values = array_fill(0, $n, 0);
for ($i = 0; $i < $iter; $i++) {
$values[rand(0, $max) % $n] += 1;
}
var_dump($values);
Expected result:
----------------
Expected results of test script is something similiar to:
array(16) {
[0]=>
int(62287)
[1]=>
int(62495)
[2]=>
int(62638)
[3]=>
int(62791)
[4]=>
int(62386)
[5]=>
int(62533)
[6]=>
int(62921)
[7]=>
int(62532)
[8]=>
int(62971)
[9]=>
int(62541)
[10]=>
int(62854)
[11]=>
int(61833)
[12]=>
int(62269)
[13]=>
int(62305)
[14]=>
int(62351)
[15]=>
int(62293)
}
when all values are close to each other.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=69396&edit=1
Thread (3 messages)