El hash de infinito en Python tiene dígitos que coinciden con pi :
>>> inf = float('inf') >>> hash(inf) 314159 >>> int(math.pi*1e5) 314159¿Es solo una coincidencia o es intencional?
Resumen: No es una coincidencia; _PyHASH_INF está codificado como 314159 en la implementación predeterminada de CPython de Python, y Tim Peters lo eligió como un valor arbitrario (obviamente de los dígitos de π) en 2000 .
El valor de hash(float('inf')) es uno de los parámetros dependientes del sistema de la función hash integrada para tipos numéricos y también está disponible como sys.hash_info.inf en 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(Los mismos resultados con PyPy también).
En términos de código, hash es una función integrada. Llamarlo en un objeto flotante de Python invoca la función cuyo puntero está dado por el atributo tp_hash del tipo flotante incorporado ( PyTypeObject PyFloat_Type ), que es la función float_hash , definida como return _Py_HashDouble(v->ob_fval) , que a su vez posee
if (Py_IS_INFINITY(v)) return v > 0 ? _PyHASH_INF : -_PyHASH_INF; donde _PyHASH_INF se define como 314159:
#define _PyHASH_INF 314159 En términos de historia, la primera mención de 314159 en este contexto en el código de Python (puede encontrar esto con git bisect o git log -S 314159 -p ) fue agregada por Tim Peters en agosto de 2000, en lo que ahora es commit 39dce293 en el repositorio cpython git.
El mensaje de confirmación dice:
Solución para http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470 . Este fue un error engañoso: el verdadero "error" fue que
hash(x)devolvió un error cuandoxes un infinito. Arreglado eso. Se agregó una nueva macroPy_IS_INFINITYapyport.h. Se reorganizó el código para reducir la creciente duplicación en el hash de números flotantes y complejos, lo que llevó la puñalada anterior de Trent a una conclusión lógica. Se corrigió un error extremadamente raro en el que el hashing de flotantes podía devolver -1 incluso si no había un error (no perdió el tiempo tratando de construir un caso de prueba, era simplemente obvio por el código que podría suceder). Hash complejo mejorado para quehash(complex(x, y))ya no sea sistemáticamente igual ahash(complex(y, x)).
En particular, en esta confirmación extrajo el código de static long float_hash(PyFloatObject *v) en Objects/floatobject.c y lo hizo return _Py_HashDouble(v->ob_fval); , y en la definición de long _Py_HashDouble(double v) en Objects/object.c agregó las líneas:
if (Py_IS_INFINITY(intpart)) /* can't convert to long int -- arbitrary */ v = v < 0 ? -271828.0 : 314159.0;Entonces, como se mencionó, fue una elección arbitraria. Tenga en cuenta que 271828 se forma a partir de los primeros dígitos decimales de e .
Confirmaciones posteriores relacionadas:
Por Mark Dickinson en abril de 2010 ( también ), haciendo que el tipo Decimal se comporte de manera similar
Por Mark Dickinson en abril de 2010 ( también ), moviendo este cheque al principio y agregando casos de prueba
Por Mark Dickinson en mayo de 2010 como edición 8188 , reescribiendo completamente la función hash asu implementación actual , pero conservando este caso especial, dando a la constante un nombre _PyHASH_INF (también eliminando el 271828, razón por la cual en Python 3 hash(float('-inf')) devuelve -314159 en lugar de -271828 como lo hace en Python 2)
Por Raymond Hettinger en enero de 2011 , agregando un ejemplo explícito en "Novedades" para Python 3.2 de sys.hash_info que muestra el valor anterior. (Ver aquí .)
Por Stefan Krah en marzo de 2012 modificando el módulo Decimal pero manteniendo este hash.
Por Christian Heimes en noviembre de 2013 , movió la definición de _PyHASH_INF de Include/pyport.h a Include/pyhash.h donde ahora reside.
_PyHASH_INF se define como una constante igual a 314159 .
No puedo encontrar ninguna discusión sobre esto, o comentarios dando una razón. Creo que fue elegido más o menos arbitrariamente. Me imagino que mientras no usen el mismo valor significativo para otros hashes, no debería importar.
En efecto,
sys.hash_info.inf devuelve 314159 . El valor no se genera, está integrado en el código fuente. De hecho,
hash(float('-inf')) devuelve -271828 , o aproximadamente -e, en python 2 ( ahora es -314159 ).
El hecho de que los dos números irracionales más famosos de todos los tiempos se utilicen como valores hash hace que sea muy poco probable que sea una coincidencia.