[ python-Bugs-899109 ] 1==float('nan')

SourceForge.net noreply at sourceforge.net
Thu Feb 19 14:55:39 EST 2004


Bugs item #899109, was opened at 2004-02-17 21:47
Message generated for change (Comment added) made by eggert
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=899109&group_id=5470

Category: Python Interpreter Core
Group: Python 2.3
Status: Closed
Resolution: Fixed
Priority: 5
Submitted By: Arman Bostani (arman0)
Assigned to: Michael Hudson (mwh)
Summary: 1==float('nan')

Initial Comment:
In python 2.3.1 on Linux/x86, X==float('nan') evaluates
to True given any number value for X.  I admit to not
knowing much about IEEE arithmetic.  But, is this Kosher?

-arman
 

----------------------------------------------------------------------

Comment By: Paul Eggert (eggert)
Date: 2004-02-19 19:55

Message:
Logged In: YES 
user_id=17848

C99 does say what happens when NaNs are
compared.  See, for example, section 7.12.14,
which says that NaNs are unordered with respect
to other floating point values, and section
7.12.14.1, which says that x>y is equivalent to
isgreater(x,y) and therefore returns false if
either x or y is a NaN (unless the "invalid"
floating-point exception occurs, which isn't
happening here and even if it did happen the
original code would be broken anyway).

Your argument is that any code that uses NaNs
returns garbage and so we should give up.  But
then you have no logical reason to either favor
or oppose this patch, as it doesn't alter
Python's behavior on non-NaN arguments.

It's clear the the patch does fix the comparison
problem on most existing platforms.  It actually
works on Solaris sparc, and I'm sure that it
will work on a wide variety of other important
platforms.

The fact that you've found an incompatibility
between MSVC 6 and C99 on one example does not
mean that the proposed patch won't work: it
merely means that MSVC 6 won't work on your
example (which is deliberately constructed to
confuse pre-C99 compilers).  The proposed patch
doesn't contain confusing code like that, so it
should work even on pre-C99 compilers.

I'm not speaking just from theory here.  Similar
code has been in GNU sort since 1999, and it
works fine in practice.

Since the patch fixes the bug on many (perhaps
all) real platforms, and it can't introduce a
bug on any platform, the patch is a win.

Michael Hudson said "Consider the attached."
but nothing was attached.  I gather from his
comments that he added rich comparisons for
floats.  This will work if the code never
invokes the 2.3.3 float_compare -- so can I take
it that he removed float_compare?


----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2004-02-19 19:39

Message:
Logged In: YES 
user_id=6656

Tim said yes.

Objects/floatobject.c revision 2.127
Misc/NEWS revision 1.936

----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2004-02-19 19:01

Message:
Logged In: YES 
user_id=6656

Consider the attached.  It implements rich comparisons for
floats, which makes the behaviour on linux at least very
much less silly.  All tests except for the
considered-hopeless-on-this box audio tests and the new
test_tcl pass.  Even test_bsddb passed! Twice!  (I'm not
sure I can claim credit for this :-)

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2004-02-19 17:34

Message:
Logged In: YES 
user_id=31435

Sorry, the patch can't work:  C89 says nothing about what 
happens when NaNs are compared, and it's in fact not the 
case across platforms that "x != x" returns 1 when x is a NaN.

The most important counter-example for Python is that the 
following prints

1.#INF
-1.#IND
1

under MSVC 6.

#include <stdio.h>

void main()
{
    double x = 1e300 * 1e300;
    printf("%g\n", x);
    x -= x;
    printf("%g\n", x);
    printf("%d\n", x == x);
}


----------------------------------------------------------------------

Comment By: Paul Eggert (eggert)
Date: 2004-02-19 06:39

Message:
Logged In: YES 
user_id=17848

There's an easy fix.  Python has long mishandled IEEE
special values
(see bugs 445484 and 737648, and see PEP 42 "Non-accidental
IEEE-754
support" as well as PEP 754), and solving the problem in
general will
be some work.  However, solving the NaN-comparison problem
is easy:
simply sort NaNs consistently before all numbers.  This is
the same
algorithm that GNU "sort -g" has used for quite some time.

===================================================================
RCS file: Include/pyport.h,v
retrieving revision 2.3.3.0
diff -pu -r2.3.3.0 Include/pyport.h
--- Include/pyport.h	2003/09/30 14:56:50	2.3.3.0
+++ Include/pyport.h	2004/02/19 06:06:10
@@ -221,6 +221,13 @@ extern "C" {
 #define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) (NARROW)(VALUE)
 #endif
 
+/* Py_IS_NAN(X)
+ * Return 1 if float or double arg is not a number (NaN),
else 0.
+ * Caution:
+ *    X is evaluated more than once.
+ */
+#define Py_IS_NAN(X) ((X) != (X))
+
 /* Py_IS_INFINITY(X)
  * Return 1 if float or double arg is an infinity, else 0.
  * Caution:
===================================================================
RCS file: Objects/floatobject.c,v
retrieving revision 2.3.3.0
diff -pu -r2.3.3.0 Objects/floatobject.c
--- Objects/floatobject.c	2003/06/28 20:04:24	2.3.3.0
+++ Objects/floatobject.c	2004/02/19 06:03:37
@@ -367,7 +367,21 @@ float_compare(PyFloatObject *v, PyFloatO
 {
 	double i = v->ob_fval;
 	double j = w->ob_fval;
-	return (i < j) ? -1 : (i > j) ? 1 : 0;
+	int c;
+	/* Because of NaNs IEEE arithmetic is not a total order.
+	 * Python works better with total orders, so use the same
+	 * total order that GNU sort does: NaNs sort before numbers,
+	 * and NaNs are sorted by internal bit-pattern.
+	 */
+	return ((i < j) ? -1
+		: (i > j) ? 1
+		: (i == j) ? 0
+		: !Py_IS_NAN(j) ? -1 /* i is NaN, j is not */
+		: !Py_IS_NAN(i) ? 1  /* j is NAN, i is not */
+		: /* i and j are both NaNs; compare them bitwise */
+		  ((c = memcmp(&v->ob_fval, &w->ob_fval, sizeof(v->ob_fval)))
+		   < 0) ? -1
+		: (c > 0));
 }
 
 static long


----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2004-02-18 17:46

Message:
Logged In: YES 
user_id=6656

Man, that's strange (I see the same behaviour on my redhat 9
box with 2.3.3).

I don't have time to dig right now, but if you want to,
playing with equivalent C programs would be a very good start.

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=899109&group_id=5470



More information about the Python-bugs-list mailing list