파이썬에서 무한의 해시는 pi와 일치하는 숫자를 갖습니다 .
>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159
우연의 일치 일까, 아니면 의도적 인 것일까?
sys.hash_info
. 이스터 에그?
-314159
. 나는 그것을 잊었다.
파이썬에서 무한의 해시는 pi와 일치하는 숫자를 갖습니다 .
>>> inf = float('inf')
>>> hash(inf)
314159
>>> int(math.pi*1e5)
314159
우연의 일치 일까, 아니면 의도적 인 것일까?
sys.hash_info
. 이스터 에그?
-314159
. 나는 그것을 잊었다.
답변:
_PyHASH_INF
되고 상수로 정의는 동일 314159
.
이에 대한 토론이나 이유를 알려주는 의견을 찾을 수 없습니다. 나는 그것이 다소 임의로 선택되었다고 생각합니다. 다른 해시에 동일한 의미의 값을 사용하지 않는 한 중요하지 않다고 생각합니다.
hash(314159)
도 마찬가지 314159
입니다. 또한 파이썬 3에서, 시도 hash(2305843009214008110) == 314159
(이 입력이 314159 + sys.hash_info.modulus
등)
요약 : 우연의 일치가 아닙니다. 파이썬의 기본 CPython 구현에서 _PyHASH_INF
314159 로 하드 코딩 되었으며 2000 년 Tim Peters에 의해 임의의 값 (π의 숫자에서 분명히 선택됨)으로 선택 되었습니다 .
의 값은 hash(float('inf'))
숫자 유형의 내장 해시 함수의 시스템에 의존하는 매개 변수 중 하나이며, 도 사용할 수 있습니다 로 sys.hash_info.inf
파이썬 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
에서 내장 함수입니다. 그 포인터으로 제공되는 기능 파이썬 플로트 객체를 호출합니다 호출 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;
여기서 314159 _PyHASH_INF
로 정의됩니다 .
#define _PyHASH_INF 314159
역사의 측면에서의 첫 번째 언급 314159
파이썬 코드에서이 맥락에서은 (당신이 이것을 찾을 수 있습니다 git bisect
또는 git log -S 314159 -p
추가되었다) 팀 피터스 (Tim Peters) 지금 커밋 무엇에, 2000 년 8 월 39dce293을 에 cpython
자식 저장소.
커밋 메시지는 다음과 같이 말합니다.
http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470 수정되었습니다 . 이것은 오해의 소지가있는 버그였습니다. 진정한 "버그"는 무한대 일
hash(x)
때 오류를 반환했습니다x
. 고쳤다. 에 새Py_IS_INFINITY
매크로를 추가 했습니다pyport.h
. 부동 소수점과 복소수의 해싱에서 중복되는 중복을 줄이기 위해 코드를 재정렬하여 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은 e 의 처음 몇 십진수로 구성 됩니다.
관련 커밋 :
2010 년 4 월 Mark Dickinson ( 또한 )에 의해 Decimal
유형이 유사하게 동작 함
2010 년 4 월 Mark Dickinson ( 또한 )이이 검사를 맨 위로 이동하고 테스트 사례 추가
2010 년 5 월 마크 디킨슨으로 같은 문제 8188 완전히에 해시 함수를 다시 작성 현재 구현을 하지만,이 특별한 경우를 유지, 상수에 이름을주고 _PyHASH_INF
도 인 271828을 제거 (왜 파이썬 3 명 hash(float('-inf'))
을 반환 -314159
하는 대신 -271828
이 파이썬에서와 같이 2)
2011 년 1 월 Raymond Hettingersys.hash_info
는 위의 값 을 보여주는 Python 3.2의 "새로운 기능"에 명시적인 예제를 추가했습니다 . ( 여기 참조 )
2012 년 3 월 Stefan Krah가 Decimal 모듈을 수정하지만이 해시는 유지합니다.
년 11 월 2013 년 기독교 Heimes으로 의 정의를 이동 _PyHASH_INF
에서 Include/pyport.h
에 Include/pyhash.h
지금 사는 곳.
hash(42.0)
와 동일하게 hash(42)
또한, 같은 hash(Decimal(42))
과 hash(complex(42))
과 hash(Fraction(42, 1))
. Mark Dickinson의 해결책은 우아한 IMO입니다. 모든 유리수에 사용할 수있는 수학 함수를 정의하고 부동 소수점 숫자도 유리수라는 사실을 사용합니다.
hash(n) = n % M
M = (2 ^ 61-1 )입니다. 이것은 hash(p/q) = (p/q) mod M
분할 n이 모듈로 M로 해석되는 합리적인 n에 대해 일반화됩니다 (즉, hash(p/q) = (p * inverse(q, M)) % M
). 우리가 이것을 원하는 이유 : 만약 d
우리 가 dict에 넣고 d[x] = foo
우리가 가지고 있지만 x==y
(예 : 42.0 == 42) d[y]
와 같지 않다면, d[x]
우리는 문제가있을 것입니다. 겉보기에 복잡한 코드의 대부분은 부동 소수점 형식 자체의 특성에서 비롯되어 분수를 올바르게 복구하고 inf 및 NaN 값에 특별한 경우가 필요합니다.
과연,
sys.hash_info.inf
을 반환합니다 314159
. 값은 생성되지 않으며 소스 코드에 내장되어 있습니다. 사실로,
hash(float('-inf'))
-271828
파이썬 2에서, 또는 대략 -e를 반환합니다 ( 지금 -314159입니다). ).
가장 유명한 두 가지 비이성적 인 숫자가 해시 값으로 사용된다는 사실은 이것이 우연의 일치가 아닐 수 있습니다.
hash(float('nan'))
것0
입니다.