简体   繁体   English

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

[英]Why does mt_rand(1, PHP_INT_MAX) always return an odd number

I've just come across an interesting question from ComputerGuru on Hacker News and no comment seems to give a convincing answer. 我刚刚在ComputerGuru上遇到了一个关于Hacker News的有趣问题 ,没有评论似乎给出了令人信服的答案。

Why does mt_rand(1, PHP_INT_MAX) always return an odd number? 为什么mt_rand(1, PHP_INT_MAX)总是返回一个奇数?

I am not the author of the original question. 我不是原始问题的作者。

http://3v4l.org/dMbat http://3v4l.org/dMbat

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

output: 输出:

8571620074060775425
7401021871338029057
4351677773593444353
1801559362708176897
7848614552286527489
...

PHP_INT_MAX here is 2 63 -1 (64-bit signed int max). PHP_INT_MAX这里是2 63 -1(64位符号int max)。

However, mt_rand() doesn't handle values this large. 但是, mt_rand()不会处理这么大的值。 The Mersenne twister internally generates 32-bit words, and PHP's mt_getrandmax() is only 2 31 -1 (it throws away the highest bit). Mersenne twister在内部生成32位字,PHP的mt_getrandmax()仅为2 31 -1(它抛出最高位)。

To generate a value in your requested min to max range, mt_rand first gets the 0 to 2 31 -1 random number, then scales it using this formula: 要在您请求的minmax范围内生成一个值, mt_rand首先得到0到2 31 -1的随机数,然后使用以下公式对其进行缩放:

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

(See the source of rand.c and php_rand.h .) (参见rand.cphp_rand.h的源代码。)

Basically it blindly scales the internally generated number to fit the overlarge range, without even raising a warning. 基本上它盲目地缩放内部生成的数字以适应超大范围,甚至没有发出警告。 Multiplying to fit the overlarge range generates a lot of zeroes in the low bits, then adding min (which is 1) makes the result odd. 乘以适合超大范围会在低位产生大量零,然后加上min (即1)会使结果变为奇数。

The problem is more dramatic in hexadecimal, where you can see that the low 32 bits of each number are completely non-random: 这个问题在十六进制中更为显着,您可以看到每个数字的低32位完全是非随机的:

for ($i = 0; $i < 10000; $i++) {
    printf("%016x\n", mt_rand(1, PHP_INT_MAX));
}

Output: 输出:

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

There is a note in the manual that tries to warn about this, although it understates the problem: 手册中有一个注释试图警告这一点,虽然它低估了问题:

The distribution of mt_rand() return values is biased towards even numbers on 64-bit builds of PHP when max is beyond 2 32 . max超过2 32时, mt_rand()返回值的分布偏向于64位版本的PHP上的偶数。 This is because if max is greater than the value returned by mt_getrandmax() , the output of the random number generator must be scaled up. 这是因为如果max大于mt_getrandmax()返回的值,则必须按比例放大随机数生成器的输出。

(It says it's biased towards even numbers, but that's only true when min is even.) (它说,它对待偶数偏见,但如果这是唯一真正的min是偶数。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM