在1到sys.maxsize范围内的随机数总是1 mod 2 ^ 10
我试图通过使用频率testing,运行testing和卡方检验来findPython(2.7.10)中可用的PRNG的统计属性。
为了进行频率testing,我需要将生成的随机数转换为二进制表示,然后计算1
和0
的分布。 我正在试验在python控制台上的随机数字的二进制表示,并观察这种奇怪的行为:
>>> for n in random.sample(xrange(1, sys.maxsize), 50): ... print '{0:b}'.format(n) ... 101101110011011001110011110110101101101101111111101000000000001 110000101001001011101001110111111110011000101011100010000000001 110111101101110011100010001010000101011111110010001110000000001 100001111010011000101001000001000011001111100000001010000000001 1111000010010011111100111110110100100011110111010000000000001 111000001011101011101110100001001001000011011001110110000000001 1000100111011000111000101010000101010100110111000100000000001 11101001000001101111110101111011001000100011011011010000000001 110011010111101101011000110011011001110001111000001010000000001 110110110110111100011111110111011111101000011001100000000001 100010010000011101011100110101011110111100001100100000000000001 10111100011010011010001000101011001110010010000010010000000001 101011100110110001010110000101100000111111011101011000000000001 1111110010110010000111111000010001101011011010101110000000001 11100010101101110110101000101101011011111101101000010000000001 10011110110110010110011010000110010010111001111001010000000001 110110011100111010100111100100000100011101100001100000000000001 100110011001101011110011010101111101100010000111001010000000001 111000101101100111110010110110100110111001000101000000000000001 111111101000010111001011111100111100011101001011010000000001 11110001111100000111010010011111010101101110111001010000000001 100001100101101100010101111100111101111001101010101010000000001 11101010110011000001101110000000001111010001110111000000000001 100111000110111010001110110101001011100101111101010000000001 100001101100000011101101010101111111011010111110111110000000001 100010010011110110111111111000010001101100111001001100000000001 110011111110010011000110101010101001001010000100011010000000001 1111011010100001001101101000011100001011001110010100000000001 110110011101100101001100111010101111001011111101100000000000001 1010001110100101001001011111000111011100001100000110000000001 1000101110010011011000001011010110001000110100100100000000001 11111110011001011100111110110111000001000100100010000000000001 101111101010000101010111111111000001100101111001011110000000001 10010010111111111100000001010010101100111001100000000000001 111110000001110010001110111101110101010110001110000000000000001 100000101101000110101010010000101101000011111010001110000000001 101001011101100011001000011010010000000111110111100010000000001 10110101010000111010110111001111011000001111001100110000000001 10110111100100100011100101001100000000101110100100010000000001 10010111110001011101001110000111011010110100110111110000000001 111011110010110111011011101011001100001000111001010100000000001 101001010001010100010010010001100111101110101111000110000000001 101011111010000101010101000110001101001001011110000000000001 1010001010111101101010111110110110000001111101101110000000001 10111111111010001000110000101101010101011010101100000000001 101011101010110000001111010100100110000011111100100100000000001 111100001101111010100111010001010010000010110110010110000000001 100111111000100110100001110101000010111111010010010000000000001 100111100001011100011000000000101100111111000111100110000000001 110110100000110111011101110101101000101110111111010110000000001 >>>
正如你所看到的,所有的数字都以0000000001
结尾,即所有的数字都是1 mod 2^10
。 这是为什么?
此外,当范围是1 to sys.maxsize
时,会出现此行为。 如果范围被指定为1 to 2^40
,则没有被观察到。 我想知道这种行为的原因以及代码中是否有任何错误。
实现我正在使用的PRNG的随机库的文档在这里 。
让我知道,如果我应该提供更多的信息。
@roeland暗示原因:在Python 2中, sample()
int(random.random() * n)
重复使用int(random.random() * n)
。 查看源代码(在你的Python的Lib/random.py
)以获得完整的细节。 总之, random.random()
返回不超过53个重要的(非零)前导位; 然后int()
用零填充其余的低位(你显然是在一台机器,其中sys.maxsize == 2**63 - 1
); 然后用一个偶数整数索引你的基数( xrange(1, sys.maxsize)
),低位0比特的“很多”总是返回一个奇数整数和相同数量的低位0比特(除了最后一个)。
在Python 3中,没有发生任何事情 – 在Python 3中random
使用更强大的algorithm,只有在必要时才会回落到random.random()
。 例如,在Python 3.4.3下:
>>> hex(random.randrange(10**70)) '0x91fc11ed768be3a454bd66f593c218d8bbfa3b99f6285291e1d9f964a9' >>> hex(random.randrange(10**70)) '0x7b07ff02b6676801e33094fca2fcca7f6e235481c479c521643b1acaf4'
编辑
下面是一个更直接相关的例子,在3.4.3的64位框中:
>>> import random, sys >>> sys.maxsize == 2**63 - 1 True >>> for i in random.sample(range(1, sys.maxsize), 6): ... print(bin(i)) 0b10001100101001001111110110011111000100110100111001100000010110 0b100111100110110100111101001100001100110001110010000101101000101 0b1100000001110000110100111101101010110001100110101111011100111 0b111110100001111100101001001001101101100100011001001010100001110 0b1100110100000011100010000011010010100100110111001111100110100 0b10011010000110101010101110001000101110111100100001111101110111
在这种情况下,Python 3根本不调用random.random()
,而是从底层的Mersenne Twister(32位无符号整数是来自MT的这个实现的“自然”输出)迭代地获取大块32位,粘贴他们一起build立一个合适的指数。 所以,在Python 3中,平台浮动与它无关; 在Python 2中,浮动行为的怪癖与它有关。
这取决于很多事情,比如RNG是如何实现的,它使用多less位状态以及如何实现sample
函数。
以下是文档所说的内容:
几乎所有的模块函数都依赖于random()函数,这个函数在半开放范围[0.0,1.0)中生成一个统一的随机浮点数。 Python使用Mersenne Twister作为核心生成器。 它生成53位精度浮点数,周期为2 ** 19937-1。
所以如果sample
确实使用了random()
,那么在结果中应该只有53位有意义的位。
这看起来像在random.sample中的舍入错误。
在乘以范围扩展( maxsize -1
)之后,最低4位总是零,然后当添加范围( 1
)的开始时,它们始终为1
如果乘法工作正常,假设扩展不是二的幂,并且随机数只有53个不同的位,我希望在最右边的位也会看到不同的值。