valor usando tipo suma siguiente round_half_up programa places para numero infinita funcion float estimar digitos desarrolle como comando coloca cast and python math hash floating-point pi

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 cuando x es un infinito. Arreglado eso. Se agregó una nueva macro pyport.h a pyport.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 el hash(complex(x, y)) ya no es igual a hash(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:


_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.