Pregunta

Sé que normalmente no puede confiar en la igualdad entre valores de tipo doble o decimal, pero me pregunto si 0 es un caso especial.

Si bien puedo entender las imprecisiones entre 0.00000000000001 y 0.00000000000002, 0 en sí mismo parece bastante difícil de confundir, ya que no es nada. Si no eres preciso en nada, ya no es nada.

Pero no sé mucho sobre este tema, así que no me corresponde decirlo.

double x = 0.0;
return (x == 0.0) ? true : false;

¿Eso siempre será cierto?

¿Fue útil?

Solución

Es seguro esperar que la comparación arroje true si y solo si la variable doble tiene un valor exactamente 0.0 (que en su fragmento de código original es, por supuesto, el caso). Esto es consistente con la semántica del operador ==. a == b significa " a es igual a b " ;.

no es seguro (porque es incorrecto ) esperar que el resultado de algún cálculo sea cero en aritmética doble (o más generalmente, de coma flotante) siempre que el resultado del mismo cálculo en Matemática pura sea cero. Esto se debe a que cuando los cálculos llegan al suelo, aparece un error de precisión de coma flotante, un concepto que no existe en la aritmética de números reales en Matemáticas.

Otros consejos

Si necesita hacer mucho " igualdad " comparaciones, podría ser una buena idea escribir una pequeña función auxiliar o método de extensión en .NET 3.5 para comparar:

public static bool AlmostEquals(this double double1, double double2, double precision)
{
    return (Math.Abs(double1 - double2) <= precision);
}

Esto podría usarse de la siguiente manera:

double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);

Para su muestra simple, esa prueba está bien. Pero qué pasa con esto:

bool b = ( 10.0 * .1 - 1.0 == 0.0 );

Recuerde que .1 es un decimal repetido en binario y no se puede representar exactamente. Luego compare eso con este código:

double d1 = 10.0 * .1; // make sure the compiler hasn't optimized the .1 issue away
bool b = ( d1 - 1.0 == 0.0 );

Te dejaré que realices una prueba para ver los resultados reales: es más probable que lo recuerdes de esa manera.

De la entrada de MSDN para Double.Equals :

  

Precisión en las comparaciones

     

El método Equals debe usarse con   precaución, porque aparentemente dos   los valores equivalentes pueden ser desiguales debido   a la precisión diferente de los dos   valores. El siguiente ejemplo informa   que el valor doble .3333 y el   El doble devuelto dividiendo 1 por 3 son   desigual.

     

...

     

En lugar de comparar por igualdad,   una técnica recomendada implica   definiendo un margen aceptable de   diferencia entre dos valores (como   .01% de uno de los valores). Si el   valor absoluto de la diferencia   entre los dos valores es menor o   igual a ese margen, la diferencia   es probable que se deba a diferencias en   precisión y, por lo tanto, los valores   Es probable que sean iguales. El seguimiento   ejemplo utiliza esta técnica para comparar   .33333 y 1/3, los dos valores dobles   que el ejemplo de código anterior encontró   ser desigual.

Además, consulte Double.Epsilon .

El problema surge cuando se comparan diferentes tipos de implementación de valores de coma flotante, p. comparando flotador con doble. Pero con el mismo tipo, no debería ser un problema.

float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true

El problema es que el programador a veces olvida que está ocurriendo la conversión implícita de tipo (doble a flotante) para la comparación y resulta en un error.

Si el número se asignó directamente al flotante o al doble, entonces es seguro realizar una prueba contra cero o cualquier número entero que pueda representarse en 53 bits para un doble o 24 bits para un flotante.

O, para decirlo de otra manera, siempre puede asignar un valor entero a un doble y luego comparar el doble con el mismo entero y garantizar que será igual.

También puede comenzar asignando un número entero y hacer que las comparaciones simples continúen trabajando sumando, restando o multiplicando por números enteros (suponiendo que el resultado sea inferior a 24 bits para un valor flotante y 53 bits para un doble) . Por lo tanto, puede tratar los flotadores y los dobles como enteros bajo ciertas condiciones controladas.

No, no está bien. Los denominados valores desnormalizados (subnormal), cuando se comparan igual a 0.0, se compararían como falsos (distintos de cero), pero cuando se usan en una ecuación se normalizarían (se convertirían en 0.0). Por lo tanto, usar esto como un mecanismo para evitar una división por cero no es seguro. En su lugar, agregue 1.0 y compárelo con 1.0. Esto asegurará que todas las subnormales sean tratadas como cero.

Pruebe esto, y encontrará que == no es confiable para double / float.
double d = 0.1 + 0.2; bool b = d == 0.3;

Aquí está el respuesta de Quora.

En realidad, creo que es mejor usar los siguientes códigos para comparar un valor doble contra 0.0:

double x = 0.0;
return (Math.Abs(x) < double.Epsilon) ? true : false;

Lo mismo para flotante:

float x = 0.0f;
return (Math.Abs(x) < float.Epsilon) ? true : false;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top