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/object.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/object.c')
-rw-r--r-- | Objects/object.c | 70 |
1 files changed, 55 insertions, 15 deletions
diff --git a/Objects/object.c b/Objects/object.c index a62c448..d6b7607 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -532,25 +532,65 @@ PyObject_Compare(PyObject *v, PyObject *w) long _Py_HashDouble(double v) { - /* Use frexp to get at the bits in the double. + double intpart, fractpart; + int expo; + long hipart; + long x; /* the final hash value */ + /* This is designed so that Python numbers of different types + * that compare equal 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, &e); + intpart = e; +} +#else + fractpart = modf(v, &intpart); +#endif + if (fractpart == 0.0) { + /* This must return the same hash as an equal int or long. */ + if (intpart > LONG_MAX || -intpart > LONG_MAX) { + /* Convert to long and use its hash. */ + PyObject *plong; /* converted to Python long */ + if (Py_IS_INFINITY(intpart)) + /* can't convert to long int -- arbitrary */ + v = v < 0 ? -271828.0 : 314159.0; + plong = PyLong_FromDouble(v); + if (plong == NULL) + return -1; + x = PyObject_Hash(plong); + Py_DECREF(plong); + return x; + } + /* Fits in a C long == a Python int, so is its own hash. */ + x = (long)intpart; + if (x == -1) + x = -2; + return x; + } + /* The fractional part is non-zero, so we don't have to worry about + * making this match the hash of some other type. + * Use frexp to get at the bits in the double. * Since the VAX D double format has 56 mantissa bits, which is the * most of any double format in use, each of these parts may have as * many as (but no more than) 56 significant bits. - * So, assuming sizeof(long) >= 4, each part can be broken into two longs; - * frexp and multiplication are used to do that. - * Also, since the Cray double format has 15 exponent bits, which is the - * most of any double format in use, shifting the exponent field left by - * 15 won't overflow a long (again assuming sizeof(long) >= 4). + * So, assuming sizeof(long) >= 4, each part can be broken into two + * longs; frexp and multiplication are used to do that. + * Also, since the Cray double format has 15 exponent bits, which is + * the most of any double format in use, shifting the exponent field + * left by 15 won't overflow a long (again assuming sizeof(long) >= 4). */ - int expo; - long hipart; - - v = frexp(v, &expo); - v = v * 2147483648.0; /* 2**31 */ - hipart = (long)v; /* Take the top 32 bits */ - v = (v - (double)hipart) * 2147483648.0; /* Get the next 32 bits */ - - return hipart + (long)v + (expo << 15); /* Combine everything */ + v = frexp(v, &expo); + v *= 2147483648.0; /* 2**31 */ + hipart = (long)v; /* take the top 32 bits */ + v = (v - (double)hipart) * 2147483648.0; /* get the next 32 bits */ + x = hipart + (long)v + (expo << 15); + if (x == -1) + x = -2; + return x; } long |