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)); ?>
似乎总是产生
00000000
或fffffff2
到ffffffff
范围内的数字。这:<?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);