我刚刚在Hacker News上碰到过ComputerGuru的interesting question,似乎没有任何评论可以给出令人信服的答案。

为什么mt_rand(1, PHP_INT_MAX)总是返回奇数?

我不是原始问题的作者。

http://3v4l.org/dMbat

for ($i=0;$i<10000;$i++)
{
    echo mt_rand(1, PHP_INT_MAX)."\n";
}

输出:
8571620074060775425
7401021871338029057
4351677773593444353
1801559362708176897
7848614552286527489
...

最佳答案

此处的PHP_INT_MAX是263-1(最大64位有符号int)。

但是,mt_rand()不能处理这么大的值。 Mersenne扭曲程序在内部生成32位字,而PHP的mt_getrandmax()仅231-1(它丢弃了最高位)。

为了在您请求的minmax范围内生成一个值,mt_rand首先获取0到231-1的随机数,然后使用以下公式对其进行缩放:

x = ((x / (mt_getrandmax() + 1)) * (max - min + 1)) + min;

(请参阅rand.cphp_rand.h的来源。)

基本上,它会盲目地缩放内部生成的数字以适应较大的范围,甚至不会发出警告。乘以适合较大的范围会在低位产生很多零,然后添加min(为1)会使结果奇怪。

这个问题在十六进制中更为严重,您可以看到每个数字的低32位完全是非随机的:
for ($i = 0; $i < 10000; $i++) {
    printf("%016x\n", mt_rand(1, PHP_INT_MAX));
}

输出:
41e0449b00000001
53d33d7c00000001
6ec8855700000001
234140e000000001
13a4581900000001
77547beb00000001
35a0660a00000001
0d0cd44200000001
...

有一个注释in the manual试图警告此问题,尽管它低估了该问题:



(它说它偏向偶数,但是只有当min是偶数时,这才是正确的。)

关于php - 为什么mt_rand(1,PHP_INT_MAX)总是返回奇数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31612082/

10-10 10:35