valor - tipo decimal python




¿Por qué el hash de infinito de Python tiene los dígitos de π? (2)

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:





pi