Why Does Double.Nan==Double.Nan Return False

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 returns true, including x!=x when x 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



Leave a reply



Submit