754 decide NaN != NaN despite being illogical?
This is a follow up question to What is the rationale for all comparisons returning false for IEEE754 NaN values? (I think this is better as another question than a comment). It has a very good answer which is missing exactly 1 important thing: why is NaN != NaN
?
I understand that NaN is unordered compared to numbers and thus NaN < x
and NaN > x
are both always false. But that doesn't explain why equality is backwards. To quote the answer of the question I linked to:
it was necessary to provide programmers with a convenient and efficient means of detecting NaN values that didn't depend on programming languages providing something like isNan()
Ok then:
if((0/0) == x) print "I found NaN!";
//using 0/0 is more readable than using 0x7fc00000 or 0x7ff8000000000000
That's convenient, efficient, and doesn't rely on a programming language provided construct. Even if the programming language doesn't have a global NaN defined you can easily make a local (or global) variable yourself.
A single extra operation is certainly not inefficient, especially since the FPU has a hard-coded response (no calculation needed). Using 0/0 is also more programmer convenient than the illogical x!=x
.
A program rarely needs to check for NaN and having a single extra operation per check is not going to be the reason a program is inefficient. Likewise there's no program so restrained that it can't handle a single extra variable, especially a temporary one.
To me the argument "I need NaN!=NaN
so that I can detect it" doesn't make sense: it's exactly the same argument as "I need Infinity!=Infinity
so that I can detect it". No you don't, just compare it to 1/0 like everyone else.
So my question is much more narrow than the original question: Why is NaN != NaN
?
I can't tell if this has been asked before since there's plenty of duplicates of the original question.
Side note:
NaN == NaN
isn't going to change now
while the FPU won't change now, some programming languages have already changed so that NaN == NaN
is true.
Edit:
Let me try to clarify why I haven't accepted any answer so far. I have read the comments so far and I'm sorry I've dropped the ball: instead of explaining why I disagree I just asked "why" hoping you'd give a different reason. So let me try to explain my perspective better.
Infinity and NaN are similar in many ways.
x == Infinity
doesn't use numeric equality (since Infinity isn't a number) instead it checks if x represents the concept of positive infinity. I would likewise expect exactly the same thing from x == NaN
to return true if x is the concept of "not a number" but this isn't the case (as to why is the point of this question). x == (1/0)
is the way to compare x to Infinity. x-1
doesn't change the value of Infinity or NaN). So yes I did hear you when you said "equality doesn't make sense because it isn't a number" but I disagree with that statement because if it was true then as per #1 it also wouldn't make sense to compare Infinity (which also isn't a number). Although as per #2 it does make sense to compare non-numbers.
I have in fact read every answer to the original question (and to Why are floating point infinities, unlike NaNs, equal? which has some related answers). All of the arguments for why NaN != NaN
is true boil down to either "because it isn't a number" (already addressed) or "because there are many different bit representations" which is countered by #5.
I can't think of any logical basis for why NaN should have different equality. I'm not saying that I have accounted for everything: so what have I missed? Is one of my arguments wrong or is there some other reason I hadn't thought of? That's why I've been camping on the word "why". If you disagree then refute me or defend your point. I'm guessing there will be at least 1 counter-point to my above logic and I'm looking forward to hearing it.
Again I apologize for not including these in the original question since I have been thinking them all along. I'm also sorry that this may cause a big change to the existing answer.
There are several ways to produce NaN
.
Imagine this:
double expr1 = 0.0 / 0.0;
double expr2 = Math.log(-1.0);
if (expr1 == expr2) {
// They are the same
}
These two NaN
s, if they had been representable as numbers, would have a high probability of being different values.
If NaN == NaN
would hold, this snippet would have the unexpected result of comparing them as equal. Since most programs do the comparison in terms of what they expect (so they use ==
, <=
, but not !==
, !<=
), returning false
doesn't make these programs conclude wrong things.