在Python中hash(n)== n是什么时候?
我一直在玩Python的散列函数 。 对于小整数,它总是出现hash(n) == n
。 然而,这并没有扩大到大数目:
>>> hash(2**100) == 2**100 False
我并不感到惊讶,我知道哈希值取值范围有限。 这个范围是什么?
我尝试使用二进制searchfind最小数字hash(n) != n
>>> import codejamhelpers # pip install codejamhelpers >>> help(codejamhelpers.binary_search) Help on function binary_search in module codejamhelpers.binary_search: binary_search(f, t) Given an increasing function :math:`f`, find the greatest non-negative integer :math:`n` such that :math:`f(n) \le t`. If :math:`f(n) > t` for all :math:`n \ge 0`, return None. >>> f = lambda n: int(hash(n) != n) >>> n = codejamhelpers.binary_search(f, 0) >>> hash(n) 2305843009213693950 >>> hash(n+1) 0
2305843009213693951有什么特别之处? 我注意到它小于sys.maxsize == 9223372036854775807
编辑:我使用Python 3.我在Python 2上运行相同的二进制search,得到了不同的结果2147483648,我注意到是sys.maxint+1
我也用[hash(random.random()) for i in range(10**6)]
的哈希函数[hash(random.random()) for i in range(10**6)]
来估计哈希函数的范围。 最大值始终低于n以上。 比较分钟,看起来Python 3的散列值总是正值,而Python 2的散列值可以是负值。
基于pyhash.c
文件中的python文档:
对于数字types来说,数字x的散列是基于x的模数减less的模数
P = 2**_PyHASH_BITS - 1
。 当x和y在数值上相等时,即使x和y有不同的types,它的devise也使得hash(x) == hash(y)
。
所以对于一个64/32位的机器来说,这个减less量是2 _PyHASH_BITS – 1,但是_PyHASH_BITS
是_PyHASH_BITS
?
你可以在pyhash.h
头文件中find它,对于一个64位的机器已经定义为61(你可以在pyconfig.h
文件中阅读更多的解释)。
#if SIZEOF_VOID_P >= 8 # define _PyHASH_BITS 61 #else # define _PyHASH_BITS 31 #endif
所以首先,基于你的平台,例如在我的64位Linux平台上,减less量是2 61 -1,即2305843009213693951
:
>>> 2**61 - 1 2305843009213693951
也可以使用math.frexp
为了获得math.frexp
的尾数和指数,对于64位机器来说,它显示max int是2 63 :
>>> import math >>> math.frexp(sys.maxint) (0.5, 64)
你可以通过一个简单的testing来看到不同之处:
>>> hash(2**62) == 2**62 True >>> hash(2**63) == 2**63 False
阅读有关Python哈希algorithm的完整文档https://github.com/python/cpython/blob/master/Python/pyhash.c#L34
正如在注释中提到的,你可以使用sys.hash_info
(在python 3.X中),它会给你一个用于计算哈希值的参数的结构序列。
>>> sys.hash_info sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003, algorithm='siphash24', hash_bits=64, seed_bits=128, cutoff=0) >>>
除了前面介绍的模数之外,还可以得到如下的inf
值:
>>> hash(float('inf')) 314159 >>> sys.hash_info.inf 314159
2305843009213693951
是2^61 - 1
。 这是最大的梅森素数,适合64位。
如果你只是通过取一个数值来做一个散列,那么一个大的梅森素数是一个不错的select – 它很容易计算,并确保可能性的均匀分布。 (虽然我个人从来不会这样做哈希)
计算浮点数的模数特别方便。 他们有一个指数分量乘以2^x
。 由于2^61 = 1 mod 2^61-1
,你只需要考虑(exponent) mod 61
。
请参阅: https : //en.wikipedia.org/wiki/Mersenne_prime
Hash函数返回的是纯int ,这意味着返回的值大于-sys.maxint
且小于sys.maxint
,这意味着如果您传递sys.maxint + x
,结果将是-sys.maxint + (x - 2)
。
hash(sys.maxint + 1) == sys.maxint + 1 # False hash(sys.maxint + 1) == - sys.maxint -1 # True hash(sys.maxint + sys.maxint) == -sys.maxint + sys.maxint - 2 # True
同时2**200
比sys.maxint
大n
倍 – 我的猜测是散列会超过范围-sys.maxint..+sys.maxint
n次直到停止在该范围内的纯整数,如代码片段以上..
所以一般来说,对于任何n <= sys.maxint :
hash(sys.maxint*n) == -sys.maxint*(n%2) + 2*(n%2)*sys.maxint - n/2 - (n + 1)%2 ## True
注意: python 2是这样的。
在这里可以findcpython中inttypes的实现。
它只是返回值,除了-1
,比它返回-2
:
static long int_hash(PyIntObject *v) { /* XXX If this is changed, you also need to change the way Python's long, float and complex types are hashed. */ long x = v -> ob_ival; if (x == -1) x = -2; return x; }