Win a copy of Functional Reactive Programming this week in the Other Languages forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

About NaN

 
Liang Anmian
Ranch Hand
Posts: 119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just curious over here. How come Double.NaN is not even equal to itself? I read about this from the K & B book, and true enough, Double.NaN == Double.NaN returns false.
 
Barry Gaunt
Ranch Hand
Posts: 7729
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I don't pretend to know much about the details, but quick glance at the Double API shows that NaN does not represent a single unique bit pattern, but a set of invalid bit patterns. It's a canonical representation for results that are not valid floating point numbers. So two NaNs may represent different things. That's my excuse for Double.NaN == Double.NaN giving the result false.

However, to confuse things even further, (new Double(Double.NaN)).equals(Double.NaN) returns true, for getting hash tables to work correctly the API says. :roll:

Oh yes, did you notice there is an isNaN() method? That's what we should be using to check if we have a NaN.

[ January 15, 2005: Message edited by: Barry Gaunt ]
[ January 15, 2005: Message edited by: Barry Gaunt ]
 
Liang Anmian
Ranch Hand
Posts: 119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The reason why I don't understand is that Double.NaN is a final variable in the Double wrapper class. Since it's a constant (it's value can't be changed throughout the program), how can a comparison test like this fail? It's very weird I thought.
 
Barry Gaunt
Ranch Hand
Posts: 7729
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
To find out why, I reckon you will have to read the IEEE 754 specification, Java is trying to be conformant to that.
 
Andris Jekabsons
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It actually kinda makes sense, because NaN is not a number, therefore regular arithmetic/boolean operations should not work with it the same way as with numbers.
And if you look at the Double's source code, this is how NaN is declared:
public static final double NaN = 0.0d / 0.0;
So JVM must know it is not a regular number, and evaluates it accordingly.
By the way, does anybody have any idea why NaN is given the value of 0x7ff8000000000000L (or 9221120237041090560L). Is it just a random number or is there some significance?
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Maybe it does not help much but I took this from the IEEE754 specification:


The exceptions are C predicates � x == x � and � x != x �, which are respectively 1 and 0 for every
infinite or finite number x but reverse if x is Not a Number ( NaN ); these provide the only simple unexceptional
distinction between NaNs and numbers in languages that lack a word for NaN and a predicate IsNaN(x). Overoptimizing
compilers that substitute 1 for x == x violate IEEE 754.
IEEE 754 assigns values to all relational expressions involving NaN . In the syntax of C , the predicate
x != y is True but all others, x < y , x <= y , x == y , x >= y and x > y , are False whenever
x or y or both are NaN, and then all but x != y and x == y are INVALID operations too and must so
signal. Ideally, expressions x !< y , x !<= y , x !>= y , x !> y and x !>=< y should be valid and
quietly True if x or y or both are NaN , but arbiters of taste and fashion for ANSI Standard C have refused to
recognize such expressions. In any event, !(x < y) differs from x >= y when NaN is involved, though
rude compilers � optimize � the difference away. Worse, some compilers mishandle NaNs in all relational
expressions.
 
Mike Gershman
Ranch Hand
Posts: 1272
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The plot thickens.

From the JLS:

If the argument is any value in the range 0x7ff0000000000001L through 0x7fffffffffffffffL or in the range 0xfff0000000000001L through 0xffffffffffffffffL, the result is a NaN.

So Java makes sure that NaN != NaN by using over 2^60 possible bit patterns for NaN. This way, the jvm can enforce the IEEE rule without checking for NaN during every == operation.
 
Andris Jekabsons
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you both!
Yesterday I was playing around a little with the NaN value and noticed that indeed NaN was represented by a range of values rather then a specific one.
 
Sim Kim
Ranch Hand
Posts: 268
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Has anybody tried this :

System.out.println(((new Double(Double.NaN)).equals(new Double(Double.NaN))));

Ans: True
 
Mike Gershman
Ranch Hand
Posts: 1272
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Has anybody tried this :

System.out.println(((new Double(Double.NaN)).equals(new Double(Double.NaN))));

Ans: True


This is the source code of Double.equals():



Double.doubleToLongBits() collapses all possible bit representations of NaN to the canonical value, 0x7ff8000000000000L.

I hope that this degree of detail will not be on the SCJP exam!

[ January 16, 2005: Message edited by: Mike Gershman ]
[ January 16, 2005: Message edited by: Mike Gershman ]
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic