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 numbers and NaN. This explains the observations.
Questions:
- Why is the op_Equality defined on Double ? (And the implementation does not factor in the NaN specific behavior)
- When is it invoked ?