在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 

23058430092136939512^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**200sys.maxintn倍 – 我的猜测是散列会超过范围-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; }