为什么python的无穷散列中有π的数字?

Python中的无穷散列包含匹配π的数字:

>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159

这是巧合还是有意为之?

29187 次浏览

_PyHASH_INF定义为常数等于314159

我找不到任何关于这个问题的讨论,或者给出理由的评论。我认为这或多或少是随意选择的。我想,只要它们对其他哈希值不使用相同的有意义的值,就不应该有关系。

总结:这不是巧合;_PyHASH_INF被硬编码为314159在Python的默认CPython实现中,并且被选为任意值(显然来自π的数字)蒂姆·彼得斯于2000年出版


hash(float('inf'))的值是用于数值类型的内置哈希函数的系统相关参数之一,而也是可用的在Python 3中是sys.hash_info.inf:

>>> import sys
>>> 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)
>>> sys.hash_info.inf
314159

(同样的结果与PyPy。)


就代码而言,hash是一个内置函数。在Python浮动对象上调用它调用的函数,其指针由内置浮点类型(PyTypeObject PyFloat_Type)的tp_hash属性给出,该函数float_hash函数,定义return _Py_HashDouble(v->ob_fval),该函数依次为

    if (Py_IS_INFINITY(v))
return v > 0 ? _PyHASH_INF : -_PyHASH_INF;

其中_PyHASH_INF定义为 314159:

#define _PyHASH_INF 314159

就历史而言,在Python代码中第一次提到314159(你可以在git bisectgit log -S 314159 -p中找到它)是在2000年8月由Tim Peters添加的,现在在cpython git存储库中提交39 dce293

提交消息说:

修复了http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470。 这是一个误导性的错误——真正的“错误”是hash(x)给出了一个错误 当x为无穷大时返回。固定。添加了新的Py_IS_INFINITYpyport.h。重新安排代码,以减少浮动和散列中不断增加的重复 复数,将特伦特之前的尝试推向了一个逻辑结论。 修正了非常罕见的错误,浮点数哈希即使存在也可能返回-1 不是一个错误(没有浪费时间试图构造一个测试用例,这只是简单的 显然,从代码可以发生)。改进的复杂哈希 hash(complex(x, y))不再系统地等于hash(complex(y, x))

特别地,在此提交中,他将Objects/floatobject.c中的static long float_hash(PyFloatObject *v)代码删除,并将其改为return _Py_HashDouble(v->ob_fval);,并且在Objects/object.c中的long _Py_HashDouble(double v)定义中,他添加了以下行:

        if (Py_IS_INFINITY(intpart))
/* can't convert to long int -- arbitrary */
v = v < 0 ? -271828.0 : 314159.0;

如前所述,这是一个随意的选择。注意,271828是由e的前几个十进制数字组成的。

相关后续提交:

的确,

sys.hash_info.inf
< p >返回314159。该值不是生成的,而是内置于源代码中。 事实上,< / p >
hash(float('-inf'))

在python 2 (现在是-314159)中返回-271828,或近似-e。

事实上,有史以来最著名的两个无理数被用作哈希值,这不太可能是巧合。