Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 39dce29

Browse files
committed
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.
1 parent 7aced17 commit 39dce29

5 files changed

Lines changed: 83 additions & 101 deletions

File tree

Include/pyport.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ extern "C" {
103103
#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) ((I) >> (J))
104104
#endif
105105

106-
/* Py_FORCE_EXPANSION
106+
/* Py_FORCE_EXPANSION(X)
107107
* "Simply" returns its argument. However, macro expansions within the
108108
* argument are evaluated. This unfortunate trickery is needed to get
109109
* token-pasting to work as desired in some cases.
@@ -123,6 +123,14 @@ extern "C" {
123123
#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) (NARROW)(VALUE)
124124
#endif
125125

126+
/* Py_IS_INFINITY(X)
127+
* Return 1 if float or double arg is an infinity, else 0.
128+
* Caution:
129+
* X is evaluated more than once.
130+
* This implementation may set the underflow flag if |X| is very small;
131+
* it really can't be implemented correctly (& easily) before C99.
132+
*/
133+
#define Py_IS_INFINITY(X) ((X) && (X)*0.5 == (X))
126134

127135
/**************************************************************************
128136
Prototypes that are missing from the standard include files on some systems

Objects/complexobject.c

Lines changed: 17 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -242,52 +242,23 @@ complex_compare(PyComplexObject *v, PyComplexObject *w)
242242
static long
243243
complex_hash(PyComplexObject *v)
244244
{
245-
double intpart, fractpart;
246-
long x;
247-
/* This is designed so that Python numbers with the same
248-
value hash to the same value, otherwise comparisons
249-
of mapping keys will turn out weird */
250-
251-
#ifdef MPW /* MPW C modf expects pointer to extended as second argument */
252-
{
253-
extended e;
254-
fractpart = modf(v->cval.real, &e);
255-
intpart = e;
256-
}
257-
#else
258-
fractpart = modf(v->cval.real, &intpart);
259-
#endif
260-
261-
if (fractpart == 0.0 && v->cval.imag == 0.0) {
262-
if (intpart > LONG_MAX || -intpart > LONG_MAX) {
263-
/* Convert to long int and use its hash... */
264-
PyObject *w = PyLong_FromDouble(v->cval.real);
265-
if (w == NULL)
266-
return -1;
267-
x = PyObject_Hash(w);
268-
Py_DECREF(w);
269-
return x;
270-
}
271-
x = (long)intpart;
272-
}
273-
else {
274-
x = _Py_HashDouble(v->cval.real);
275-
if (x == -1)
276-
return -1;
277-
278-
if (v->cval.imag != 0.0) { /* Hash the imaginary part */
279-
/* XXX Note that this hashes complex(x, y)
280-
to the same value as complex(y, x).
281-
Still better than it used to be :-) */
282-
long y = _Py_HashDouble(v->cval.imag);
283-
if (y == -1)
284-
return -1;
285-
x += y;
286-
}
287-
}
288-
if (x == -1)
289-
x = -2;
290-
return x;
245+
long hashreal, hashimag, combined;
246+
hashreal = _Py_HashDouble(v->cval.real);
247+
if (hashreal == -1)
248+
return -1;
249+
hashimag = _Py_HashDouble(v->cval.imag);
250+
if (hashimag == -1)
251+
return -1;
252+
/* Note: if the imaginary part is 0, hashimag is 0 now,
253+
* so the following returns hashreal unchanged. This is
254+
* important because numbers of different types that
255+
* compare equal must have the same hash value, so that
256+
* hash(x + 0*j) must equal hash(x).
257+
*/
258+
combined = hashreal + 1000003 * hashimag;
259+
if (combined == -1)
260+
combined = -2;
261+
return combined;
291262
}
292263

293264
static PyObject *

Objects/floatobject.c

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -326,44 +326,7 @@ float_compare(PyFloatObject *v, PyFloatObject *w)
326326
static long
327327
float_hash(PyFloatObject *v)
328328
{
329-
double intpart, fractpart;
330-
long x;
331-
/* This is designed so that Python numbers with the same
332-
value hash to the same value, otherwise comparisons
333-
of mapping keys will turn out weird */
334-
335-
#ifdef MPW /* MPW C modf expects pointer to extended as second argument */
336-
{
337-
extended e;
338-
fractpart = modf(v->ob_fval, &e);
339-
intpart = e;
340-
}
341-
#else
342-
fractpart = modf(v->ob_fval, &intpart);
343-
#endif
344-
345-
if (fractpart == 0.0) {
346-
if (intpart > LONG_MAX || -intpart > LONG_MAX) {
347-
/* Convert to long int and use its hash... */
348-
PyObject *w = PyLong_FromDouble(v->ob_fval);
349-
if (w == NULL)
350-
return -1;
351-
x = PyObject_Hash(w);
352-
Py_DECREF(w);
353-
return x;
354-
}
355-
x = (long)intpart;
356-
}
357-
else {
358-
/* Note -- if you change this code, also change the copy
359-
in complexobject.c */
360-
x = _Py_HashDouble(v->ob_fval);
361-
if (x == -1)
362-
return -1;
363-
}
364-
if (x == -1)
365-
x = -2;
366-
return x;
329+
return _Py_HashDouble(v->ob_fval);
367330
}
368331

