Pointers can be invalid. They can be invalid for any number of reason. Lack of memory, object not found, etc. No one ever suggest that null should not equal null.
File handle can be invalid. They can be invalid for any number of reasons: file not found, access denied, file server is offline. No one has ever made invalid handles not being equal to themselves.
The justification for NaN not being equal to themselves is just bonk.
Most languages nowadays have standard-library functions/types that require well-behaved equality, so why have a builtin type for which equality is not well-behaved?
It makes a lot of sense to me. NaN indicates data has been lost. You did something and you stored the result in a number datatype but the result isn't a number. Data was lost. You lost the data and have only 'your answer wasn't a number.'
Comparing NaN with NaN is asking the computer 'we have two buckets that have overflowed, were their contents the same?' The answer is 'we don't know' which means, to err on the side of safety, the answer is 'no.'
No?
But then it's sensible for different operations to give you different NaN values.
And you still wouldn't say that 4 < NaN is true, or NaN < 4 is true, would you?
So it's still going to confuse the user. Is just changing equality going to give you a better system overall?
Zero/zero doesn’t return NaN because it isn’t representable within floating point - it returns NaN because it is an expression that has no mathematical meaning.
The fact that sqrt(-1) has two valid nonreal answers has nothing to do with why it returns NaN - after all, sqrt(4) has two valid real answers so is also technically not representable by a single floating point value, but that doesn’t typically result in NaN.
NaN is just an error value you get when you ask floating point math a dumb question it can’t usefully answer.
Far more interesting and subtle are the ways in which positive and negative infinity and positive and negative zero let you actually still obtain useful (at least for purposes of things like comparison) results to certain calculations even if they overflow the representable range.
Well, you test for it by comparing the value against itself and seeing if that returns false.
(There’s also a bit of confusion on by value vs. by reference comparison and the actual bit value on a NaN, which isn’t quite right.)
No ieee754 ever produces a NaN result unless the operation has no valid result in the set of real values.
Similarly the behaviour in comparisons: if you want NaN to equal NaN you have to come up with a definition of equality that is also consistent with
NaN < X
NaN > X
NaN == X
The logical result of this is that NaN does not equal itself, and I believe mathematicians agree on that definition. Again not a result of the representation, but a result of the mathematical rules of real values.I want to be very clear here: floating point math always produces the correct value rounded (according to rounding mode) to the appropriate value in the represented space unless it is fundamentally not possible. The only place where floating point (or indeed any finite representation) produces an incorrectly rounded result are the transcendental functions, where some values can only be correctly rounded if you compute the exact value, but the exact value is irrational.
People seem hell bent on complaining about floating point behavior, but it is fundamentally mathematically sound. IEEE754 also specifies some functions like e^x-1 explicitly to ensure that you get the best possible accuracy for the core arithmetic operations
As you say relations with NaN don’t make sense, but given the requirement of a single value NaN != NaN makes the most “sense” mathematically, and a core principle of ieee754 was ensuring the most accurate rendition of true maths with a finite representation (see a bunch of papers by Kahan).
Of course x87’s ieee754 implementation does actually have multiple NaNs, infinities, and representations of the same value. For all its quirks remember x87 was what demonstrated that the ieee754 specification could be made fast and affordably, which non-intel manufacturers were all claiming was impossible. The only real “flaw”* in x87 was the explicit leading 1, which was an artifact of it intel being sufficiently ahead of the curve to predate dropping it.
* the x87 transcendtals are known to be hopelessly inaccurate, but that in theory could have been fixed, whereas the format could not be.
In the meeting when they went over the code the guy who did it said we were wondering why you did this? So I had to explain NaN to him. He really did not know it existed. At any rate I thought this is a weird thing not to know anything at all about.
On the other hand, I would strongly discourage 'if(x)' where x is a float that may be NaN purely because the 'correct' behaviour here isn't clear to me.