The hash of infinity in Python has digits matching pi:
>>> inf = float("inf") >>> hash(inf) 314159 >>> int(math.pi*1e5) 314159
Is that just a coincidence or is it intentional?
Summary: It"s not a coincidence;
_PyHASH_INF is hardcoded as 314159 in the default CPython implementation of Python, and was picked as an arbitrary value (obviously from the digits of œÄ) by Tim Peters in 2000.
The value of
hash(float("inf")) is one of the system-dependent parameters of the built-in hash function for numeric types, and is also available as
sys.hash_info.inf in 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
(Same results with PyPy too.)
In terms of code,
hash is a built-in function. Calling it on a Python float object invokes the function whose pointer is given by the
tp_hash attribute of the built-in float type (
PyTypeObject PyFloat_Type), which is the
float_hash function, defined as
return _Py_HashDouble(v->ob_fval), which in turn has
if (Py_IS_INFINITY(v)) return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
_PyHASH_INF is defined as 314159:
#define _PyHASH_INF 314159
In terms of history, the first mention of
314159 in this context in the Python code (you can find this with
git bisect or
git log -S 314159 -p) was added by Tim Peters in August 2000, in what is now commit 39dce293 in the
cpython git repository.
The commit message says:
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
xis an infinity. Fixed that. Added new
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
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) in
Objects/object.c he added the lines:
if (Py_IS_INFINITY(intpart)) /* can"t convert to long int -- arbitrary */ v = v < 0 ? -271828.0 : 314159.0;
So as mentioned, it was an arbitrary choice. Note that 271828 is formed from the first few decimal digits of e.
Related later commits:
By Mark Dickinson in May 2010 as issue 8188, completely rewriting the hash function to its current implementation, but retaining this special case, giving the constant a name
_PyHASH_INF (also removing the 271828 which is why in Python 3
-314159 rather than
-271828 as it does in Python 2)
By Stefan Krah in Mar 2012 modifying the Decimal module but keeping this hash.
By Christian Heimes in Nov 2013, moved the definition of
Include/pyhash.h where it now lives.
It would be easy for me to develop native apps using Java, C++ or Objective-C and I am also able to learn Kotlin, Dart or Swift, but things are much easier when you just use Python. I have done a Djan...
This encyclopedia will be an indispensable resource for our time as it reflects the fact that we are currently living in an expanding data-driven world. ...
Vincent Bumgarner has been designing software for nearly 20 years, working in many languages on nearly as many platforms. He started using Splunk in 2007 and has enjoyed watching the product evolve ov...
Grokking Deep Learning teaches you to build deep learning neural networks from scratch! In his immersive style, deep learning expert Andrew Trask shows you the hidden science so you can uncover every ...