python - точность - символ бесконечности в питоне




Почему хэш бесконечности Python имеет цифры π? (2)

В самом деле,

sys.hash_info.inf

возвращает 314159 . Значение не генерируется, оно встроено в исходный код. По факту,

hash(float('-inf'))

возвращает -271828 , или примерно -e, в Python 2 (сейчас это -314159 ).

Тот факт, что два самых известных иррациональных числа всех времен используются в качестве значений хеш-функции, делает маловероятным совпадение.

Хэш бесконечности в Python имеет цифры, соответствующие pi :

>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159

Это просто совпадение или это намеренно?


Резюме: это не совпадение; _PyHASH_INF жестко закодирован как 314159 в реализации Python по умолчанию на CPython и был выбран Тимом Петерсом в 2000 году как произвольное значение (очевидно, из цифр π).

Значение hash(float('inf')) является одним из системных параметров встроенной хэш-функции для числовых типов, а также доступно как sys.hash_info.inf в 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

(Те же результаты с PyPy тоже.)

С точки зрения кода, hash является встроенной функцией. Вызов его для объекта с плавающей точкой Python вызывает функцию, указатель которой tp_hash атрибутом tp_hash встроенного типа с плавающей точкой ( PyTypeObject PyFloat_Type ), который is функцией float_hash , defined как return _Py_HashDouble(v->ob_fval) , которая в свою очередь has

    if (Py_IS_INFINITY(v))
        return v > 0 ? _PyHASH_INF : -_PyHASH_INF;

где _PyHASH_INF определяется как 314159:

#define _PyHASH_INF 314159

С точки зрения истории, первое упоминание о 314159 в этом контексте в коде Python (вы можете найти это с помощью git bisect или git log -S 314159 -p ) было добавлено Тимом Питерсом в августе 2000 года, в том, что сейчас является коммитом github.com/python/cpython/commit/… в репозиторий cpython git.

Сообщение коммита говорит:

Исправление для http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470 . Это ошибочная ошибка - настоящая «ошибка» заключалась в том, что hash(x) возвращал ошибку, когда x - бесконечность. Исправлено Добавлен новый макрос pyport.h в pyport.h . Переставил код, чтобы уменьшить растущее дублирование в хешировании чисел с плавающей запятой и комплексных чисел, что подтолкнуло более раннюю попытку Трента к этому логическому завершению. Исправлена ​​чрезвычайно редкая ошибка, из-за которой хэширование чисел с плавающей точкой могло возвращать -1, даже если ошибки не было (не тратя время на попытки создать тестовый пример, из кода было просто очевидно, что это может произойти). Улучшен сложный хеш, так что hash(complex(x, y)) систематически не равен hash(complex(y, x)) .

В частности, в этом static long float_hash(PyFloatObject *v) он вырвал код static long float_hash(PyFloatObject *v) в Objects/floatobject.c и заставил его просто return _Py_HashDouble(v->ob_fval); и в определении long _Py_HashDouble(double v) в Objects/object.c он добавил строки:

        if (Py_IS_INFINITY(intpart))
            /* can't convert to long int -- arbitrary */
            v = v < 0 ? -271828.0 : 314159.0;

Как уже упоминалось, это был произвольный выбор. Обратите внимание, что 271828 формируется из первых нескольких десятичных цифр e .

Связанные позже коммиты:





pi