diff options
author | Tim Peters <tim.peters@gmail.com> | 2000-08-15 03:34:48 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2000-08-15 03:34:48 (GMT) |
commit | 39dce29365d287dc6b353b2a527dc11fe58dcfa6 (patch) | |
tree | f24a592be4c36c5d1888fb0881e8535bf023e41b /Objects/complexobject.c | |
parent | 7aced17437a6b05bc4b0b5ff93aa6a5d3a374d68 (diff) | |
download | cpython-39dce29365d287dc6b353b2a527dc11fe58dcfa6.zip cpython-39dce29365d287dc6b353b2a527dc11fe58dcfa6.tar.gz cpython-39dce29365d287dc6b353b2a527dc11fe58dcfa6.tar.bz2 |
Fix for http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470.
This was a misleading bug -- the true "bug" was that hash(x) gave an error
return when x is an infinity. Fixed that. Added new Py_IS_INFINITY macro to
pyport.h. Rearranged code to reduce growing duplication in hashing of float and
complex numbers, pushing Trent's earlier stab at that to a logical conclusion.
Fixed exceedingly rare bug where hashing of floats could return -1 even if there
wasn't an error (didn't waste time trying to construct a test case, it was simply
obvious from the code that it *could* happen). Improved complex hash so that
hash(complex(x, y)) doesn't systematically equal hash(complex(y, x)) anymore.
Diffstat (limited to 'Objects/complexobject.c')
-rw-r--r-- | Objects/complexobject.c | 63 |
1 files changed, 17 insertions, 46 deletions
diff --git a/Objects/complexobject.c b/Objects/complexobject.c index e8916d5..6f1cfea 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -242,52 +242,23 @@ complex_compare(PyComplexObject *v, PyComplexObject *w) static long complex_hash(PyComplexObject *v) { - double intpart, fractpart; - long x; - /* This is designed so that Python numbers with the same - value hash to the same value, otherwise comparisons - of mapping keys will turn out weird */ - -#ifdef MPW /* MPW C modf expects pointer to extended as second argument */ -{ - extended e; - fractpart = modf(v->cval.real, &e); - intpart = e; -} -#else - fractpart = modf(v->cval.real, &intpart); -#endif - - if (fractpart == 0.0 && v->cval.imag == 0.0) { - if (intpart > LONG_MAX || -intpart > LONG_MAX) { - /* Convert to long int and use its hash... */ - PyObject *w = PyLong_FromDouble(v->cval.real); - if (w == NULL) - return -1; - x = PyObject_Hash(w); - Py_DECREF(w); - return x; - } - x = (long)intpart; - } - else { - x = _Py_HashDouble(v->cval.real); - if (x == -1) - return -1; - - if (v->cval.imag != 0.0) { /* Hash the imaginary part */ - /* XXX Note that this hashes complex(x, y) - to the same value as complex(y, x). - Still better than it used to be :-) */ - long y = _Py_HashDouble(v->cval.imag); - if (y == -1) - return -1; - x += y; - } - } - if (x == -1) - x = -2; - return x; + long hashreal, hashimag, combined; + hashreal = _Py_HashDouble(v->cval.real); + if (hashreal == -1) + return -1; + hashimag = _Py_HashDouble(v->cval.imag); + if (hashimag == -1) + return -1; + /* Note: if the imaginary part is 0, hashimag is 0 now, + * so the following returns hashreal unchanged. This is + * important because numbers of different types that + * compare equal must have the same hash value, so that + * hash(x + 0*j) must equal hash(x). + */ + combined = hashreal + 1000003 * hashimag; + if (combined == -1) + combined = -2; + return combined; } static PyObject * |