[Python-ideas] Why is nan != nan?
greg.ewing at canterbury.ac.nz
Fri Mar 26 03:01:46 CET 2010
> Excuse me but NaNs propagate right? So we'd have not only
> float('nan') == float('nan'), but also float('nan') = float('nan') + 1
The fact that one of the operands was a NaN propagates,
but it doesn't have to be that particular NaN object.
So NaN + 1 could create a new NaN object to return as
>> It is rather dangerous indeed to depart from the fundamental laws of mathematics.
> The very idea of IEEE-754 floats are a
> a definite departure from the fundamental laws of mathematics,
They're a departure from the laws of *real numbers*,
but Meyer is using the word "mathematics" in a much
broader sense here -- meaning any formal system
that you can reason about rigorously.
If your formal system has a notion of equality but
includes values that don't compare equal to themselves,
it seriously screws up your ability to reason about it.
For Meyer, this is a *big* problem, because making it
possible to reason rigorously about programs is something
that Eiffel gets really anal about^H^H^H^H^H^H^H^H^H^H
^H^H^H^H^H^H one of the underpinnings of Eiffel's design.
The more I think about it, the more I think that the
only reason for needing NaNs in the first place is if
you don't have, or don't want to use, an exception
As Meyer points out, treating NaN == NaN as false is
not fundamentally any more correct than treating it
as true. One interpretation or the other might be
appropriate in a particular algorithm, but this needs
to be considered on a case-by-case basis.
So the *pythonic* way to handle NaNs is not to have
them at all, but to raise an exception whenever an
operation would produce a NaN. Code that knows what
to do can catch the exception and proceed appropriately.
Another possibility is to extend the boolean type with
a NaB that propagates in the same way as a NaN. But
something still has to give somewhere, because what
happens when you do this?
x = float('nan')
y = float('nan')
if x == y:
If NaN == NaN is a NaB, then neither branch of the
'if' is appopriate, so the only correct thing to do
would be to raise an exception when trying to branch
on a NaB.
So we have three correctness-preserving possibilites:
1) Always raise an exception as soon as a NaN is
2) Propagate NaNs through arithmetic but raise an
exception when attempting to compare them.
3) Return a NaB when comparing NaNs, and raise an
exception when attempting to branch on a NaB.
More information about the Python-ideas