Why does Double.NaN==Double.NaN return false?
NaN means "Not a Number".
Java Language Specification (JLS) Third Edition says:
An operation that overflows produces a signed infinity, an operation that underflows produces a denormalized value or a signed zero, and an operation that has no mathematically definite result produces NaN. All numeric operations with NaN as an operand produce NaN as a result. As has already been described, NaN is unordered, so a numeric comparison operation involving one or two NaNs returns
false
and any!=
comparison involving NaN returnstrue
, includingx!=x
whenx
is NaN.
Java variable shows value of 'NaN' but var == Double.NaN is false, why?
You can check for NaN
only via Double.isNan()
:
if (Double.isNaN(sim)) {
// is Nan
} else {
// not nan
}
On first thoughts that is not intiutive, you have to know it.
The reason behind it, is that this is specified by IEEE Floating Point standard.
You can argument:NaN
is not a number, it can be anything but not a number, so two NaN
cannot be compared to be equal.
For example = 0.0 / 0.0 is NaN; and sqrt(-1) is NaN, too. But that values cannot be compared to be the same.
Additional reading: http://en.wikipedia.org/wiki/NaN
Why does double.IsNegative(double.NaN) return true?
Well, according to refrence source, double.IsNegative
just checks the most significant bit:
[Pure]
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe static bool IsNegative(double d) {
return (*(UInt64*)(&d) & 0x8000000000000000) == 0x8000000000000000;
}
In case of double.NaN
the most signifucant bit is set:
11111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000
|| || |
|<- Exp -><- Mantissa ->
Sign
That's why double.IsNegative
returns true
When we put <
or >
FPU commands are used which know all ones exponent is a special kind of floating point value which should be treated in a special way.
The very same picture is with Single.NaN
.
Note, that we can construct another strange value, negative zero:
10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|| || |
|<- Exp -><- Mantissa ->
Sign
Please, look:
double negativeZero = BitConverter.ToDouble(new byte[] {
0, 0, 0, 0, 0, 0, 0, 128
});
Console.WriteLine(negativeZero == 0 ? "Zero" : "???");
Console.WriteLine(double.IsNegative(negativeZero) ? "Negative" : "???");
Why does Double.NaN equal itself when wrapped in a Double instance?
What is going on is that the equals
method deliberately deviates from IEE floating point. Quoting from the Javadoc for the equals(Object)
method of java.lang.Double.
However, there are two exceptions:
- If d1 and d2 both represent Double.NaN, then the equals method
returns true, even though
Double.NaN==Double.NaN has the value
false.- If d1 represents +0.0 while d2 represents -0.0, or vice versa, the
equal test has the value false, even
though +0.0==-0.0 has the value true.
This definition allows hash tables to
operate properly.
The upshot is that if you want 100% IEE floating point compatibility you need to explicitly unbox the java.lang.Double
instances and compare the resulting double
values.
Comparing Double.NaN with itself
The reason for the difference is simple, if not obvious.
If you use the equality operator ==
, then you're using the IEEE test for equality.
If you're using the Equals(object)
method, then you have to maintain the contract of object.Equals(object)
. When you implement this method (and the corresponding GetHashCode
method), you have to maintain that contract, which is different from the IEEE behaviour.
If the Equals
contract was not upheld, then the behaviour of hash tables would break.
var map = new Dictionary<double,string>();
map[double.NaN] = "NaN";
var s = map[double.NaN];
If !double.NaN.Equals(double.NaN)
, you'd never get your value out of the dictionary!
If the previous sentence does not make sense, then understand that the mechanics of hashing (used in Dictionary<T,U>
, HashSet<T>
, etc) use both the object.Equals(object)
and object.GetHashCode()
methods extensively, and rely upon guarantees of their behaviour.
Why does this comparsion return false?
From the Java Language Specifications:
Floating-point operators produce no exceptions (§11). An operation
that overflows produces a signed infinity, an operation that
underflows produces a denormalized value or a signed zero, and an
operation that has no mathematically definite result produces NaN. All
numeric operations with NaN as an operand produce NaN as a result. As
has already been described, NaN is unordered, so a numeric comparison
operation involving one or two NaNs returns false and any !=
comparison involving NaN returns true, including x!=x when x is NaN.
The important sentence here is:
so a numeric comparison
operation involving one or two NaNs returns false
Why is double.NaN not equal to itself?
If you are curious, this is what Double.IsNaN
looks like:
public static bool IsNaN(double d)
{
return (d != d);
}
Funky, huh?
What is the purpose of Double.IsNaN(double d)?
double
and float
have "Not A Number" values that they use to represent error quantities. A NaN has the unfortunate property that it always compares false to everything, including itself. Thus you call a special method to tell you if a given double is a NaN. (Since NaNs are the only values that have the property that they do not equal themselves, you can also tell if a value is a NaN by comparing it to itself! But x != x
looks weird in the code; it is much more idiomatic to simply call IsNaN(x)
.)
Is there something about the documentation that was so unclear that it prompted you to ask a question here? If you can explain what you found unclear I can pass that feedback on to the documentation manager.
NaN Constant Magic in Java
NaN
is a concept, not a value or a number. Since that concept can represent multiple non-real-number values (imaginary, 0/0, etc) it doesn't make sense to say that any particular NaN is equal to any other NaN.
Similarly you can't say that Double::NEGATIVE_INFINITY
equals itself, since infinity is not a number either.
Related Topics
Open a Link in Browser with Java Button
How to Schedule a Task to Run at Periodic Intervals
Docker: Combine Multiple Images
How to Implement Dynamic Gui in Swing
What Objects How to Inject Using the @Context Annotation
How to Extract a Tar File in Java
List.Clear() VS List = New Arraylist<Integer>();
Eclipse: Attach Source/Javadoc to a Library via a Local Property
How to Access Resources in Jar File
Spring Boot @Responsebody Doesn't Serialize Entity Id
Is Jdk "Upward" or "Backward" Compatible
How to Add Unicode in Truetype0Font on PDFbox 2.0.0
Package Conflicts with Automatic Modules in Java 9