GETah
GETah

Reputation: 21449

Comparing Double.NaN with itself

I am stuck trying to find out why these two operations return different values:

  1. Double.NaN == Double.NaN returns false
  2. Double.NaN.Equals(Double.NaN) returns true

I have the answer to the first part but not the second and not to "why are these two comparisons returning different values"

Upvotes: 43

Views: 3563

Answers (5)

Richard Ellingworth
Richard Ellingworth

Reputation: 1

I would avoid either of these operations. According to the Microsoft documentation for code analysis usage rules, rule CA2242 (Test for NaN correctly) says "To fix a violation of this rule and accurately determine whether a value represents System.Double.NaN, use System.Single.IsNaN or System.Double.IsNaN to test the value.". So I would suggest you use double.IsNaN(double.NaN) && double.IsNaN(double.NaN) which will always return true. Pointless example, but correct. I would suggest you avoid comparing doubles for equality at all. Round off errors can result in very small differences which nevertheless are enough to break equality. When comparing two doubles named a and b I would use something like: if( Math.Abs( a - b ) < 1e-20 ). Maybe this doesn't answer the question, but I think it needs to be said.

Upvotes: 0

Drew Noakes
Drew Noakes

Reputation: 311305

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.

Upvotes: 37

daryal
daryal

Reputation: 14929

if you inspect Double.NaN;

    // Summary:
    //     Represents a value that is not a number (NaN). This field is constant.
    public const double NaN = 0.0 / 0.0;

the first one returns false as NaN is not representing any number.

A method or operator returns NaN when the result of an operation is undefined. For example, the result of dividing zero by zero is NaN

The second one returns true as NaN equality is implemented explicitly in the overloaded equals method.

from msdn double.equals:

If two Double.NaN values are tested for equality by calling the Equals method, the method returns true. However, if two NaN values are tested for equality by using the equality operator, the operator returns false. When you want to determine whether the value of a Double is not a number (NaN), an alternative is to call the IsNaN method.

This is done delibaretly to conform with IEC 60559:1989;

According to IEC 60559:1989, two floating point numbers with values of NaN are never equal.However, according to the specification for the System.Object::Equals method, it's desirable to override this method to provide value equality semantics. Since System.ValueType provides this functionality through the use of Reflection, the description for Object.Equals specifically says that value types should consider overriding the default ValueType implementation to gain a performance increase. In fact from looking at the source of System.ValueType::Equals (line 36 of clr\src\BCL\System\ValueType.cs in the SSCLI), there's even a comment from the CLR Perf team to the effect of System.ValueType::Equals not being fast.

refer to: http://blogs.msdn.com/b/shawnfa/archive/2004/07/19/187792.aspx

Upvotes: 3

Soner G&#246;n&#252;l
Soner G&#246;n&#252;l

Reputation: 98858

Well, Oded's answer is great but I want to say something;

When I decompile Double.Equals() method, it seems like this;

public bool Equals(double obj)
{
    return ((obj == this) || (IsNaN(obj) && IsNaN(this)));
}

So since we have this = Double.NaN and obj = Double.NaN

(IsNaN(obj)) and (IsNaN(this)) returns `true`.

So basicly it is could return ((obj == this) || true

which is equvalent to

return ((obj == this) is true.

Upvotes: 3

Oded
Oded

Reputation: 499312

At the very bottom of the remarks section of Double.Equals, you will find:

If two Double.NaN values are tested for equality by calling the Equals method, the method returns true. However, if two NaN values are tested for equality by using the equality operator, the operator returns false. When you want to determine whether the value of a Double is not a number (NaN), an alternative is to call the IsNaN method.

Upvotes: 10

Related Questions