什么是PHP的mt_rand()最小值以及如何在32位Linux机器上计算32位内插

时间:2015-07-06 18:03:00

标签: php linux random

find允许的最低值是多少? 32位和64位机器的值是否相同?如何使用mt_rand()生成32位整数(请注意,它不需要高度随机)?

背景为什么我要求:我有一个64位开发物理服务器和一个32位生产VPS。刚刚意识到生产服务器没有产生跨越整个范围的PK。为了弄清楚发生了什么,我运行了以下脚本。 64位机器永远不会(或者至少我没见过)匹配,但32位匹配大约50%的时间。

mt_rand()

输出

<?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);

3 个答案:

答案 0 :(得分:3)

TL; DR:要获得整个可能整数范围内的随机整数,请使用:

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);
}

对于PHP 7,您可以使用random_int()

在幕后(12),PHP正在执行此操作:

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

注意$max - $min。当max设置为高端且min为负值时,会发生溢出。因此,最大范围PHP_INT_MAX。如果您的最大值为PHP_INT_MAX,那么您的最低值必须为0

现在回顾一下。 PHP实现了32位Mersenne Twister算法。这给出了[0和2 ^ 31-1]之间的随机整数。如果您要求任何其他范围,PHP 使用简单的分箱功能缩放该数字。该分箱功能包括可导致溢出的减法,以及此问题。

因此,如果你想获得一个比PHP中的整数更大的范围,你必须一起添加间隔,如下所示:

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

请注意,从PHP 7开始,PHP_INT_MIN可用,因此您需要在此之前为您的环境计算合适的最小值。

另外,请注意2 ^ 31-1是getrandmax()返回的内容。人们错误地认为在64位机器上getrandmax()将返回2 ^ 63-1。那不是真的。 getrandmax()返回算法将返回的最大整数,该值始终为2 ^ 31-1。

答案 1 :(得分:2)

您可以像这样生成32位整数:

$rand = unpack("l", openssl_random_pseudo_bytes(4));

答案 2 :(得分:1)

这是PHP文档中提到的问题

  

这在64位Linux上运行良好:

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

但是在我们的32位Linux开发服务器上,它始终会产生00000000

     

在同一台机器上,这个:

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

似乎总是产生00000000fffffff2ffffffff范围内的数字。这个:

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

给出最后两位数字变化的数字,依此类推至少0xF0000000.

     

但是,这个:

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

工作正常

添加了错误报告here

目前还没有人说PHP是否正在解决这个问题。

在此期间,您可以使用mt_rand之间的max_rand功能,您应该没问题

使用示例

$rand=mt_rand(1,2147483647)+mt_rand(0,2147483647);