2012-07-10 7 views
15

tengo una cadena que puedo convertir a un doble de esta manera:"-Weverything" ceder "Comparación de punto flotante con == o = no es seguro!"

double d = [string doubleValue]; 

La documentación para doubleValue nos dice que ante un desbordamiento , este método devuelve HUGE_VAL o -HUGE_VAL. Así es como he comprobado para este anterior:

if (d == HUGE_VAL || d == -HUGE_VAL) 
    //overflow 

Ahora, puesto que la adición de la nueva "-Weverything" Bandera de alerta, el compilador se queja de que ahora

Comparing floating point with == or != is unsafe 

¿Cómo puedo resolver este problema? ¿Cómo debería Haré estas comparaciones?


que también tienen la misma pregunta sobre la comparación de dos números de coma flotante "normales" (es decir, no queridos "HUGE_VAL"). Por ejemplo,

double a, b; 
//... 
if (a != b) //this will now yield the same warning 
    //... 

¿Cómo se debe resolver esto?

Respuesta

29

Usted no necesita preocuparse por esta advertencia. No tiene sentido en muchos casos, incluido el tuyo.

La documentación de doubleValue no dice que devuelve algo lo suficientemente cerca de HUGE_VAL o -HUGE_VAL en caso de desbordamiento. Dice que devuelve exactamente estos valores en caso de desbordamiento. En otras palabras, el valor devuelto por el método en caso de desbordamiento se compara == con HUGE_VAL o -HUGE_VAL.

¿Por qué existe la advertencia en primer lugar?

Considere el ejemplo 0.3 + 0.4 == 0.7. Este ejemplo se evalúa como falso. Las personas, incluidos los autores de la advertencia que ha conocido, piensan que el punto flotante == es inexacto y que el resultado inesperado proviene de esta inexactitud.

Todos están mal.

El punto flotante además es "impreciso", por alguna sensación de inexactitud: devuelve el número de punto flotante representable más cercano para la operación que ha solicitado. En el ejemplo anterior, las conversiones (de decimal a coma flotante) y la suma de coma flotante son las causas del comportamiento extraño.

El punto flotante igualdad, por el contrario, funciona exactamente igual que para otros tipos discretos.La igualdad de coma flotante es exacta: salvo excepciones menores (el valor NaN y el caso de +0. Y -0), la igualdad se evalúa como verdadera si y solo si los dos números de coma flotante considerados tienen la misma representación.

No necesita un épsilon para probar si dos valores de coma flotante son iguales. Y, como Dewar says in substance, la advertencia en el ejemplo 0.3 + 0.4 == 0.7 debe estar en +, no en ==, para que la advertencia tenga sentido.

Por último, la comparación con dentro de un épsilon significa que los valores que no son iguales se verán iguales, lo que no es apropiado para todos los algoritmos.

+0

Tiene sentido. Por otro lado, también parece tener sentido advertir sobre esto, de alguna manera. ¿Hay alguna manera de decirle al compilador de manera más explícita que: "Sí, estoy absolutamente seguro de que estoy comparando estos flotadores como siendo exactamente iguales entre sí, y no me advierta". ? Entonces, en casos donde estoy seguro, la advertencia no aparecerá. En otros casos, yo haría la prueba épsilon. – NoobOverflow

+0

@NoobOverflow Si realmente deseas hacer feliz al compilador, prueba si 'd> = HUGE_VAL || d <= -HUGE_VAL'. Calcula lo mismo sin usar '=='. Pero recomiendo no usar la advertencia. –

+0

@NoobOverflow En realidad, mi recomendación anterior hace que el código sea menos legible, pero si Objective-C tiene una función 'is_infinity', usar eso haría que el código ** fuera más legible. La especificación de la función debería ser que devuelve verdadero exactamente para los dos valores 'HUGE_VAL' y' -HUGE_VAL', y recomiendo que lo use simplemente para eso. –

-1

Los flotantes no se deben comparar con == o! = Debido a la inexactitud del tipo de flotación, lo que podría ocasionar errores inesperados al utilizar estos operadores. Debería probar si los flotadores se encuentran a una distancia entre ellos (llamado "Epsilon" la mayor parte del tiempo).

Se podría tener este aspecto:

const float EPSILON = 1.0f; // use a really small number instead of this 

bool closeEnough(float f1, float f2) 
{ 
    return fabs(f1-f2)<EPSILON; 
    // test if the floats are so close together that they can be considered equal 
} 
+1

Lo épsilon se puede recomendar? ¿Este enfoque también funcionará con esos HUGE_VALs? ¿Y su respuesta implica que el comentario anterior de Pascal es incorrecto? – NoobOverflow

+0

Además, ¿no hay alguna buena función incorporada como esta que pueda usar? Es una lástima que tenga que esconder mi propia función personalizada en algún lugar global. – NoobOverflow

+0

Pascal tiene razón, probablemente no tenga que preocuparse por esta advertencia. Sin embargo, hay un épsilon incorporado, eche un vistazo a [esto] (http://www.cplusplus.com/reference/std/limits/numeric_limits/) – Brainbot

8

En este caso, intente utilizar >= y <=.

+3

¿Por qué es eso mejor? –

+3

Bueno, no se compara para la igualdad estricta, por lo que pacifica el compilador.Y como nada puede ser mayor que HUGE_VAL o menor que -HUGE_VAL, funciona igual. – echristopherson

2

Si no está seguro acerca de su comparación y quieres dilo a clang, rodear con su código:

#pragma clang diagnostic ignored "-Wfloat-equal" 
/* My code triggering the warnings */ 
#pragma clang diagnostic pop 
Cuestiones relacionadas