Podsumowanie: To nie przypadek; _PyHASH_INF
jest zapisany na stałe jako 314159 w domyślnej implementacji CPython w Pythonie i został wybrany jako dowolna wartość (oczywiście z cyfr π) przez Tim Peters w 2000 roku .
Wartość hash(float('inf'))
jest jednym z zależnych od systemu parametrów wbudowanej funkcji skrótu dla typów numerycznych i jest również dostępna jak sys.hash_info.inf
w Pythonie 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
(Te same wyniki również w przypadku PyPy .)
Pod względem kodu hash
jest wbudowaną funkcją. Nazywając go na obiekt typu float Python wywołuje funkcję, której wskaźnik jest przez tp_hash
atrybut z wbudowanym typu float ( PyTypeObject PyFloat_Type
), która jestfloat_hash
funkcja, zdefiniowanego jako return _Py_HashDouble(v->ob_fval)
, co z kolei ma
if (Py_IS_INFINITY(v))
return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
gdzie _PyHASH_INF
jest zdefiniowany jako 314159:
#define _PyHASH_INF 314159
Jeśli chodzi o historię, pierwsza wzmianka o 314159
tym kontekście w kodzie Pythona (można to znaleźć za pomocą git bisect
lub git log -S 314159 -p
) została dodana przez Tima Petersa w sierpniu 2000 r. W tym, co obecnie zatwierdza 39dce293 w cpython
repozytorium git.
Komunikat zatwierdzenia mówi:
Poprawka dla http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470 . To był błąd wprowadzający w błąd - prawdziwy „błąd” polegał hash(x)
na zwróceniu błędu, gdy x
występuje nieskończoność. Naprawiono to. Dodano nowe Py_IS_INFINITY
makro do
pyport.h
. Zmieniono kod, aby zmniejszyć rosnące powielanie liczb mieszanych i liczb zespolonych, co doprowadziło do logicznego zakończenia wcześniejszego dźgnięcia Trenta. Naprawiono niezwykle rzadki błąd, w którym haszowanie liczb zmiennoprzecinkowych mogło zwrócić -1, nawet jeśli nie wystąpił błąd (nie marnował czasu na próby zbudowania przypadku testowego, po prostu było oczywiste z kodu, że może się zdarzyć). Ulepszony złożony skrót, który
hash(complex(x, y))
nie jest już systematycznie równy hash(complex(y, x))
.
W szczególności w tym zatwierdzeniu rozerwał kod static long float_hash(PyFloatObject *v)
in Objects/floatobject.c
i uczynił go sprawiedliwym return _Py_HashDouble(v->ob_fval);
, aw definicji long _Py_HashDouble(double v)
in Objects/object.c
dodał linie:
if (Py_IS_INFINITY(intpart))
/* can't convert to long int -- arbitrary */
v = v < 0 ? -271828.0 : 314159.0;
Jak wspomniano, był to arbitralny wybór. Zauważ, że 271828 jest utworzony z pierwszych kilku cyfr dziesiętnych e .
Powiązane później zatwierdza:
Autor: Mark Dickinson w kwietniu 2010 r. ( Także ), dzięki czemu ten Decimal
typ zachowuje się podobnie
Autor: Mark Dickinson w kwietniu 2010 r. ( Także ), przenosząc tę kontrolę na górę i dodając przypadki testowe
Autor: Mark Dickinson w maju 2010 jako numer 8188 , całkowicie przepisując funkcję haszującą do jej obecnej implementacji , ale zachowując ten specjalny przypadek, nadając stałej nazwę _PyHASH_INF
(usuwając również 271828, dlatego hash(float('-inf'))
powraca w Pythonie 3, -314159
a nie -271828
jak w Pythonie 2)
Autor: Raymond Hettinger w styczniu 2011 r. , Dodając wyraźny przykład w „Co nowego” dla Python 3.2 sys.hash_info
pokazujący powyższą wartość. (Zobacz tutaj .)
Autor: Stefan Krah w marcu 2012 r. Modyfikujący moduł dziesiętny, ale zachowujący ten skrót.
Christian Heimes w listopadzie 2013 roku , przeniósł się do definicji _PyHASH_INF
z Include/pyport.h
celu Include/pyhash.h
, gdzie obecnie mieszka.
hash(float('nan'))
bycie0
.