Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The stupid thing about IEEE NaN is that it's not equal to itself! If variable x holds a NaN, then (x == x) is false.

This violates: http://en.wikipedia.org/wiki/Law_of_identity

If (x == x) tests false, then it asserts that x is not itself, which is logically preposterous.

ANSI Common Lisp has a bit of this problem in it too, but it's not required; it is there for some weird historic implementations. That is to say, if x holds a number like 1, then (eq x x) is not required. (But in sane implementations it does yield t; and it yields t even if x is a bignum, because (eq x x) is given the same object as two arguments. Two separately computed bignums of equal value will likely, of course, not be eq.

How this can be explained is that eq tests "implementation identity", and somehow different instances of a number are treated as different implementations. Argument passing is by value, and the two reductions of the expression x in (eq x x) to a value somehow produce a different implementation of the value.

This rationale is unrelated to IEEE NaN-s, though.



Don't quote me on this, but I recall the rational for NaN is because NaN is typically the result of a division by 0.

Divisions by 0 can be thought of as infinity (for the sake of this explanation, but mathematicians will cringe), but it is not any particular infinity. In the sense that x / 0 does not necessarily have to equal y / 0. For that definition, the result of a division by 0, NaN, must not equal itself.

You can use `isNaN`, tho.


I understand the point perfectly. However, if I have a NaN which is captured in a lexical variable (perhaps the result of a division by zero, as you note) then in fact I do have a particular infinity: whatever object is inside that darned variable! If I do another division by zero, then sure, hit me with a different NaN which doesn't compare equal to the first one I got. But don't make my variable not equal to itself.


Normal division by zero gives you Infinity. To get NaN, you have to do something as numerically confounding as divide zero by zero, which isn't any infinity, because the numerator is zero, and which isn't zero or any finite number, because the denominator is zero.


Yes, and some programming languages will let you express that, eg C you can compare &x == &x not x == x.


IEEE division by zero gives positive (or negative) infinity (with the sign determined by the sign of the zero). NaN crops up with e.g. sqrt(-1) and infinity - infinity for which there is no way to define a sane answer.


Determining positive or negative infinity from the "sign of the zero" is not sane to begin with. Zero has no sign in mathematics. It's just a representational accident in floating-point: there is a one bit wide field for sign, and for the sake of uniformity, representations of zero have that field too. Treating these as different is dumb; they are just different spellings of the same number in a bitwise notation.

To drive the point home, this is somewhat like making 0xF different from 15.


> Zero has no sign in mathematics.

Not wrong, but zero having a sign is useful for several complex plane algorithms--it's not just an accident.

As a general rule, anything that is in IEEE 754 (or 854) has a damn good reason for being there, and you had best take some time to understand it or risk looking stupid. A lot of hardware people screamed about a lot of the obnoxious software crap in IEEE 754, so, if something survived and made it into the standard, it had an initial reason for being there even if that reason has gone away with time/the advance of knowledge/Moore's Law.

The original designer's commentary about it is: William Kahan, "Branch Cuts for Complex Elementary Functions, or Much Ado About Nothing's Sign Bit", in The State of the Art in Numerical Analysis (eds. Iserles and Powell), Clarendon Press, Oxford, 1987.


You are missing a lot of nuance here.

First of all it is debatable over whether or not the spec allows (eq x x) to be false. eq is required to return true if the arguments are the same identical object. It would be a twisted interpretation of that to allow (eq x x) to ever return false.

Now (eq 1 1) is specifically not required to return true, as, for example an implementation that boxes all numbers could create two separate objects for that expression, and the arguments are now in fact not the same identical object.

This is something that exposes implementation details to the user, so using eq is discouraged (and in fact it can only portably be used to compare symbols). There are times when the best way to accomplish what you are doing is to (ab)use implementation specific behavior, and this is particularly true of Lisp which was a dynamically typed garbage collected language in the 70s (yes, predating the VT100 terminal referenced in this article).


Direct quote from Common Lisp HyperSpec, under Function EQ:

"An implementation is permitted to make ``copies'' of characters and numbers at any time. The effect is that Common Lisp makes no guarantee that eq is true even when both its arguments are ``the same thing'' if that thing is a character or number. "


Ah, you're correct, a copy can be made at the call to eq.

I stand by the rest of what I said. It's no more strange for (eq 1 1) to be false than (eql '(1) '(1))


