Resumen: no es una coincidencia; _PyHASH_INF
está codificado como 314159 en la implementación predeterminada de Python para CPython, 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 incorporada para los 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 en un objeto flotante de Python se invoca la función cuyo puntero viene dado por el tp_hash
atributo del tipo flotante incorporado ( PyTypeObject PyFloat_Type
), que es la float_hash
función, definida como return _Py_HashDouble(v->ob_fval)
, que a su vez tiene
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
este contexto en el código 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 39dce293 en el cpython
repositorio git.
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 el que hash(x)
devolvió el error cuando x
es infinito. Arreglado eso. Se agregó una nueva Py_IS_INFINITY
macro a
pyport.h
. Código reordenado para reducir la creciente duplicación en el hash de números flotantes y complejos, empujando la puñalada anterior de Trent a una conclusión lógica. Se corrigió un error extremadamente raro en el que el hash de los flotadores podía devolver -1 incluso si no había un error (no perdía el tiempo tratando de construir un caso de prueba, era simplemente obvio por el código que podía suceder). Hash complejo mejorado para que
hash(complex(x, y))
ya no sea igual sistemáticamente hash(complex(y, x))
.
En particular, en esta confirmación, eliminó el código de static long float_hash(PyFloatObject *v)
in Objects/floatobject.c
y lo hizo justo return _Py_HashDouble(v->ob_fval);
, y en la definición de long _Py_HashDouble(double v)
in 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;
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 .
Compromisos posteriores relacionados:
hash(float('nan'))
ser0
.