41

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"

Community
  • 1
  • 1
GETah
  • 20,922
  • 7
  • 61
  • 103
  • 2
    Might be a stupid comment, but I would say that in case 1, you are comparing values. And in case 2 you are comparing references. – jbl Jan 22 '13 at 12:50
  • 4
    @jbl No, you’re comparing values in both cases – `double`s aren’t references and you’re not even boxing since [`System.Double.Equals`](http://msdn.microsoft.com/en-us/library/ya2zha7s.aspx) is overloaded. – Konrad Rudolph Jan 22 '13 at 12:52
  • @spender OMFG I should read the question better! Thanks! – RB. Jan 22 '13 at 12:53
  • @RB. Actually, I suspect that this might *still* be the correct reason. I would have guessed the same thing. – Konrad Rudolph Jan 22 '13 at 12:54
  • @RB I imagine the issues are broadly similar though. – spender Jan 22 '13 at 12:54
  • The same stands for `float`. – Alex Filipovici Jan 22 '13 at 12:56
  • 1
    This has nothing to do with reference/value types. It's about semantics. If you override `Equals`, you have to maintain a contract. See my answer. – Drew Noakes Jan 22 '13 at 13:01
  • I'd like to add, since no other answer did, that NaN represents a mathematical concept, which you can arrive at in multiple ways (e.g., sqrt(-1), 0/0, etc.), testing its equivalence against a real number is [mathematically invalid](https://en.wikipedia.org/wiki/NaN). *However*, if we were to consider NaN not a value, but a *state* of a double, then you might be able to make the hands waving statement that "a double object in the state of NaN is equal to another object in the state of NaN". For `==`, c# chose the former, for `Equals` C# chose the latter. – jrh Feb 26 '18 at 19:07
  • Here's something funny: `double.NaN.Equals(float.NaN)` is true, but `float.NaN.Equals(double.NaN)` is false. Well... actually, it's not funny. – geekley Mar 09 '21 at 21:42

5 Answers5

35

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.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
  • 1
    Ah. Finally. :-) (I’d like very much to get a proper reference for the claim here but I believe this is the correct answer (the contract part definitely is), so +1). – Konrad Rudolph Jan 22 '13 at 13:02
  • 1
    Yes I should point out that I don't have a reference. It's just the only reason that makes sense to me. – Drew Noakes Jan 22 '13 at 13:04
  • 1
    +1. Can you please provide a ref to IEEE test for equality? I couldn't find it anywhere – GETah Jan 22 '13 at 13:22
  • 11
    For completeness, this is given in a note in ECMA-335 I.8.2.5.2 "Equality is implemented on System.Object via the Equals method. [Note: Although two floating point NaNs are defined by IEC 60559:1989 to always compare as unequal, the contract for System.Object.Equals requires that overrides must satisfy the requirements for an equivalence operator. Therefore, System.Double.Equals and System.Single.Equals return True when comparing two NaNs, while the equality operator returns False in that case, as required by the IEC standard. end note]" – R. Martinho Fernandes Jan 22 '13 at 13:44
  • 5
    Excellent reasoning. We don't link to references here, we create them. – Hans Passant Jan 22 '13 at 13:47
  • Very good answer. There is however one addition worth mentioning. When we use `double` as key in a `Dictionary<,>`, also the `GetHashCode()` implementation is important. There are however in IEEE many different binary representations of `NaN` (and they come in two categories, quiet NaN and signaling NaN). The `Equals` of .NET considers them all to be equal. Therefore it is a requirement that `GetHashCode` agrees on all those. But it doesn't. See [this (closed) thread started by my](http://stackoverflow.com/questions/14281911/) for details. – Jeppe Stig Nielsen Jan 25 '13 at 18:53
  • It is not always a desirable feature to be able to use Double.NaN as a unique key in a map. See http://research.swtch.com/randhash for an interesting discussion where NaN values are assigned random hash values. – Zayenz Jan 29 '13 at 09:30
  • @Zayenz: That's really horrid. Lookup-based collections only make sense for types with defined equivalence relations. If certain objects shouldn't be retrievable from a collection, why are they being stored there in the first place? – supercat Aug 14 '13 at 22:19
  • @supercat Well, since one might want to use doubles as keys sometimes, it becomes necessary to handle NaN keys. Since NaN is defined to not be equal to itself, there is little else one could do. The suggested way of handling it avoids avoids linear time complexity for linked chain hash-tables where lots of NaNs are stored in a simple way. Whether NaN should be non-equal to itself, or whether doubles makes sense as keys in a collection is another question. – Zayenz Aug 15 '13 at 08:22
  • @Zayenz: If doubles are going to be used as keys, one should either wrap them or specify a comparator such that NaN compares equal to itself, or else modify wrap the collection in something that will not accept anything that doesn't compare equal to itself (depending upon semantics, such an item may be silently discarded or throw an exception). If one is really stuck with the code that operates on the collection, I suppose jinxing the hash function may be a clever way to patch things to kinda sorta work, but from a design standpoint it's really hideous. – supercat Aug 15 '13 at 15:15
  • @Zayenz: As for whether different kinds of NaN values should compare equal to each other, that's something of another issue. Personally, my philosophy is that proper "universal standard" for overriding `Object.Equals` should be to test whether objects should be considered indistinguishable; (Object)(0.0/0.0).Equals((Object)(0.0/0.0)) should be true, but (Object)(1.0/(1.0/0.0)).Equals((Object)(-1.0/(1.0/0.0)) should be false [positive and negative zero represent numerically-indistinguishable quantities, but do not behave as indistinguishable quantities when divided into zero]. – supercat Aug 15 '13 at 15:21
9

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.

Oded
  • 489,969
  • 99
  • 883
  • 1,009
3

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

daryal
  • 14,643
  • 4
  • 38
  • 54
  • 2
    The question was **why** the two methods yield different results. You didn’t answer that. – Konrad Rudolph Jan 22 '13 at 12:55
  • I do believe I have answered; NaN is not defined, does not represent any number, it is undefined. Talking about equality is not possible; but equals method defines an equality between two NaN values. – daryal Jan 22 '13 at 12:58
  • 2
    *Why* is `Equals` defined like this? You are simply [begging the question](https://en.wikipedia.org/wiki/Begging_the_question). – Konrad Rudolph Jan 22 '13 at 13:00
  • have you read the further updates? if you have further questions I can answer. read the link I have posted in the end please before. – daryal Jan 22 '13 at 13:03
  • The linked article indeed contains the explanation. However, the quote you’ve pulled out isn’t relevant. – Konrad Rudolph Jan 22 '13 at 13:07
  • "Represents **a** value" is the key here. IIRC, there are 6 bit patterns for NaN. – leppie Jan 22 '13 at 13:57
  • 1
    @daryal: If the `==` operator is supposed to answer the question "should X be considered indistinguishable from Y", then the answer to that question should be true if X and Y are both NaN. I'm not really sure what useful question `==` can answer with the IEEE semantics, since the fact that two floating-point variables hold the same nominal value doesn't mean they both represent the same quantity--merely that the quantities represented are indistinguishable. – supercat Aug 14 '13 at 22:13
3

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.

Community
  • 1
  • 1
Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
0

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.