Python中无穷大的哈希值具有与pi匹配的数字:
>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159
这仅仅是巧合还是故意的?
sys.hash_info
。复活节彩蛋?
-314159
。我忘记了这一点。
Python中无穷大的哈希值具有与pi匹配的数字:
>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159
这仅仅是巧合还是故意的?
sys.hash_info
。复活节彩蛋?
-314159
。我忘记了这一点。
Answers:
hash(314159)
也是314159
。也可以尝试在Python 3中hash(2305843009214008110) == 314159
(此输入为314159 + sys.hash_info.modulus
)等
简介:这不是巧合;在Python的默认CPython实现中_PyHASH_INF
被硬编码为314159,并在2000年被Tim Peters选为任意值(显然是从π的数字)。
的值hash(float('inf'))
是数值类型内置散列函数的系统相关的参数中的一个,并且也可以作为sys.hash_info.inf
在Python 3:
>>> 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 float对象上调用它会调用函数,该函数的指针由内置float类型()的tp_hash
属性给定,该类型是定义为的函数,PyTypeObject PyFloat_Type
而该函数又具有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
从历史的角度来看,Tim Peters在2000年8月添加了314159
此上下文中Python代码中的第一个提及(您可以使用git bisect
或找到git log -S 314159 -p
),现在在git存储库中提交了39dce293。cpython
提交消息说:
修复了http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470的问题。这是一个令人误解的错误-真正的“错误”是
hash(x)
当x
infinity为无限时返回错误。修复了。向添加了新的Py_IS_INFINITY
宏pyport.h
。重新排列了代码,以减少浮点数和复数的散列中越来越多的重复,从而将Trent之前的做法推到了合理的结论。修复了一个极其罕见的错误,即即使没有错误,浮点数的哈希也可能返回-1(并没有浪费时间来构造一个测试用例,从代码中可以明显看出它可能发生)。改进了复杂的哈希,因此hash(complex(x, y))
不再系统地相等hash(complex(y, x))
。
特别是,在此提交中,他撕掉了static long float_hash(PyFloatObject *v)
in 的代码Objects/floatobject.c
并使它成为just return _Py_HashDouble(v->ob_fval);
,并在in的定义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模块,但保留了该哈希值。
由基督教海梅斯在2013年11月,移动的定义_PyHASH_INF
来自Include/pyport.h
于Include/pyhash.h
它现在的生活。
hash(42.0)
是一样的hash(42)
,也一样hash(Decimal(42))
和hash(complex(42))
和hash(Fraction(42, 1))
。该解决方案(由Mark Dickinson提出)是一种优雅的IMO:定义适用于任何有理数的数学函数,并利用浮点数也为有理数这一事实。
hash(n) = n % M
其中M =(2 ^ 61-1 )。对于有理数n,这是广义的,hash(p/q) = (p/q) mod M
除法以M为模(换句话说:)hash(p/q) = (p * inverse(q, M)) % M
。我们想要这样做的原因是:如果放入dict中,然后d
放入(例如42.0 == 42),但是与不一致,那么我们就会遇到问题。大多数看似复杂的代码都来自浮点格式本身的性质,以便正确恢复小数部分,并且需要特殊情况下的inf和NaN值。d[x] = foo
x==y
d[y]
d[x]
确实,
sys.hash_info.inf
返回314159
。该值不会生成,而是内置在源代码中。事实上,
hash(float('-inf'))
-271828
在python 2中返回或大约为-e(现在为-314159)。
将所有时间中两个最著名的无理数用作哈希值的事实使得它不太可能是巧合。
hash(float('nan'))
存在0
。