summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2019-08-16 03:58:26 (GMT)
committerGitHub <noreply@github.com>2019-08-16 03:58:26 (GMT)
commitf3cb68f2e4c3e0c405460f9bb881f5c1db70f535 (patch)
treea37473112bfc5b94a21f76aa655a3a8a1a2ea9f3
parent69f37bcb28d7cd78255828029f895958b5baf6ff (diff)
downloadcpython-f3cb68f2e4c3e0c405460f9bb881f5c1db70f535.zip
cpython-f3cb68f2e4c3e0c405460f9bb881f5c1db70f535.tar.gz
cpython-f3cb68f2e4c3e0c405460f9bb881f5c1db70f535.tar.bz2
bpo-37863: Optimize Fraction.__hash__() (#15298)
-rw-r--r--Lib/fractions.py26
-rw-r--r--Misc/NEWS.d/next/Library/2019-08-14-20-46-39.bpo-37863.CkXqgX.rst1
2 files changed, 12 insertions, 15 deletions
diff --git a/Lib/fractions.py b/Lib/fractions.py
index e774d58..c922c38 100644
--- a/Lib/fractions.py
+++ b/Lib/fractions.py
@@ -556,23 +556,19 @@ class Fraction(numbers.Rational):
def __hash__(self):
"""hash(self)"""
- # XXX since this method is expensive, consider caching the result
-
- # In order 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').
-
- # 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:
+ # 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').
+
+ try:
+ dinv = pow(self._denominator, -1, _PyHASH_MODULUS)
+ except ValueError:
+ # ValueError means there is no modular inverse
hash_ = _PyHASH_INF
else:
- hash_ = abs(self._numerator) * dinv % _PyHASH_MODULUS
- result = hash_ if self >= 0 else -hash_
+ hash_ = hash(abs(self._numerator)) * dinv % _PyHASH_MODULUS
+ result = hash_ if self._numerator >= 0 else -hash_
return -2 if result == -1 else result
def __eq__(a, b):
diff --git a/Misc/NEWS.d/next/Library/2019-08-14-20-46-39.bpo-37863.CkXqgX.rst b/Misc/NEWS.d/next/Library/2019-08-14-20-46-39.bpo-37863.CkXqgX.rst
new file mode 100644
index 0000000..90df6e9
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-08-14-20-46-39.bpo-37863.CkXqgX.rst
@@ -0,0 +1 @@
+Optimizations for Fraction.__hash__ suggested by Tim Peters.