[Python-checkins] CVS: python/dist/src/Objects complexobject.c,2.29,2.30 floatobject.c,2.66,2.67 longobject.c,1.65,1.66 object.c,2.93,2.94

Tim Peters python-dev@python.org
Mon, 14 Aug 2000 20:34:51 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory slayer.i.sourceforge.net:/tmp/cvs-serv1338/python/dist/src/Objects

Modified Files:
	complexobject.c floatobject.c longobject.c object.c 
Log Message:
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.


Index: complexobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/complexobject.c,v
retrieving revision 2.29
retrieving revision 2.30
diff -C2 -r2.29 -r2.30
*** complexobject.c	2000/07/31 15:28:04	2.29
--- complexobject.c	2000/08/15 03:34:48	2.30
***************
*** 243,292 ****
  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;
  }
  
--- 243,263 ----
  complex_hash(PyComplexObject *v)
  {
! 	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;
  }
  

Index: floatobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/floatobject.c,v
retrieving revision 2.66
retrieving revision 2.67
diff -C2 -r2.66 -r2.67
*** floatobject.c	2000/08/12 21:37:39	2.66
--- floatobject.c	2000/08/15 03:34:48	2.67
***************
*** 327,368 ****
  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;
  }
  
--- 327,331 ----
  float_hash(PyFloatObject *v)
  {
! 	return _Py_HashDouble(v->ob_fval);
  }
  

Index: longobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/longobject.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -C2 -r1.65 -r1.66
*** longobject.c	2000/07/31 15:28:04	1.65
--- longobject.c	2000/08/15 03:34:48	1.66
***************
*** 115,119 ****
  	int i, ndig, expo, neg;
  	neg = 0;
! 	if (dval && dval * 0.5 == dval) {
  		PyErr_SetString(PyExc_OverflowError,
  			"cannot convert float infinity to long");
--- 115,119 ----
  	int i, ndig, expo, neg;
  	neg = 0;
! 	if (Py_IS_INFINITY(dval)) {
  		PyErr_SetString(PyExc_OverflowError,
  			"cannot convert float infinity to long");

Index: object.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v
retrieving revision 2.93
retrieving revision 2.94
diff -C2 -r2.93 -r2.94
*** object.c	2000/08/11 00:14:26	2.93
--- object.c	2000/08/15 03:34:48	2.94
***************
*** 533,555 ****
  _Py_HashDouble(double v)
  {
! 	/* 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).
  	 */
!     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 */
  }
  
--- 533,595 ----
  _Py_HashDouble(double v)
  {
! 	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).
  	 */
! 	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;
  }