Skip to content

Commit f40244f

Browse files
author
Stefan Behnel
committed
cache hash value
1 parent f4ca829 commit f40244f

File tree

1 file changed

+13
-6
lines changed

1 file changed

+13
-6
lines changed

src/quicktions.pyx

+13-6
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,11 @@ cdef class Fraction:
130130
"""
131131
cdef _numerator
132132
cdef _denominator
133+
cdef Py_hash_t _hash
133134

134135
def __cinit__(self, numerator=0, denominator=None, _normalize=True):
135136
cdef Fraction value
137+
self._hash = -1
136138
if denominator is None:
137139
if type(numerator) is int or type(numerator) is long:
138140
self._numerator = numerator
@@ -508,25 +510,30 @@ cdef class Fraction:
508510

509511
def __hash__(self):
510512
"""hash(self)"""
511-
512-
# XXX since this method is expensive, consider caching the result
513+
if self._hash != -1:
514+
return self._hash
513515

514516
# In order to make sure that the hash of a Fraction agrees
515517
# with the hash of a numerically equal integer, float or
516518
# Decimal instance, we follow the rules for numeric hashes
517519
# outlined in the documentation. (See library docs, 'Built-in
518520
# Types').
519521

522+
cdef Py_hash_t result
520523
# dinv is the inverse of self._denominator modulo the prime
521524
# _PyHASH_MODULUS, or 0 if self._denominator is divisible by
522525
# _PyHASH_MODULUS.
523526
dinv = pow(self._denominator, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
524527
if not dinv:
525-
hash_ = _PyHASH_INF
528+
result = _PyHASH_INF
526529
else:
527-
hash_ = abs(self._numerator) * dinv % _PyHASH_MODULUS
528-
result = hash_ if self >= 0 else -hash_
529-
return -2 if result == -1 else result
530+
result = abs(self._numerator) * dinv % _PyHASH_MODULUS
531+
if self._numerator < 0:
532+
result = -result
533+
if result == -1:
534+
result = -2
535+
self._hash = result
536+
return result
530537

531538
def __richcmp__(a, b, int op):
532539
if op == Py_EQ:

0 commit comments

Comments
 (0)