Python 中无穷大的哈希值匹配 pi :
>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159
这只是巧合还是故意的?
最佳答案
总结:这不是巧合; _PyHASH_INF
is hardcoded as 314159在 Python 的默认 CPython 实现中,并被选为任意值(显然来自 π 的数字)by Tim Peters in 2000 .
hash(float('inf'))
的值是数字类型内置散列函数的系统相关参数之一,is also available作为 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
(同样的结果 with PyPy 也是。)
在代码方面,hash
是一个内置函数。在 Python 浮点对象上调用它会调用指针由 tp_hash
attribute 给出的函数。内置浮点类型 (PyTypeObject PyFloat_Type
),is float_hash
函数,defined作为 return _Py_HashDouble(v->ob_fval)
,它反过来 has
if (Py_IS_INFINITY(v))
return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
其中 _PyHASH_INF
是 defined as 314159:
#define _PyHASH_INF 314159
在历史上,第一次提到 314159
在这个上下文中的 Python 代码(你可以用 git bisect
或 git log -S 找到这个314159 -p
) 由 Tim Peters 添加2000 年 8 月,现在提交 39dce293在 cpython
git 存储库中。
提交信息说:
Fix for http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470. This was a misleading bug -- the true "bug" was that
hash(x)
gave an error return whenx
is an infinity. Fixed that. Added newPy_IS_INFINITY
macro topyport.h
. Rearranged code to reduce growing duplication in hashing of float and complex numbers, pushing Trent's earlier stab at that to a logical conclusion. Fixed exceedingly rare bug where hashing of floats could return -1 even if there wasn't an error (didn't waste time trying to construct a test case, it was simply obvious from the code that it could happen). Improved complex hash so thathash(complex(x, y))
doesn't systematically equalhash(complex(y, x))
anymore.
特别是在这次提交中,他把 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 的前几位小数组成。 .
相关的后续提交:
By Mark Dickinson in Apr 2010 ( also ),使
Decimal
类型的行为相似By Mark Dickinson in Apr 2010 ( also ),将此检查移至顶部并添加测试用例
By Mark Dickinson in May 2010如issue 8188 , 将哈希函数完全重写为 its current implementation ,但保留这种特殊情况,给常量一个名称
_PyHASH_INF
(也删除 271828 这就是为什么在 Python 3hash(float('-inf'))
返回-314159
而不是 Python 2 中的-271828
)By Raymond Hettinger in Jan 2011 ,在
sys.hash_info
的 Python 3.2 的“新增功能”中添加一个显式示例,显示上述值。 (见 here。)By Stefan Krah in Mar 2012修改 Decimal 模块但保留此哈希。
By Christian Heimes in Nov 2013 ,将
_PyHASH_INF
的定义从Include/pyport.h
移到了它现在所在的Include/pyhash.h
。
关于python - 为什么 Python 的无穷大哈希有 π 的数字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56227419/