diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2010-05-23 13:33:13 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2010-05-23 13:33:13 (GMT) |
commit | dc787d2055a7b562b64ca91b8f1af6d49fa39f1c (patch) | |
tree | f6a3868e8134c25c662868f19306bfea76b0ab45 /Objects/longobject.c | |
parent | 03721133a68814696e3eee75b1eb09f5016ff078 (diff) | |
download | cpython-dc787d2055a7b562b64ca91b8f1af6d49fa39f1c.zip cpython-dc787d2055a7b562b64ca91b8f1af6d49fa39f1c.tar.gz cpython-dc787d2055a7b562b64ca91b8f1af6d49fa39f1c.tar.bz2 |
Issue #8188: Introduce a new scheme for computing hashes of numbers
(instances of int, float, complex, decimal.Decimal and
fractions.Fraction) that makes it easy to maintain the invariant that
hash(x) == hash(y) whenever x and y have equal value.
Diffstat (limited to 'Objects/longobject.c')
-rw-r--r-- | Objects/longobject.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c index 850396b..564d1a0 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2571,18 +2571,37 @@ long_hash(PyLongObject *v) sign = -1; i = -(i); } - /* The following loop produces a C unsigned long x such that x is - congruent to the absolute value of v modulo ULONG_MAX. The - resulting x is nonzero if and only if v is. */ while (--i >= 0) { - /* Force a native long #-bits (32 or 64) circular shift */ - x = (x >> (8*SIZEOF_LONG-PyLong_SHIFT)) | (x << PyLong_SHIFT); + /* Here x is a quantity in the range [0, _PyHASH_MODULUS); we + want to compute x * 2**PyLong_SHIFT + v->ob_digit[i] modulo + _PyHASH_MODULUS. + + The computation of x * 2**PyLong_SHIFT % _PyHASH_MODULUS + amounts to a rotation of the bits of x. To see this, write + + x * 2**PyLong_SHIFT = y * 2**_PyHASH_BITS + z + + where y = x >> (_PyHASH_BITS - PyLong_SHIFT) gives the top + PyLong_SHIFT bits of x (those that are shifted out of the + original _PyHASH_BITS bits, and z = (x << PyLong_SHIFT) & + _PyHASH_MODULUS gives the bottom _PyHASH_BITS - PyLong_SHIFT + bits of x, shifted up. Then since 2**_PyHASH_BITS is + congruent to 1 modulo _PyHASH_MODULUS, y*2**_PyHASH_BITS is + congruent to y modulo _PyHASH_MODULUS. So + + x * 2**PyLong_SHIFT = y + z (mod _PyHASH_MODULUS). + + The right-hand side is just the result of rotating the + _PyHASH_BITS bits of x left by PyLong_SHIFT places; since + not all _PyHASH_BITS bits of x are 1s, the same is true + after rotation, so 0 <= y+z < _PyHASH_MODULUS and y + z is + the reduction of x*2**PyLong_SHIFT modulo + _PyHASH_MODULUS. */ + x = ((x << PyLong_SHIFT) & _PyHASH_MODULUS) | + (x >> (_PyHASH_BITS - PyLong_SHIFT)); x += v->ob_digit[i]; - /* If the addition above overflowed we compensate by - incrementing. This preserves the value modulo - ULONG_MAX. */ - if (x < v->ob_digit[i]) - x++; + if (x >= _PyHASH_MODULUS) + x -= _PyHASH_MODULUS; } x = x * sign; if (x == (unsigned long)-1) |