usando - ¿Por qué el hash de infinito de Python tiene los dígitos de π?
python round_half_up (3)
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 usen como valores de hash hace que sea muy poco probable que sea una coincidencia.
El hash del 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 por defecto de CPython de Python, y fue seleccionado como un valor arbitrario (obviamente de los dígitos de π)
por Tim Peters en 2000
.
El valor de
hash(float(''inf''))
es uno de los parámetros dependientes del sistema de la función hash incorporada 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 incorporada.
Al llamarlo a un objeto flotante de Python, se invoca la función cuyo puntero está dado por el
atributo
tp_hash
del tipo flotante
PyTypeObject PyFloat_Type
(
PyTypeObject PyFloat_Type
), que
is
la función
float_hash
,
defined
como el
return _Py_HashDouble(v->ob_fval)
, que a su vez
has
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 la 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 se confirma
github.com/python/cpython/commit/…
en
cpython
repositorio git de
cpython
.
El mensaje de confirmación dice:
Arreglo para http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470 . Este fue un error engañoso: el verdadero "error" fue que el
hash(x)
dio una respuesta de error cuandox
es un infinito. Arreglado eso. Se agregó una nueva macropyport.h
apyport.h
. Se reorganizó el código para reducir la creciente duplicación en el hashing de números flotantes y complejos, lo que lleva a Trent a una conclusión lógica. Se corrigió un error extremadamente raro en el que el hashing de flotadores podía devolver -1 incluso si no había un error (no perdía el tiempo tratando de construir un caso de prueba, simplemente era obvio por el código que podía ocurrir). Hash complejo mejorado, de modo que elhash(complex(x, y))
ya no es igual ahash(complex(y, x))
.
En particular, en esta confirmación, arrancó el código del
static long float_hash(PyFloatObject *v)
en
Objects/floatobject.c
y lo hizo simplemente
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;
Así que 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 .
Relacionado más tarde se compromete:
-
Por Mark Dickinson en abril de 2010 ( also ), haciendo que el tipo
Decimal
comporte de manera similar -
Por Mark Dickinson en abril de 2010 ( also ), moviendo este control a la parte superior y agregando casos de prueba
-
Por Mark Dickinson en mayo de 2010 como bugs.python.org/issue8188 , reescribiendo completamente la función hash a su implementación actual , pero conservando este caso especial, asignando a la constante un nombre
_PyHASH_INF
(también eliminando el 271828, que es la razón por la cual en elhash(float(''-inf''))
Python 3hash(float(''-inf''))
devuelve-314159
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
muestra el valor anterior. (Ver here .) -
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
deInclude/pyport.h
aInclude/pyhash.h
donde ahora vive.
_PyHASH_INF
se
define como una constante
igual a
314159
.
No puedo encontrar ninguna discusión sobre esto, o comentarios que den 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.