2010-03-04 17 views
24

Sé que no podemos comparar 2 valores de coma flotante con ==. Solo podemos comparar que están dentro de algún intervalo el uno del otro. Sé¿Se pueden comparar valores de punto flotante exactamente a cero?

if(val == 0.512) 

es incorrecto debido a errores inherentes a los cálculos de punto flotante y la conversión a binario y debería ser

if (val in (0.512-epsilon, 0.512+epsilon)) 

Pero es 0 especial? ¿Podemos comparar flotadores exactamente a 0? O incluso eso es incorrecto? Particularmente en el contexto de C# y Java?

double val = 0; 
val = getVal(); 
if(val == 0) 
+1

pedantería matemática: es epsilon, no ephsilon. buena pregunta, sin embargo. – Carl

+7

Por supuesto, puede comparar dos valores de coma flotante usando la igualdad exacta. Para ciertos propósitos restringidos, no es lo que quieres hacer, pero decir que "no puedes" hacerlo es una tontería, pura y simple, y evita que los desarrolladores aprendan acerca de la semántica real del punto flotante. –

+1

@Carl: ¡Gracias por la pedantería griega! editó la publicación. Estoy tan acostumbrado a escribir (U + 0395) ε, ¡no sabía la ortografía exacta! – Fakrudeen

Respuesta

17

Aunque 0 tiene una representación exacta, no puede confiar en que el resultado de un cálculo con flotantes sea exactamente 0. Como ha indicado, esto se debe al cálculo de punto flotante y problemas de conversión.

Por lo tanto, debe probar 0 en contra de su épsilon de tolerancia.

+0

Prácticamente todas las respuestas me aconsejaron sobre la carcasa especial 0. Gracias ! Aceptando el primero [en orden predeterminado]. – Fakrudeen

+2

@Fakrudeen: orden por defecto s por puntaje primero, luego al azar. –

2

Todavía recomendaría seguir el idioma de tolerancia y no comparar exactamente con cero.

12

Puede comparar con cero si asignó esa variable a cero. Si obtiene cero de, por ejemplo. una resta aún puede obtener un número muy pequeño cerca de cero. ej .: 0.1-0.1 puede evaluar algo así como 1e-9.

0

No creo que pueda en general, el cálculo que se produce en getVal() lógicamente puede dar como resultado cero, pero eso no significa que devolverá cero. Si explicilty devuelve un cero para indicar alguna condición, la comparación siempre debería funcionar, pero no creo que sea una buena práctica. Modificaría la función para devolver un código de estado y pasar el valor que se cambiará por refrendo.

3

Como cero tiene una representación exacta, es posible que un valor compare == con cero. Si la variable que está probando fue establecida por una asignación, o desde un valor ingresado (como getVal en su ejemplo?), Fácilmente podría ser cero. Pero si fue el resultado de un cálculo, las posibilidades de que sea exactamente cero son muy pequeñas. Esto empeora porque fracciones decimales ordinarias como 0.2 no tienen una representación exacta en coma flotante. Es por eso que es mejor usar épsilon.

13

Utilice tolerancia/ephsilon enfoque.

acabo evaluaron los siguientes en Java, lo que matemáticamente se traduce en cero:

1.0/5.0 + 1.0/5.0 - 1.0/10.0 - 1.0/10.0 - 1.0/10.0 - 1.0/10.0 

y en realidad tiene

2.7755575615628914E-17 
+5

+1 para proporcionar un ejemplo real. –

4

Para la comparación con err todo lo que necesita es.

// compare a and b with an ERR error. 
if (Math.abs(a - b) <= ERR) 

Para comparar con 0

// compare a and 0 with an ERR error. 
if (Math.abs(a) <= ERR) 
+0

¿Qué es 'ERR'? – Jess

+1

@Jess Su error aceptable, por ejemplo, 'estático final doble ERR = 1e-6' –

+1

Oh, pensé que era algún tipo de acrónimo. ¿Quizás cambiar el nombre a ErrorTolerance? O ZeroTolerance sería divertido: D! – Jess

0

En cualquier situación no trivial, realmente debería utilizar sólo el enfoque de tolerancia. Como se señaló, la comparación cero solo es precisa cuando realmente la asignó a cero.

Sin repetir lo que otros han dicho, solo quiero enfatizar el hecho de que usar el enfoque de tolerancia es más prueba futura. Lo que una vez piensas que es una tarea simple puede implicar una aritmética real más adelante. Usar una comparación simple hace que sea dolorosamente oscuro depurar en una fecha posterior.

Cuestiones relacionadas