python - 为什么 Python 的无穷大哈希有 π 的数字?

标签 python math hash floating-point pi

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_INFdefined as 314159:

#define _PyHASH_INF 314159

在历史上,第一次提到 314159 在这个上下文中的 Python 代码(你可以用 git bisectgit log -S 找到这个314159 -p) 由 Tim Peters 添加2000 年 8 月,现在提交 39dce293cpython 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 when x is an infinity. Fixed that. Added new Py_IS_INFINITY macro to pyport.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 that hash(complex(x, y)) doesn't systematically equal hash(complex(y, x)) anymore.

特别是在这次提交中,他把 Objects/floatobject.c 中的 static long float_hash(PyFloatObject *v) 的代码撕掉了,变成了 return _Py_HashDouble(v->ob_fval);,并在 Objects/object.clong _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 的前几位小数组成。 .

相关的后续提交:

关于python - 为什么 Python 的无穷大哈希有 π 的数字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56227419/

相关文章:

python - 从给定列表创建一个新列表,以便新列表可以标记给定列表中的连续重复

python - wxPython 上的 IPython

algorithm - 如何使用 HashMap 查找一个点属于哪个区域?

ruby - 检查给定字符串是否作为键存在于嵌套哈希中

javascript - nodejs - 如何比较bcrypt的两个哈希密码

python - Pandas 切 : how to convert categorical labels to strings (otherwise cannot export to Excel)?

python - 在服务器上执行python脚本

c++ - 计算数值误差

c++ - 如何在C++中高效实现无穷大和负无穷大的支持算术?

css - 从 matrix3d 获取 css 变换 3D