Edit report at https://bugs.php.net/bug.php?id=60543&edit=1
ID: 60543
User updated by: daniel at danielnorton dot com
Reported by: daniel at danielnorton dot com
Summary: mt_rand() poor quality with large magnitude negative
$min
Status: Open
Type: Bug
Package: Math related
Operating System: Windows
PHP Version: 5.3.8
Block user comment: N
Private report: N
New Comment:
In a 64-bit environment, although documented to be limited to
mt_getrandmax() (which is 0x7FFFFFFF in my environment), for
the purposes of diagnosis, the following is notable:
**1) The problem does not seem to surface when the absolute value
of both the $min and $max is within (PHP_INT_MAX/2)-1
(0x3FFFFFFFFFFFFFFF).
**2) The oft-repeated value is always $min & PHP_INT_MAX, which
always yields a positive integer.
Previous Comments:
------------------------------------------------------------------------
[2011-12-16 05:11:07] daniel at danielnorton dot com
Further study in a 32-bit environment shows:
**1) The problem does not seem to surface when the absolute value of
both the $min and $max is within 0x3FFFFFFF. In other words, it works
as expected when the range is within -1073807359 ... 1073807359
(-0x3FFFFFFF ... 0x3FFFFFFF).
**2) The oft-repeated value is always $min & 0x7FFFFFFF, which is
always a positive integer.
------------------------------------------------------------------------
[2011-12-16 01:55:54] daniel at danielnorton dot com
Description:
------------
Example output from the following script that generates 16 random numbers in
the
range from -1073741823 to 2147483647. It shows that the number 1073741825 was
repeated 4 times, or 25% of the time. This output is typical and the repeated
number is always 1073741825. The problem is less the smaller the magnitude of
$min.
Test script:
---------------
<?php
printf("PHP_VERSION=%s\n",PHP_VERSION);
$min = -(mt_getrandmax()>>1);
$max = mt_getrandmax();
$count = isset($argv[1])?(int)$argv[1]:16;
printf("min=%d, max=%d, count=%d\n",$min,$max,$count);
$repeat_counts = array();
for ($i=0;$i<$count;$i++) {
$random = mt_rand($min,$max);
if (!isset($repeat_counts[$random])) {
$repeat_counts[$random] = 0;
}
$repeat_counts[$random]++;
//printf("%12d%s\n", abs($random),($random<0)?"-":"");
}
$max_repeat_count = max($repeat_counts);
$same_value_max = array();
if ($max_repeat_count > 1) {
foreach ($repeat_counts as $value => $repeat_count) {
if ($repeat_count >= $max_repeat_count) {
$same_value_max[] = $value;
}
}
printf("The following number/s was/were repeated %d times (%s%%): %s\n"
,$max_repeat_count
,number_format(($max_repeat_count/$count)*100.0,1)
,implode(", ",$same_value_max)
);
}
Expected result:
----------------
PHP_VERSION=5.3.8
min=-1073741823, max=2147483647, count=16
Actual result:
--------------
PHP_VERSION=5.3.8
min=-1073741823, max=2147483647, count=16
The following number/s was/were repeated 4 times (25.0%): 1073741825
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=60543&edit=1