PRECISIÓN DECIMAL EN JAVA

Ésta, es una de esas cosas que cuando creas aplicaciones para ti, puedes ignorarlas o ni darte cuenta, pero cuando estás creando aplicaciones para grandes empresas pueden fastidiarte muy mucho.
En mi caso, el problema surgió cuando empecé a trabajar con dinero y en determinadas operaciones se perdían céntimos. ¿Cómo? Pues sí, aquí es donde empezó la búsqueda de un porqué para que
Double x = new Double(8192.55);
System.out.println("->" + (x * 100));
tenga como resultado por pantalla
819254.9999999999

Navegando por Internet, me encontré con un bonito artículo, que a su vez es la traducción de otro, en el que se explica el uso de BigDecimal para trabajar con cantidades que necesiten precisión decimal, como puede ser el caso de trabajar con dinero. El artículo viene a explicar que si trabajas con números en coma flotante se puede trabajar sin problemas con datos de tipo primitivo como double, pero si sobre esos números se tuvieran que realizar operaciones hay que tener mucho cuidado porque puede que no salgan los resultados correctos.
¿Por qué? Pues porque los ordenadores trabajan en binario y a la hora de trabajar con variables de tipo float o double cometen errores de precisión al trabajar con valores que no pueden representar.
Es en este momento es cuando alguno se lleva las manos a la cabeza diciendo, ¿CÓMO? TÚ ESTÁS MAL DE LA CABEZA. Pero no, porque nosotros también tenemos esos problemas de precisión en nuestro sistema decimal. Por ejemplo, si queremos reprentar 1/3, el resultado es 0.3333333333333… y así hasta el infinito. No podemos dar un valor exacto a esa operación. Y a los ordenadores les pasa exactamente lo mismo, si quieren representar por ejemplo 1/100, el resultado sería 1100110011001100110011001100110011… y así hasta el infinito. Ahí está nuestro problema.
Como no podía ser de otra forma, Java ya había pensado en esto, y por eso nos proporciona BigDecimal, una clase pensada para resolver este tipo de problemas. Pero aún nos queda una mala sorpresa reservada.
Lo primero a por lo que uno tira al utilizar BigDecimal es el constructor BigDecimal(double), y esto nos lleva al mismo problema. Este constructor lo que hace es guardar exactamente la misma representación que si trabajara con un dato de tipo double. La solución es trabajar SIEMPRE con el constructor BigDecimal(String). La propia documentación de BigDecimal así lo recomienda.
BigDecimal bd1 = new BigDecimal("8192.55");
BigDecimal bd2 = new BigDecimal("100");
bd1 = bd1.multiply(bd2);
System.out.println("->" + bd1.toString());
Para obtener, ahora sí, 819255.00
En los proyectos que ya teníamos y no se podía modificar la base de datos, recurrimos a un simple
BigDecimal bigDecimal = new BigDecimal(Double.toString(amount));
 
Fuente: http://mejorenjava.wordpress.com/2011/03/15/precision-decimal-en-java/
 

Comentarios

Entradas populares de este blog

JAVASCRIPT - DESHABILITAR RETROCESO, CONTROLAR REFRESH DE PÁGINA

TIPOS DE DATOS POSTGRES

PROBLEMA LICENCIAS TERMINAL SERVER Y WINDOWS SERVER 2012