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.
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 @@
 #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 @@
 #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 @@
 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 @@
 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 @@
 	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 @@
 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