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
+Summary:            mt_rand() only reliable when ($max - $min) <=
                     mt_getrandmax ()
 Status:             Open
 Type:               Bug
 Package:            Math related
 Operating System:   Windows
 PHP Version:        5.3.8
 Block user comment: N
 Private report:     N

 New Comment:

I suggest changing the title of this to "mt_rand() only reliable when
($max - $min) <= mt_getrandmax ()".


Previous Comments:
------------------------------------------------------------------------
[2011-12-16 06:18:19] daniel at danielnorton dot com

The problem does not appear if ($max - $min) <= PHP_INT_MAX.

Perhaps this is a documentation problem and the solution might simply be to 
specify that ($max - $min) must be less than mt_getrandmax()?

------------------------------------------------------------------------
[2011-12-16 05:38:22] daniel at danielnorton dot com

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.

------------------------------------------------------------------------
[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

Reply via email to