What is the minimum PHP value mt_rand () and how to calculate a 32-bit interfer on a 32-bit Linux panel

What is the minimum value allowed for mt_rand() ? Is this the same value for 32-bit and 64-bit machines? How can I generate a 32-bit integer using mt_rand() (note that it does not have to be very random)?

BACKGROUND WHY I ASKED: I have a 64-bit physical development server and a 32-bit VPS. I just realized that the production server does not generate PCs covering the entire range. To find out what is happening, I ran the following script. A 64-bit machine never (or, at least, I never witnessed), but 32 bits corresponds to approximately 50% of the time.

 <?php date_default_timezone_set('America/Los_Angeles'); ini_set('display_errors', 1); error_reporting(E_ALL); $count=0; for ($i = 0; $i <= 10000; $i++) { $rand=2147483648+mt_rand(-2147483647,2147483647); //Spans 1 to 4294967295 where 0 is reserved if($rand==2147483649){$count++;} } echo('mt_getrandmax()='.mt_getrandmax().' count='.$count); 

Exit

 mt_getrandmax()=2147483647 count=5034 
+4
linux php random
Jul 6 '15 at 18:02
source share
3 answers

TL; DR: To get a random integer over the entire range of possible integers, use:

 function random_integer() { $min = defined('PHP_INT_MIN') ? PHP_INT_MIN : (-PHP_INT_MAX-1); return mt_rand($min, -1) + mt_rand(0, PHP_INT_MAX); } 

For PHP 7 you can use random_int() .




Under the hood ( 1 , 2 ), PHP does this:

 $number = random_number_between_0_and_0x7FFFFFFF_using_Mersenne_Twister; $number = $min + (($max - $min + 1.0) * ($number / (0x7FFFFFFF + 1.0))); 

Pay attention to $max - $min . When max is set to the upper end and min is something negative, an overflow occurs. Therefore, the maximum range is PHP_INT_MAX . If your maximum value is PHP_INT_MAX , then your minimum is necessarily 0 .

Now for the background. PHP implements the 32-bit Mersenne Twister algorithm. This gives random integers between [0 and 2 ^ 31-1). If you request any other range, PHP scales this number using the simple binning function. This binning function includes subtraction, which can lead to overflow, and this problem.

Thus, if you want to get a range larger than can be represented as an integer in PHP, you need to add the intervals together, for example:

 mt_rand(PHP_INT_MIN, -1) + mt_rand(0, PHP_INT_MAX); 

Please note that PHP_INT_MIN available since PHP 7, so you will need to calculate the appropriate minimum for your environment before that.




Note that 2 ^ 31-1 is what getrandmax() returns. People mistakenly believe that getrandmax() will return 2 ^ 63-1 on a 64-bit machine. It is not true. getrandmax() returns the maximum integer returned by the algorithm, which is always 2 ^ 31-1.

+3
Jul 06 '15 at 19:10
source share

You can generate a 32 bit integer like this:

 $rand = unpack("l", openssl_random_pseudo_bytes(4)); 
+2
Jul 6 '15 at 18:16
source share

This is a problem noted in PHP docs here

This works fine on a 64-bit version of Linux:

  <?php printf ("%08x\n", mt_rand (0, 0xFFFFFFFF)); ?> 

but on our 32-bit Linux development server it always gives 00000000 .

On the same machine it is:

 <?php printf ("%08x\n", mt_rand (0, 0xFFFFFFF0)); ?> 

seems to always give either 00000000 or a number in the range from fffffff2 to ffffffff . It:

 <?php printf ("%08x\n", mt_rand (0, 0xFFFFFF00)); ?> 

gives numbers in which the last two digits change, and so on, at least 0xF0000000.

However, this:

 <?php printf ("%08x\n", mt_rand (0, 0x7FFFFFFF)); ?> 

works great

Added bug report here .

There were no words if PHP fixes this yet.

In the meantime, you can use the mt_rand function between max_rand , and you should be fine

Usage example

 $rand=mt_rand(1,2147483647)+mt_rand(0,2147483647); 
+1
Jul 06 '15 at 18:50
source share



All Articles