I am stuck trying to find out why these two operations return different values:
Double.NaN == Double.NaN
returns false
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"
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.
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.
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
.
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