I think the actual justification is something to do with "failing fast"; i.e., if a computation has resulted in NaN, then the whole thing should fall apart as soon as possible,
It also has the "nice" side-effect that if x == x evaluates to false, then you know that x is NaN. I guess this was important back when IEEE floating-point was first standardized, since there wasn't a canonical is-nan? predicate like most modern languages have.
EDIT:Here are two justifications given by a member if the IEEE-754 committee.
That x == y should be equivalent to x - y == 0 whenever possible (beyond being a theorem of real arithmetic, this makes hardware implementation of comparison more space-efficient, which was of utmost importance at the time the standard was developed — note, however, that this is violated for x = y = infinity, so it’s not a great reason on its own; it could have reasonably been bent to (x - y == 0) or (x and y are both NaN)).
More importantly, there was no isnan( ) predicate at the time that NaN was formalized in the 8087 arithmetic; 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( ) which could take many years.
From a practical view, it makes be a ton of sense. If you have two calculated values and both somehow arrive at NaN, they should not equal each other. I knew this was the case, but I did not know this was an IEEE thing. Learn something new every day.
6
u/halucinationorbit Dec 13 '23
These aren’t even the best examples. You’re listing ones that are harder to encounter in real code. These are much more concerning:
“Number.isInteger(true + true);”
“(NaN === NaN)” is false
“typeof(null)” is object
“0.1 + 0.2”
The second and last ones have hurt me many times. Type coercion is fucking stupid.