Friday, 15 January 2010

c# - When is Double's == operator invoked? -



c# - When is Double's == operator invoked? -

it started trick question posed me.. (it's mentioned in book - c# in nutshell) here's gist of it.

double = double.nan; console.writeline(a == a); // => false console.writeline(a.equals(a)); // => true

the above doesn't seem right. should == (reference equality) & both should consistent.

seems double overloads == operator. confirmed reflector follows:

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

strange looks recursive , no mention of nan specific behavior. why homecoming false?

so add together more code distinguish

var x = "abc"; var y = "xyz"; console.writeline(x == y); // => false

now see

l_0001: ldc.r8 nan l_000a: stloc.0 l_000b: ldloc.0 l_000c: ldloc.0 l_000d: ceq l_000f: phone call void [mscorlib]system.console::writeline(bool) l_0014: nop l_0015: ldloca.s l_0017: ldloc.0 l_0018: phone call instance bool [mscorlib]system.double::equals(float64) l_001d: phone 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: phone call bool [mscorlib]system.string::op_equality(string, string) l_0036: phone call void [mscorlib]system.console::writeline(bool) for doubles, == operator phone call translates ceq il opcode where strings, translates system.string::op_equality(string, string).

sure plenty documentation ceq specifies special-cased floating point numbers , nan. explains observations.

questions:

why op_equality defined on double ? (and implementation not factor in nan specific behavior) when invoked ?

reflector's erroneous interpretation

the decompilation seeing reflector bug in reflector. reflector needs able decompile function 2 doubles beingness compared; in functions, find ceq emitted right code. result, reflector interprets ceq instruction == between 2 doubles help decompile function 2 doubles beingness compared.

by default, value types don't come == implementation. (don't user-defined structs inherit overloaded == operator?) however, of built-in scalar types have explicitly overloaded operator compiler translates appropriate cil. overload contains simple ceq based comparison, dynamic/late-bound/reflection-based invokes of == operator overload won't fail.

more details

for predefined value types, equality operator (==) returns true if values of operands equal, false otherwise. reference types other string, == returns true if 2 operands refer same object. string type, == compares values of strings.

-- http://msdn.microsoft.com/en-us/library/53k8ybth.aspx

what said implies == uses reference type semantics comparing of double. however, since double value type, uses value semantics. why 3 == 3 true, though they're different stack objects.

you can think of compiler translation how linq's queryable object contains extension methods with code in them, compiler translates these calls look trees passed linq provider instead. in both cases, underlying function never gets called.

double's comparing semantics

the documentation double allude how ceq cil instruction works:

if 2 double.nan values tested equality calling equals method, method returns true. however, if 2 nan values tested equality using equality operator, operator returns false. when want determine whether value of double not number (nan), alternative phone call isnan method.

-- http://msdn.microsoft.com/en-us/library/ya2zha7s.aspx

raw compiler source

if in decompiled c# compiler source, you'll find next code handle direct translation of double comparisons ceq:

private void emitbinarycondoperator(boundbinaryoperator binop, bool sense) { int num; constantvalue constantvalue; bool flag = sense; binaryoperatorkind kind = binop.operatorkind.operatorwithlogical(); if (kind <= binaryoperatorkind.greaterthanorequal) { switch (kind) { ... case binaryoperatorkind.equal: goto label_0127; ... } } ... label_0127: constantvalue = binop.left.constantvalue; if (((constantvalue != null) && constantvalue.isprimitivezeroornull) && !constantvalue.isfloating) { ... return; } constantvalue = binop.right.constantvalue; if (((constantvalue != null) && constantvalue.isprimitivezeroornull) && !constantvalue.isfloating) { ... return; } this.emitbinarycondoperatorhelper(ilopcode.ceq, binop.left, binop.right, sense); return; }

the above code roslyn.compilers.csharp.codegen.codegenerator.emitbinarycondoperator(...), , added "..."'s in order create code more readable purpose.

c# .net

No comments:

Post a Comment