It all started with a trick question that someone posed to me.. (It's mentioned in the book - C# in a nutshell) Here's the gist of it.

Double a = Double.NaN;
Console.WriteLine(a == a); // => false
Console.WriteLine(a.Equals(a)); // => true

The above doesn't seem right. a should always be == to itself (reference equality) & both should be consistent.

Seems like Double overloads the == operator. Confirmed by reflector as follows:

[__DynamicallyInvokable]
public static bool operator ==(double left, double right)
{
    return (left == right);
}

Strange that looks recursive and no mention of the NaN specific behavior. So why does it return false?

So I add some more code to distinguish

var x = "abc";
var y = "xyz";
Console.WriteLine(x == y); // => false

Now I see

    L_0001: ldc.r8 NaN
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: ldloc.0 
    L_000d: ceq 
    L_000f: call void [mscorlib]System.Console::WriteLine(bool)
    L_0014: nop 
    L_0015: ldloca.s a
    L_0017: ldloc.0 
    L_0018: call instance bool [mscorlib]System.Double::Equals(float64)
    L_001d: call void [mscorlib]System.Console::WriteLine(bool)
    L_0022: nop 
    L_0023: ldstr "abc"
    L_0028: stloc.1 
    L_0029: ldstr "xyz"
    L_002e: stloc.2 
    L_002f: ldloc.1 
    L_0030: ldloc.2 
    L_0031: call bool [mscorlib]System.String::op_Equality(string, string)
    L_0036: call void [mscorlib]System.Console::WriteLine(bool)
  • for doubles, the == operator call translates to a ceq IL opcode
  • where as for strings, it translates to System.String::op_Equality(string, string).

Sure enough the documentation for ceq specifies that it is special-cased for floating point num

Edit
Report