¿Por qué usar ‘==’ para comparar decimales es un error?

Hoy por hoy, muchos desarrolladores de software utilizan ‘==’ para comparar si dos valores numéricos son iguales o no, esta práctica se hace sin mediar consecuencias y así sin más; y es comprensible, ¿a cuántos no nos han dicho que si queremos comparar si dos números son iguales, hay que utilizar ‘==’?

Pero cuando hacemos un análisis a fondo, y aprendemos como funciona un procesador; nos daremos cuenta que muchas prácticas utilizadas por nosotros a la hora de escribir código no son las adecuadas, y entre esas prácticas está el usar ‘==’ para comprar decimales.

Como muchos de ustedes sabe que el operador lógico ‘==’ se utiliza para saber si dos valores son iguales.

int x = 5;
int y = 5;
if(x == y){}

 

Hasta ahí, todo perfecto, el problema radica en que este operador funciona perfecto y SIN ERRORES cuando utilizamos valores discretos como los son los enteros. Se dice que los enteros son discretos porque entre A y B (1 y 2) no hay valores intermedios.

int A = 1;
//There are no values between A and B
int B = 2;

Pero al implementar valores continuos puede que el operador ‘==’ no funcione como lo esperamos. Se dice que los decimales son continuos porque entre A y B(1 y 2) pueden haber valores intermedios.

float A = 1;
float C = 1.5;//C is between A and B
float B = 2;

Los compiladores y la FPU (floating-point unit) no tienen una forma única de representar valores numéricos, por lo cual hacen ciertas tareas de redondeo para obtener un valor cercano al que esperamos.

/*Can be the following value: 
1.500000000000000000000001.*/
float A = 1.5;
/*Can be the following value: 
1.499999999999999999999999.*/
float B = (2) - 0.5;

Como podemos ver, para el lenguaje de programación A y B son 1.5, pero la FPU (que hace parte de nuestro procesador) hace un redondeo para aproximar a A y B a el valor de 1.5, sin embargo, el valor guardado en nuestro sistema sigue siendo el original:1.499999999999999999999999 para B y 1.500000000000000000000001 para A.

/*Can be the following value: 
1.500000000000000000000001.*/
float A = 1.5;
/*Can be the following value: 
1.499999999999999999999999.*/
float B = (2) - 0.5;
if(A == B){
    myApp.peace(Country.ALL);
}else{
    myApp.startWWIII(Country.USA, Country.KOREA)
}

Cuando utilizamos ‘==’ para comparar decimales, le estamos diciendo a nuestro procesador que COMPARE LOS VALORES ORIGINALES que están almacenados en nuestro sistema; nosotros esperábamos que hubiera PAZ, pero iniciamos la tercera guerra mundial.

Esto es un gran problema (y a la vez peligroso) cuando trabajamos con software financiero o que maneje demasiados procesos con valores decimales, y es que es verdad que esto ocurre en muy pocas ocasiones, pero cuando sucede es muy difícil de detectar el BUG ya que no veríamos el error lógico en nuestro código.

¿Entonces cómo comparar decimales?.

Para comparar valores decimales, se DEBEN utilizar los operadores < ó >, los operadores <= y >= usan la igualdad y podríamos recaer en el mismo problema que estamos evitando. Lo recomendable para hacer comparaciones de decimales es evaluar las situaciones, posibles escenarios y sector al que está dirigida nuestra aplicación; ya que no es lo mismo un error de 0.0000001 mg en una dosis de cianuro que 0.0000001 una (unidades astronómicas) recorridas por una sonda espacial.

Cuando ya tenemos evaluado cuál es el margen de diferencia máximo en que no se afecta nuestra solución, podemos crear una función para comparar los decimales.

EJEMPLO: según un estudio químico.
1,000000 mg de una dosis puede curar a una persona.
1,00001 mg de la misma dosis es totalmente letal para una persona.

boolean compareDosage(double dosageA, double dosageB){
    float ACCEPTABLE_ERROR = 0.000001;
    return(Math.abs(dosageA -dosageB) < ACCEPTABLE_ERROR)
}

En el ejemplo de comparar dosis de cianuro, hay una función que verifica si dos dosis son iguales, en caso que la diferencia entre dos dosis sea mayor a 0.000001, y por los estudios químicos hechos antes de escribir el código, se determina que ya la cantidad de dosis A no es igual a la cantidad de dosis B.

 

0 Comments Unéte a los comentarios →