bpo-37863: Optimize Fraction.__hash__() (#15298)

This commit is contained in:
Raymond Hettinger 2019-08-15 20:58:26 -07:00 committed by GitHub
parent 69f37bcb28
commit f3cb68f2e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 11 additions and 14 deletions

View file

@ -556,23 +556,19 @@ class Fraction(numbers.Rational):
def __hash__(self): def __hash__(self):
"""hash(self)""" """hash(self)"""
# XXX since this method is expensive, consider caching the result # To make sure that the hash of a Fraction agrees with the hash
# of a numerically equal integer, float or Decimal instance, we
# follow the rules for numeric hashes outlined in the
# documentation. (See library docs, 'Built-in Types').
# In order to make sure that the hash of a Fraction agrees try:
# with the hash of a numerically equal integer, float or dinv = pow(self._denominator, -1, _PyHASH_MODULUS)
# Decimal instance, we follow the rules for numeric hashes except ValueError:
# outlined in the documentation. (See library docs, 'Built-in # ValueError means there is no modular inverse
# Types').
# dinv is the inverse of self._denominator modulo the prime
# _PyHASH_MODULUS, or 0 if self._denominator is divisible by
# _PyHASH_MODULUS.
dinv = pow(self._denominator, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
if not dinv:
hash_ = _PyHASH_INF hash_ = _PyHASH_INF
else: else:
hash_ = abs(self._numerator) * dinv % _PyHASH_MODULUS hash_ = hash(abs(self._numerator)) * dinv % _PyHASH_MODULUS
result = hash_ if self >= 0 else -hash_ result = hash_ if self._numerator >= 0 else -hash_
return -2 if result == -1 else result return -2 if result == -1 else result
def __eq__(a, b): def __eq__(a, b):

View file

@ -0,0 +1 @@
Optimizations for Fraction.__hash__ suggested by Tim Peters.