Python 中的无穷散列具有与 pi 匹配的数字:
>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159
这只是巧合还是故意的?
原文由 wim 发布,翻译遵循 CC BY-SA 4.0 许可协议
Python 中的无穷散列具有与 pi 匹配的数字:
>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159
这只是巧合还是故意的?
原文由 wim 发布,翻译遵循 CC BY-SA 4.0 许可协议
总结:这不是巧合; _PyHASH_INF
在 Python 的默认 CPython 实现中被硬编码为 314159 ,并 在 2000 年被 Tim Peters 选择为任意值(显然来自 π 的数字)。
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 bisect
或 git log -S 314159 -p
找到它,由 Tim– Peters 添加) 2000 年 8 月,在 cpython
git 存储库中提交 39dce293 。
提交消息说:
修复了 http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470 。这是一个误导性错误——真正的“错误”是
hash(x)
在x
为无穷大时返回错误。固定那个。添加了新的Py_IS_INFINITY
宏pyport.h
。重新排列代码以减少浮点数和复数散列中不断增加的重复,将 Trent 早先的尝试推向了合乎逻辑的结论。修复了极其罕见的错误,即使没有错误,浮点数的散列也可能返回 -1(没有浪费时间尝试构建测试用例,从代码中可以明显看出它 可能 发生)。改进了复杂散列,以便hash(complex(x, y))
不再系统地等于hash(complex(y, x))
。
In particular, in this commit he ripped out the code of static long float_hash(PyFloatObject *v)
in Objects/floatobject.c
and made it just return _Py_HashDouble(v->ob_fval);
, and in the definition of long _Py_HashDouble(double v)
在 Objects/object.c
他添加了以下行:
if (Py_IS_INFINITY(intpart))
/* can't convert to long int -- arbitrary */
v = v < 0 ? -271828.0 : 314159.0;
如前所述,这是一个任意的选择。请注意,271828 是由 e 的前几位小数组成的。
相关的后续提交:
Mark Dickinson 于 2010 年 4 月( 也),使 Decimal
类型的行为类似
Mark Dickinson 于 2010 年 4 月( 也),将此检查移至顶部并添加测试用例
马克·迪金森 (Mark Dickinson) 于 2010 年 5 月 发布的第 8188 期,将哈希函数完全重写 为其当前实现,但保留了这种特殊情况,为常量命名 _PyHASH_INF
(同时删除了 271828,这就是为什么在 Python 3 中 hash(float('-inf'))
返回 -314159
而不是 -271828
就像在 Python 2 中那样)
由 Raymond Hettinger 于 2011 年 1 月 在 Python 3.2 的“新增功能”中添加了一个明确的示例 sys.hash_info
显示了上述值。 (见 此处。)
由 Stefan Krah 于 2012 年 3 月 修改 Decimal 模块但保留此哈希。
Christian Heimes 在 2013 年 11 月 将 _PyHASH_INF
的定义从 Include/pyport.h
移动到 Include/pyhash.h
它现在所在的位置。
原文由 ShreevatsaR 发布,翻译遵循 CC BY-SA 4.0 许可协议
2 回答5.1k 阅读✓ 已解决
2 回答1.1k 阅读✓ 已解决
4 回答1k 阅读✓ 已解决
3 回答1.1k 阅读✓ 已解决
3 回答1.2k 阅读✓ 已解决
1 回答1.7k 阅读✓ 已解决
1 回答1.2k 阅读✓ 已解决
_PyHASH_INF
被 定义为 等于314159
的常量。我找不到关于此的任何讨论,也找不到给出理由的评论。我认为它或多或少是任意选择的。我想只要他们不对其他哈希值使用相同的有意义的值,就没有关系。