Bug #60543 [Opn]: mt_rand() only reliable when ($max - $min) <= mt_getrandmax ()

From: Date: Fri, 16 Dec 2011 07:14:09 +0000
Subject: Bug #60543 [Opn]: mt_rand() only reliable when ($max - $min) <= mt_getrandmax ()
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-165906@lists.php.net to get a copy of this message
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

« previous php.bugs (#165906) next »