NaN does not equal NaN(swizec.com)
swizec.com
NaN does not equal NaN
http://swizec.com/blog/nan-does-not-equal-nan/swizec/2517
28 comments
blah is now NaN because (5 + NaN) is NaN. We want this because we want to know if there's been some kind of error in the making of blah
Commence countdown to frontpage submission "Float is a monad". I agree with your justification for 5 + NaN evaluating to NaN, but it would be even more useful if NaN == x (and every other operation on NaN) would evaluate to NaN as well. That's obviously not possible in statically typed languages, but it is in JS.
Commence countdown to frontpage submission "Float is a monad". I agree with your justification for 5 + NaN evaluating to NaN, but it would be even more useful if NaN == x (and every other operation on NaN) would evaluate to NaN as well. That's obviously not possible in statically typed languages, but it is in JS.
Haha, "float is a monad" is the first thing that popped into my head when I read that.
> You should never use null in JavaScript for the value of a yet-to-determine number. Always use NaN.
Actually, it is more idiomatic to use undefined for this purpose rather than NaN...
Actually, it is more idiomatic to use undefined for this purpose rather than NaN...
var determineLater; // undefined
var blah = 5;
blah += determineLater; // blah is now NaNYou know what's a simple test for NaN? The isNaN built-in function...
Yes, but this is bigger than that. JavaScript doesn't define NaN, IEEE-754 defines NaN and JavaScript takes its definition from that. So it's IEEE-754 thinks num == num being false is a good test for NaN.
For the record, isNaN in JavaScript is also not necessarily the fastest way of doing it: http://jsperf.com/nantest
For the record, isNaN in JavaScript is also not necessarily the fastest way of doing it: http://jsperf.com/nantest
> For the record, isNaN in JavaScript is also not necessarily the fastest way of doing it
Which will absolutely not matter in 100% of the cases after rounding. `isNaN` is simple (your original criteria) and clearly says what it's doing.
Which will absolutely not matter in 100% of the cases after rounding. `isNaN` is simple (your original criteria) and clearly says what it's doing.
It's things like this that make it hard to write optimizers where floating point is used. Many algebraic identities just don't apply: x == x can't be reduced to true, 0-x isn't the same as -x (it fails for +0), x<=y isn't the opposite of x>y (because of NaN), (a+b)+c isn't the same as a+(b+c), and you can't replace ac+bc with a*(b+c).
The paper "What Every Computer Scientist Should Know About Floating Point Arithmetic" is a good guide to the details.
The paper "What Every Computer Scientist Should Know About Floating Point Arithmetic" is a good guide to the details.
The most intuitive way to describe this for me is:
You've got 2 things, but you know nothing about them. Does the fact that you know nothing about them alone make them equal?
True, they have a commonality (you know nothing about them) but that's not enough to make them equal.
You've got 2 things, but you know nothing about them. Does the fact that you know nothing about them alone make them equal?
True, they have a commonality (you know nothing about them) but that's not enough to make them equal.
Yes, and the creators of the concept were kind enough to embed this intuition into the name, just so you can't forget.
All you know is what it is NOT, not what it IS. So you can't tell if it's the same as anything else.
All you know is what it is NOT, not what it IS. So you can't tell if it's the same as anything else.
Relevant discussions: http://news.ycombinator.com/item?id=2024778 and http://news.ycombinator.com/item?id=2599331
As a former SQL guy myself, this issue wasn't a surprise the first time I saw it.
In MSSQL (and I believe this is somewhat, though not always universal since Structured Query Language is somewhat, though rarely completely compatible between RDBMSs), NULL does not equal NULL (or anything else). In SQL terms, the idea is that it's different from "empty", it's a value with no definition---an unknown.
NaN seemed like it should work the same way. "Zed" is NaN, "Bob" is NaN, "Zed" / "Bob" is NaN. None of those are equal, they simply make no sense, so they're undefinable. (quick disclaimer: It's been a few years since I've had to actually deal with NaN in JavaScript, so if it's now possible to divide "Zed" by "Bob" in newer specs or strange implementations of JS, and not end up with NaN, feel free to correct me, I won't take it personally. I'm not writing from a position of authority on the subject).
In the land of "sort-of standard SQL", this is remedied by Field IS NULL. I can see the a similar utility in JavaScript's IsNaN. It's important to know when two things return values that the equivalent of "unknown", and not allow the unknown to equal the other unknown.
EDIT: changed "not rarely" to "rarely" in second paragraph.
In MSSQL (and I believe this is somewhat, though not always universal since Structured Query Language is somewhat, though rarely completely compatible between RDBMSs), NULL does not equal NULL (or anything else). In SQL terms, the idea is that it's different from "empty", it's a value with no definition---an unknown.
NaN seemed like it should work the same way. "Zed" is NaN, "Bob" is NaN, "Zed" / "Bob" is NaN. None of those are equal, they simply make no sense, so they're undefinable. (quick disclaimer: It's been a few years since I've had to actually deal with NaN in JavaScript, so if it's now possible to divide "Zed" by "Bob" in newer specs or strange implementations of JS, and not end up with NaN, feel free to correct me, I won't take it personally. I'm not writing from a position of authority on the subject).
In the land of "sort-of standard SQL", this is remedied by Field IS NULL. I can see the a similar utility in JavaScript's IsNaN. It's important to know when two things return values that the equivalent of "unknown", and not allow the unknown to equal the other unknown.
EDIT: changed "not rarely" to "rarely" in second paragraph.
In Oracle, the empty string ('') is null, though otherwise it works mostly as you describe.
At least Javascript has isNaN().
Exercise: Try checking for NaN in C. Then read [1] and see if your method is cross platform like you thought
[1] http://stackoverflow.com/questions/570669/checking-if-a-doub...
Exercise: Try checking for NaN in C. Then read [1] and see if your method is cross platform like you thought
[1] http://stackoverflow.com/questions/570669/checking-if-a-doub...
Like NULL in SQL...
sqlite> SELECT 1=1;
1
sqlite> SELECT 1=0;
0
sqlite> SELECT NULL!=NULL;
sqlite> SELECT NULL=NULL;This is correct behaviour. You are supposed to use `isNaN()`, which makes perfect sense.
This is the same as SQL where `NULL IS NULL` is true, but `NULL = NULL` is not true.
This is the same as SQL where `NULL IS NULL` is true, but `NULL = NULL` is not true.
Even better: since SQL has a tri-valued logic (T, F, Unknown) it can assign "Unknown" as the result of a test against NULL. That means that `3 = NULL` is not true, but `3 != NULL` is also not true. If testing against NULL were merely false, then you'd have the bizarre result that
(I was just teaching this today in my DB class! Fun.)
val > 3
and not (val <= 3)
might return different results!(I was just teaching this today in my DB class! Fun.)
Well, yes, this is how it's supposed to work, the values being defined as unknown. SQL is the same with NULLs not matching each other.
Interestingly, this once bit me the other way round. I get so used to NaN/NULL not matching itself that it's a bit off the radar to test, yet I discovered that SAS' equivalent concept, missing, does match with itself. Which caused some head scratching to find!
Interestingly, this once bit me the other way round. I get so used to NaN/NULL not matching itself that it's a bit off the radar to test, yet I discovered that SAS' equivalent concept, missing, does match with itself. Which caused some head scratching to find!
For the record, I do not think there is anything breathtakingly special about this. But it seems to elude a lot of people and I wish it didn't.
1/0 is not equal to 2/0, they are both errors but not the same.
actually, they are both equal to infinity:
#include <stdio.h>
int main()
{
float a = 1. / 0;
float b = 2. / 0;
printf("%f == %f ? %d\n", a, b, a == b);
return 0;
}
will print: inf == inf ? 1
Moreover: #include <stdio.h>
int main()
{
float a = 0. / 0;
float b = a;
printf("%f == %f ? %d\n", a, b, a == b);
return 0;
}
nan == nan ? 0
So this is certainly surprising without knowing quite a bit already about floats, because it means = is not only not transitive but even not reflexive.Actually, they're _not_ both equal to infinity, in the mathematical sense (which I believe you're discussing) -- X / 0 is undefined.
What's equal to infinity is the limit of 1 / x as x approaches 0, and that's only from the positive side. From the negative side, it's -infinity.
What's equal to infinity is the limit of 1 / x as x approaches 0, and that's only from the positive side. From the negative side, it's -infinity.
Nobody is discussing about usual mathematical definitions: this is about the IEEE754 standard. In that context, x / 0 is defined (to positive infinity). I was pointing the error of the OP about the explanation about Nan != Nan.
Actually no. Just in case you were confused by cdavid's sample code: the concise explanation is that division by zero in IEEE floating point produces an infinity (there are two: positive and negative), not a NaN. Neither is necessarily an "error" in the sense of a runtime exception (the generation of which is programmable).
[deleted]
var x = NaN;
console.log(typeof x); //"number"
Yes, that's how it is supposed to work.
Unless of course you are Dr James Anderson ;)
While we're on the topic of NaN, I'd like to mention a lesson from my little book of JavaScript you should never do[1]: You should never use null in JavaScript for the value of a yet-to-determine number. Always use NaN.
Why? It will be easier to detect problems:
blah is now NaN because (5 + NaN) is NaN. We want this because we want to know if there's been some kind of error in the making of blah
Better:
blah is now 5 because (5 + null) is 5. We do not want this because it doesn't let us know that there's been an error (the error typically being that determineLater was - incorrectly - never determined!)
[1] not a real book, just a text file of mis-use cases.