usar usa unario que para operadores operador logicos como asignacion c# .net

c# - usa - ¿Cuándo se invoca el operador== de Double?



operadores logicos para string c# (3)

Todo comenzó con una pregunta trampa que alguien me hizo ... (Se menciona en el libro - C # en pocas palabras) Aquí está la esencia de esto.

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

Lo anterior no parece correcto. a siempre debe ser == para sí mismo (igualdad de referencia) y ambos deben ser coherentes.

Parece que Doble sobrecarga el operador ==. Confirmado por el reflector de la siguiente manera:

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

Extraño que parece recursivo y no menciona el comportamiento específico de NaN. Entonces, ¿por qué devuelve falso?

Así que agrego un poco más de código para distinguir

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

Ahora veo

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)

  • para los dobles, la llamada del operador == se traduce a un código de operación ceq IL
  • donde en cuanto a cadenas, se traduce a System.String :: op_Equality (cadena, cadena).

Por supuesto, la documentación para ceq especifica que está especialmente especificada para números de punto flotante y NaN. Esto explica las observaciones.

Preguntas:

  • ¿Por qué se define la op_Equality en Double? (Y la implementación no tiene en cuenta el comportamiento específico de NaN)
  • ¿Cuándo se invoca?

La interpretación errónea del reflector

La descompilación que está viendo desde Reflector es en realidad un error en Reflector. El reflector debe poder descompilar una función donde se comparan dos dobles; en esas funciones, encontrará ceq emitido directamente en el código. Como resultado, Reflector interpreta una instrucción ceq como == entre dos dobles para ayudar a descompilar una función donde se comparan dos dobles.

De forma predeterminada, los tipos de valor no vienen con una implementación ==. ( ¿Las estructuras definidas por el usuario no heredan un operador == sobrecargado? ) Sin embargo, todos los tipos escalares incorporados tienen un operador sobrecargado explícitamente que el compilador traduce al CIL apropiado. La sobrecarga también contiene una comparación simple basada en ceq , por lo que las ceq dinámicas / vinculadas tardías / basadas en la reflexión de la sobrecarga del operador == no fallarán.

Más detalles

Para tipos de valores predefinidos, el operador de igualdad (==) devuelve verdadero si los valores de sus operandos son iguales, de lo contrario, falso. Para tipos de referencia distintos a la cadena, == devuelve verdadero si sus dos operandos se refieren al mismo objeto. Para el tipo de cadena, == compara los valores de las cadenas.

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

Lo que dijiste implica que == usa semántica de tipo de referencia para comparar un double . Sin embargo, dado que el double es un tipo de valor, utiliza la semántica del valor. Esta es la razón por la cual 3 == 3 es cierto, aunque son objetos de pila diferentes.

Casi se puede pensar en esta traducción del compilador como la forma en que el objeto Queryable de LINQ contiene métodos de extensión con código, pero el compilador traduce estas llamadas en árboles de expresión que se pasan al proveedor de LINQ. En ambos casos, la función subyacente nunca se llama realmente.

Semántica de comparación de dobles.

La documentación de Double hace alusión a cómo funciona la instrucción ceq CIL:

Si dos valores Double.NaN se prueban para determinar su igualdad llamando al método Equals, el método devuelve true. Sin embargo, si dos valores de NaN se prueban para determinar la igualdad mediante el uso del operador de igualdad, el operador devuelve falso. Cuando desea determinar si el valor de un Doble no es un número (NaN), una alternativa es llamar al método IsNaN.

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

Fuente compiladora cruda

Si observa la fuente del compilador C # descompilado, encontrará el siguiente código para manejar la traducción directa de comparaciones dobles en 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; }

El código anterior es de Roslyn.Compilers.CSharp.CodeGen.CodeGenerator.EmitBinaryCondOperator(...) , y agregué los "..." para hacer que el código sea más legible para este propósito.


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

Si dos valores Double.NaN se prueban para determinar su igualdad llamando al método Equals, el método devuelve true. Sin embargo, si dos valores de NaN se prueban para determinar la igualdad mediante el uso del operador de igualdad, el operador devuelve falso. Cuando desea determinar si el valor de un Doble no es un número (NaN), una alternativa es llamar al método IsNaN.


En http://msdn.microsoft.com/en-us/library/ya2zha7s.aspx se afirma que;

Si dos valores Double.NaN se prueban para determinar su igualdad llamando al método Equals, el método devuelve true. Sin embargo, si dos valores de NaN se prueban para determinar la igualdad mediante el uso del operador de igualdad, el operador devuelve falso. Cuando desea determinar si el valor de un Doble no es un número (NaN), una alternativa es llamar al método IsNaN.

Esto se realiza de forma detallada para cumplir con la norma IEC 60559: 1989, ya que establece que dos valores de NaN no son iguales ya que no se tratan como números, por op_Equal definición op_Equal cumple con este estándar;

De acuerdo con IEC 60559: 1989, dos números de punto flotante con valores de NaN nunca son iguales. Sin embargo, de acuerdo con la especificación para el método System.Object :: Equals, es conveniente anular este método para proporcionar semántica de igualdad de valores. Dado que System.ValueType proporciona esta funcionalidad mediante el uso de Reflection, la descripción de Object.Equals dice específicamente que los tipos de valor deberían considerar anular la implementación predeterminada de ValueType para obtener un aumento de rendimiento. De hecho, al mirar la fuente de System.ValueType :: Equals (línea 36 de clr / src / BCL / System / ValueType.cs en el SSCLI), incluso hay un comentario del equipo de CLR Perf al efecto de System.ValueType :: Es igual a no ser rápido.

consulte: http://blogs.msdn.com/b/shawnfa/archive/2004/07/19/187792.aspx