Podsumowanie: To nie przypadek; _PyHASH_INFjest 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.infw 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 hashjest wbudowaną funkcją. Nazywając go na obiekt typu float Python wywołuje funkcję, której wskaźnik jest przez tp_hashatrybut 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_INFjest zdefiniowany jako 314159:
#define _PyHASH_INF 314159
Jeśli chodzi o historię, pierwsza wzmianka o 314159tym kontekście w kodzie Pythona (można to znaleźć za pomocą git bisectlub git log -S 314159 -p) została dodana przez Tima Petersa w sierpniu 2000 r. W tym, co obecnie zatwierdza 39dce293 w cpythonrepozytorium 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 xwystępuje nieskończoność. Naprawiono to. Dodano nowe Py_IS_INFINITYmakro 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.ci uczynił go sprawiedliwym return _Py_HashDouble(v->ob_fval);, aw definicji long _Py_HashDouble(double v)in Objects/object.cdodał 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 Decimaltyp 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, -314159a nie -271828jak 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_infopokazują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_INFz Include/pyport.hcelu Include/pyhash.h, gdzie obecnie mieszka.
hash(float('nan'))bycie0.