我刚刚从HackG News上的ComputerGuru遇到interesting question,似乎没有任何评论可以给出令人信服的答案。
为什么mt_rand(1, PHP_INT_MAX)
总是返回一个奇数?
我不是原问题的作者。
for ($i=0;$i<10000;$i++)
{
echo mt_rand(1, PHP_INT_MAX)."\n";
}
输出:
8571620074060775425
7401021871338029057
4351677773593444353
1801559362708176897
7848614552286527489
...
答案 0 :(得分:5)
PHP_INT_MAX
这里是2 63 -1(64位符号int max)。
但是,mt_rand()
并没有处理这么大的值。 Mersenne twister在内部生成32位字,PHP mt_getrandmax()
只有2 31 -1(它抛出最高位)。
要在您请求的min
到max
范围内生成值,mt_rand
首先获得0到2 31 -1的随机数,然后进行缩放使用这个公式:
x = ((x / (mt_getrandmax() + 1)) * (max - min + 1)) + min;
(请参阅rand.c和php_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试图警告这一点,虽然它低估了这个问题:
当
mt_rand()
超过2 32 时,max
返回值的分布偏向于64位版本的PHP上的偶数。这是因为如果max
大于mt_getrandmax()
返回的值,则必须按比例放大随机数生成器的输出。
(它说它偏向偶数,但只有当min
是偶数时才会这样。)