NANs were not designed with object-oriented coding in mind. They were designed with low-level languages in mind where there is no concept of “object identity”.
Under those circumstances, it is highly desirable that NANs compare unequal to every value, including other NANs, even other NANs with the same bit-pattern.
(Remember that there are many different NAN bit-patterns. NANs can differ by a 51 bit payload, a 1 bit quiet vs signalling bit, and a sign bit.)
Otherwise we would have very bad consequences. Quoting Stephen Canon, who was on the IEEE committee that chose the behaviour:
“NaN being equal to itself would be extremely problematic. It would lead to completely nonsensical “true” statements like 0.0/0.0 == infinity - infinity
or acos(1.5) == log(-1.0)
. You really don’t want those to be identities, much more so than you want == to be reflexive.”
The source of the quote was this Stackoverflow post a few years ago, but unfortunately it looks like somebody has deleted that specific comment, or at least I can’t find it now. (One of the bad things about Stackoverflow is that people can edit other people’s comments.)
When IEEE-754 maths was moved into object-oriented languages like Python, folks decided that the way to honour the spirit of the standard was for NANs to compare unequal to all other floats, including:
- other NANs;
- even if they have the same bit-pattern;
- even if they are the same object.
Alas, that implies that the interpreter cannot assume that if two object references point to the same object that they are not equal.
Yes for Decimal. For floats: no, but yes, but mostly no.
Signalling NANs will signal (raise an exception) on comparisons:
>>> from decimal import Decimal
>>> s = Decimal('snan')
>>> s == 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
The Decimal module has a flag that treats all NANs as signalling NANs. That is fully supported.
In theory, we can do the same with binary floats. Most (all?) CPUs that implement IEEE-754 allow you to set the floating point flags to treat all NANs as signalling.
Unfortunately this is platform specific, and Python’s support for float exception control was fragile and unmaintained and is now removed.