Хеш нескінченності в Python має цифри, відповідні pi :
>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159
Це просто збіг чи це навмисне?
sys.hash_info. Пасхальне яйце?
-314159. Я забув про це.
Хеш нескінченності в Python має цифри, відповідні pi :
>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159
Це просто збіг чи це навмисне?
sys.hash_info. Пасхальне яйце?
-314159. Я забув про це.
Відповіді:
_PyHASH_INFбуде визначено як константа , яка дорівнює314159 .
Я не можу знайти жодної дискусії з цього приводу або коментарів, що дають причину. Я думаю, що його обирали більш-менш довільно. Я гадаю, що поки вони не використовують однакове значення для інших хешів, це не має значення.
hash(314159)також 314159. Також спробуйте, в Python 3, hash(2305843009214008110) == 314159(цей вхід є 314159 + sys.hash_info.modulus) тощо
Резюме: Це не випадковість; у впровадженні CPython Python за замовчуванням _PyHASH_INFжорстко кодується як 314159 , і Тим Петерс у 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. Впорядкований код для зменшення дублювання у хешировании float і комплексних чисел, підштовхуючи попередній удар Trent до логічного завершення. Виправлена надзвичайно рідкісна помилка, при якій хеширование плавців може повернутися до -1, навіть якщо не було помилки (не витрачаючи часу на конструювання тестового випадку, з коду було просто очевидно, що це може статися). Удосконалено складний хеш, щобhash(complex(x, y))систематичноhash(complex(y, x))більше не дорівнювати .
Зокрема, у цьому документі він видобув код 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 утворюється з перших кількох десяткових цифр е .
Пов’язані пізніші зобов’язання:
За Марком Дікінсоном у квітні 2010 року ( також ), змушуючи Decimalтип вести себе аналогічно
Автор Марка Дікінсона у квітні 2010 року ( також ), перемістивши цей чек на початок і додавши тестові випадки
Марк Дікінсон в травні 2010 року як випуск 8188 , повністю переписав хеш-функцію до її поточної реалізації , але зберігаючи цей особливий випадок, даючи постійне ім'я _PyHASH_INF(також видаляючи 271828, тому в Python 3 hash(float('-inf'))повертається, -314159а не -271828як у Python 2)
Автор Реймонд Хеттінгер у січні 2011 року , додавши явний приклад у "Що нового" для Python 3.2 sys.hash_infoпоказує вищевказане значення. (Дивіться тут .)
Штефан Крах у березні 2012 року модифікував модуль Decimal, але зберігав цей хеш.
Крістіан Хеймс у листопаді 2013 року переніс визначення _PyHASH_INFз того Include/pyport.hмісця, Include/pyhash.hде воно живе зараз.
hash(42.0)бути такими ж hash(42), також такими ж, як hash(Decimal(42))і hash(complex(42))і hash(Fraction(42, 1)). Рішення (за Марком Дікінсоном) - це елегантний ІМО: визначення математичної функції, яка працює для будь-якого раціонального числа, та використання факту, що числа з плаваючою комою є і раціональними числами.
hash(n) = n % Mтам, де M = (2 ^ 61 - 1). Це узагальнено для раціонального n до hash(p/q) = (p/q) mod Mтого, як інтерпретується поділ за модулем M (іншими словами hash(p/q) = (p * inverse(q, M)) % M:). Причина, яку ми хочемо так: якщо dми поставимо в дікт d[x] = fooі тоді ми маємо x==y(наприклад, 42,0 == 42), але d[y]це не те саме d[x], що у нас виникне проблема. Більшість, здавалося б, складних кодів походить від характеру самого формату з плаваючою комою, щоб належним чином відновити дріб та потрібні спеціальні випадки для значень inf та NaN.
Дійсно,
sys.hash_info.inf
повертає 314159. Значення не генерується, воно вбудовано у вихідний код. Фактично,
hash(float('-inf'))
повертається -271828, або приблизно -e, в python 2 ( зараз -314159 ).
Той факт, що два найвідоміші ірраціональні числа усіх часів використовуються як хешові значення, робить його малоймовірним випадковістю.
hash(float('nan'))буття0.