369332
static PyObject *

Objects/longobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ PyLong_FromDouble(double dval)
114114
double frac;
115115
int i, ndig, expo, neg;
116116
neg = 0;
117-
if (dval && dval * 0.5 == dval) {
117+
if (Py_IS_INFINITY(dval)) {
118118
PyErr_SetString(PyExc_OverflowError,
119119
"cannot convert float infinity to long");
120120
return NULL;

Objects/object.c

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -532,25 +532,65 @@ PyObject_Compare(PyObject *v, PyObject *w)
532532
long
533533
_Py_HashDouble(double v)
534534
{
535-
/* Use frexp to get at the bits in the double.
535+
double intpart, fractpart;
536+
int expo;
537+
long hipart;
538+
long x; /* the final hash value */
539+
/* This is designed so that Python numbers of different types
540+
* that compare equal hash to the same value; otherwise comparisons
541+
* of mapping keys will turn out weird.
542+
*/
543+
544+
#ifdef MPW /* MPW C modf expects pointer to extended as second argument */
545+
{
546+
extended e;
547+
fractpart = modf(v, &e);
548+
intpart = e;
549+
}
550+
#else
551+
fractpart = modf(v, &intpart);
552+
#endif
553+
if (fractpart == 0.0) {
554+
/* This must return the same hash as an equal int or long. */
555+
if (intpart > LONG_MAX || -intpart > LONG_MAX) {
556+
/* Convert to long and use its hash. */
557+
PyObject *plong; /* converted to Python long */
558+
if (Py_IS_INFINITY(intpart))
559+
/* can't convert to long int -- arbitrary */
560+
v = v < 0 ? -271828.0 : 314159.0;
561+
plong = PyLong_FromDouble(v);
562+
if (plong == NULL)
563+
return -1;
564+
x = PyObject_Hash(plong);
565+
Py_DECREF(plong);
566+
return x;
567+
}
568+
/* Fits in a C long == a Python int, so is its own hash. */
569+
x = (long)intpart;
570+
if (x == -1)
571+
x = -2;
572+
return x;
573+
}
574+
/* The fractional part is non-zero, so we don't have to worry about
575+
* making this match the hash of some other type.
576+
* Use frexp to get at the bits in the double.
536577
* Since the VAX D double format has 56 mantissa bits, which is the
537578
* most of any double format in use, each of these parts may have as
538579
* many as (but no more than) 56 significant bits.
539-
* So, assuming sizeof(long) >= 4, each part can be broken into two longs;
540-
* frexp and multiplication are used to do that.
541-
* Also, since the Cray double format has 15 exponent bits, which is the
542-
* most of any double format in use, shifting the exponent field left by
543-
* 15 won't overflow a long (again assuming sizeof(long) >= 4).
580+
* So, assuming sizeof(long) >= 4, each part can be broken into two
581+
* longs; frexp and multiplication are used to do that.
582+
* Also, since the Cray double format has 15 exponent bits, which is
583+
* the most of any double format in use, shifting the exponent field
584+
* left by 15 won't overflow a long (again assuming sizeof(long) >= 4).
544585
*/
545-
int expo;
546-
long hipart;
547-
548-
v = frexp(v, &expo);
549-
v = v * 2147483648.0; /* 2**31 */
550-
hipart = (long)v; /* Take the top 32 bits */
551-
v = (v - (double)hipart) * 2147483648.0; /* Get the next 32 bits */
552-
553-
return hipart + (long)v + (expo << 15); /* Combine everything */
586+
v = frexp(v, &expo);
587+
v *= 2147483648.0; /* 2**31 */
588+
hipart = (long)v; /* take the top 32 bits */
589+
v = (v - (double)hipart) * 2147483648.0; /* get the next 32 bits */
590+
x = hipart + (long)v + (expo << 15);
591+
if (x == -1)
592+
x = -2;
593+
return x;
554594
}
555595

556596
long

0 commit comments

Comments
 (0)