2011-08-24 16 views
24

Tengo el siguiente código:¿Está comprobando un doble para la igualdad siempre segura?

double x = 0; 

{ ...do stuff ...} 

if(x == 0){ 

} 

Siempre me enseñaron que no se debe comprobar flotadores para la igualdad. ¿Está comprobando si es diferente a cero?

+0

no entiendo, si inicia x a 0 ¿por qué no es bueno comprobar si 0? 0 es un valor válido para el doble – JohnJohnGa

+1

Los números de punto flotante tienen un montón de redondeos cuando comienza a alcanzar los límites. La misma razón que si tiene 3 dígitos para usar en la base diez, tiene 0.004 y se divide entre tres, espera 0.00, pero quién sabe qué sucede. –

+0

Correcciones de Thomas: Técnicamente no es redondeado, pero es inexacta debido a la precisión limitada y la naturaleza binaria de los flotadores. –

Respuesta

27

La razón por la que no debería verificarse la igualdad de flotadores es que los números de punto flotante no son perfectamente precisos: hay cierta inexactitud en el almacenamiento con algunos números, como los extendidos demasiado lejos en la mantisa y los decimales Estoy hablando de repetir decimales en la base 2). Puedes pensar en esta imprecisión como "redondeando hacia abajo". Los dígitos que se extienden más allá de la precisión del número de coma flotante se truncan, redondeando efectivamente hacia abajo.

Si no ha cambiado, mantendrá esa igualdad. Sin embargo, si lo cambia ligeramente, probablemente no debería usar igualdades, sino un rango como (x < 0.0001 && x > -.0001).

En resumen: siempre y cuando no juegue con x en un nivel muy pequeño, está bien.

+6

No está pasando el redondeo, sino la incapacidad de almacenar ciertos números debido a la representación de los números de coma flotante. 0 puede representarse exactamente mediante un valor de coma flotante, pero no todos los valores pueden. 0.1, por ejemplo, tiene que ser aproximado. –

+1

@Thomas Redondeando hacia abajo. La misma razón que '3/2' es' 1' –

+7

No, no se redondea. Imprecisiones en representaciones de punto flotante IEEE. No tiene absolutamente nada que ver con el redondeo. http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems –

16

Es seguro si el 0 que intenta atrapar es el 0 original en la inicialización. Sin embargo, no es seguro si espera un 0 de una operación matemática.

+0

cuál debe ser el enfoque correcto cuando quiere comparar 0 desde la operación matemática –

+0

Ver la respuesta aceptada. – Vache

4

Aún no debería verificar si es igual a cero. Solo verifica si está cerca de cero.

private final static double EPSILON = 0.00001; 
if (x + EPSILON > 0 && x - EPSILON < 0){ 
... 
} 
+3

No debe usar un epison absoluto sino uno relativo. E.G., 'if (value> = target * (1 - epsilon) && value <= target * (1 + epsilon))' Esto es especialmente cierto cuando los valores pueden variar en un rango grande. –

+2

@HovercraftFullOfEels Esto funcionará solo si el objetivo es positivo. –

4

si establece usted mismo y desea ver si alguna vez se cambió se puede comprobar de forma segura por la igualdad (como usar un valor centinela), aunque NaN es más seguro para ese tipo de cosas

float x=Float.NaN; 
{ 
    //some code that may or may not set x 
} 
if(Float.isNaN(x))//it never got set 
2

doble tiene cero positivo y negativo. == entre cero positivo y cero negativo devuelve falso. Además, == entre dos NaNs devuelve falso.

Cuestiones relacionadas