Резюме: это не совпадение; _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
атрибутом из встроенного типа поплавка ( PyTypeObject PyFloat_Type
), который являетсяfloat_hash
функцией, определенной , как return _Py_HashDouble(v->ob_fval)
, что , в свою очередь , имеет
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 года в том, что сейчас является коммитом 39dce293 в cpython
репозитории git.
Сообщение коммита говорит:
Исправление для http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470 . Это была вводящая в заблуждение ошибка - истинная «ошибка» заключалась в том, что она hash(x)
возвращала ошибку, когда x
это бесконечность. Исправлено. Добавлен новый Py_IS_INFINITY
макрос в
pyport.h
. Переставил код, чтобы уменьшить растущее дублирование в хешировании чисел с плавающей запятой и комплексных чисел, подтолкнув ранний удар Трента в этом к логическому завершению. Исправлена чрезвычайно редкая ошибка, при которой хеширование чисел с плавающей запятой могло возвращать -1, даже если ошибки не было (не тратя время на попытки создать тестовый пример, из кода было просто очевидно, что это может произойти). Улучшен сложный хеш, так что
hash(complex(x, y))
систематически hash(complex(y, x))
больше не равно .
В частности, в этом коммите он вырвал код static long float_hash(PyFloatObject *v)
in 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 .
Связанные позже коммиты:
hash(float('nan'))
быть0
.