You are correct. However:

    (let ((x '(1)))
      (eql x x))
yields T!

It is strange for (eq x x) to be false, when x holds 1, or anything else; yet that appears to be allowed when it holds a number or character.

(eq 1 1) being nil caters to implementations that have heap allocated numbers. That is fine, but under (eq x x), both arguments should be the same heap-allocated 1.

(eq x x) being nil is nothing but pandering to some weird, historic implementations, whose quirk should never have been made ANSI conforming. I don't think it's relevant today.


NaN literally means "not a number." Lots of things aren't numbers. The letter a is not a number. The square root of negative 1 is not a number (at least, not one representable in floating point math). a is not equal to the square root of negative 1.


In practice, NaN as a literal means that the outcome of a mathematical statement is not expressible. So, the letter 'a' is not equal to NaN (with either two or three = signs). NaN, in other words, has a special meaning.

Dismayingly, JavaScript's isNaN() function diverges from this special meaning, and does something close to what you said -- it tests to see if something is at least almost a number. So isNaN(13/0) and isNaN('foo') both evaluate to 'true', whereas isNaN('1') and isNaN(42) both evaluate to 'false'.


Javascript type coercions might make sense if you realize it was originally designed for a close integration with HTML forms using a simplified proto-DOM ("Level 0").

The idea was more like "isNaN(myForm.myField)"?

For all I know, the above might actually still work. But either way, that explains Javascript type conversion logic.


I don't understand your point. This is not a number:

    char *p = "abc";
Yet, this yields true:

    p == p
The square root of -1 is easily representable in floating math. You just need two floats to make a complex.


Okay, but while "abc" is not a number, it is also the string "abc". NaN is special in that all it tells you is that the value is not a number -- it doesn't tell you what it is. In order to return a true value from an equality test, it isn't enough to know that both values are not a number, you have to know what they actually are.


If it is not known what is in the p variable, then the variable is indeterminate; it has exactly the same status as a variable that has not been initialized. In this case, the behavior upon accessing the variable should be undefined.

I agree with making accesses of NaN-valued variables undefined behavior, so that not comparing equal is then a possible consequence of undefined behavior.

I don't agree with defining the unequal comparison as the required behavior. To define the behavior is tantamount to the recognition that a NaN is something: an object. A variable can have a defined value which is that something, and that value must obey the Law of Identity.


The point is that you can have very different things that are not a number. It's not safe to say that multiple things that are not a number are equal.


The values of two expressions that evaluate the same variable are not "multiple things".


According to http://stackoverflow.com/a/1573715 the IEEE-754 committee decided to make NaN != NaN in order for programmers to have a simple way of detecting NaN before there was a standardized isnan function or macro.


I'm lacking sleep a bit here, but wouldn't NaN == NaN do the same trick?


Yes, if you take the false result to be the indication that you have a NaN. Either polarity comparison will work, if you correctly interpret its result.


The law of identity shouldn't apply to NaN because it isn't a single value. NaN represents a set of values that get mapped to NaN. But information is lost along the way. Since we can't recover that information, we can't know for certain what value this NaN represents or whether this NaN represents the same thing as that NaN.


The stupid thing about IEEE NaN is that it's not equal to itself!

Why would it be? The rationale makes perfect sense. It would be unexpected to believe that 17/0 == 0^0. Both are NaN, and equally nonsense, but 2 very different statements.

Secondly, IIRC, NaN is supposed to break assert(x==x), because if you use NaN in your program, then your program is undefined.


Your == expression has distinct operands which are the results of different evaluations.

The problem is that a NaN is not equal to itself:

    double nan = /* NaN-producing expression */

    if (nan == nan) {
      /* dead code */
    }


While your overall point is correct, your example is wrong: 17/0 == Infinity, and 0^0 == 1. Neither is NaN :)


Infinity is Not a Number, so 17/0 is NaN.


IEEE floating point distinguishes infinities and NaNs.


D'oh. Missed that we were specifically talking about IEEE floating point. That was very stupid of me.


Having consistent behavior for NaN means that I can write "<math operation> ? x : y" and know that "y" will be the result when "<math operation>" involves NaN. It's useful.

Not saying it's the perfect way to handle things, but it's pretty reasonable in world where people write code that generates NaN almost every time they use division. I worry more about writing code that generates NaNs than NaNs themselves anyway.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: