summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/pyport.h10
-rw-r--r--Objects/complexobject.c63
-rw-r--r--Objects/floatobject.c39
-rw-r--r--Objects/longobject.c2
-rw-r--r--Objects/object.c70
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