PHP 的 mt_rand() 最小值是多少以及如何在 32 位 Linux 盒子上计算 32 位交互器


What is PHP's mt_rand() minimum value and how to calculate 32 bit interger on 32 bit Linux box

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

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

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

输出

mt_getrandmax()=2147483647 count=5034

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() .


在引擎盖(1,2(下,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_INT_MIN 从 PHP 7 开始可用,因此您需要在此之前为您的环境计算合适的最小值。


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

您可以生成一个 32 位整数,如下所示:

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

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

工作正常

此处添加了错误报告。

目前

还没有消息说PHP是否正在解决这个问题。

同时,您可以在max_rand之间使用mt_rand功能,您应该没问题

示例用法

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