
Masklinn wrote:
Excuse me but NaNs propagate right? So we'd have not only float('nan') == float('nan'), but also float('nan') = float('nan') + 1 right?
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 its result.
[Meyer:]
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 mechanism. 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: ... else: ... 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 produced. 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. -- Greg