diff options
-rw-r--r-- | Include/pyport.h | 10 | ||||
-rw-r--r-- | Objects/complexobject.c | 63 | ||||
-rw-r--r-- | Objects/floatobject.c | 39 | ||||
-rw-r--r-- | Objects/longobject.c | 2 | ||||
-rw-r--r-- | Objects/object.c | 70 |
5 files changed, 83 insertions, 101 deletions
diff --git a/Include/pyport.h b/Include/pyport.h index 3d9b305..5bd641c 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -103,7 +103,7 @@ extern "C" { #define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) ((I) >> (J)) #endif -/* Py_FORCE_EXPANSION +/* Py_FORCE_EXPANSION(X) * "Simply" returns its argument. However, macro expansions within the * argument are evaluated. This unfortunate trickery is needed to get * token-pasting to work as desired in some cases. @@ -123,6 +123,14 @@ extern "C" { #define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) (NARROW)(VALUE) #endif +/* Py_IS_INFINITY(X) + * Return 1 if float or double arg is an infinity, else 0. + * Caution: + * X is evaluated more than once. + * This implementation may set the underflow flag if |X| is very small; + * it really can't be implemented correctly (& easily) before C99. + */ + #define Py_IS_INFINITY(X) ((X) && (X)*0.5 == (X)) /************************************************************************** Prototypes that are missing from the standard include files on some systems 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 * diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 8182ae2..26b39e8 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -326,44 +326,7 @@ float_compare(PyFloatObject *v, PyFloatObject *w) static long float_hash(PyFloatObject *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->ob_fval, &e); - intpart = e; -} -#else - fractpart = modf(v->ob_fval, &intpart); -#endif - - if (fractpart == 0.0) { - if (intpart > LONG_MAX || -intpart > LONG_MAX) { - /* Convert to long int and use its hash... */ - PyObject *w = PyLong_FromDouble(v->ob_fval); - if (w == NULL) - return -1; - x = PyObject_Hash(w); - Py_DECREF(w); - return x; - } - x = (long)intpart; - } - else { - /* Note -- if you change this code, also change the copy - in complexobject.c */ - x = _Py_HashDouble(v->ob_fval); - if (x == -1) - return -1; - } - if (x == -1) - x = -2; - return x; + return _Py_HashDouble(v->ob_fval); } static PyObject * diff --git a/Objects/longobject.c b/Objects/longobject.c index 37da244..86b4aba 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -114,7 +114,7 @@ PyLong_FromDouble(double dval) double frac; int i, ndig, expo, neg; neg = 0; - if (dval && dval * 0.5 == dval) { + if (Py_IS_INFINITY(dval)) { PyErr_SetString(PyExc_OverflowError, "cannot convert float infinity to long"); return NULL; 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 |