round parsear parse cast java precision bigdecimal

java - parsear - "New BigDecimal(13.3D)" da como resultado "13.3000000000000007105.." imprecisa?



talend bigdecimal (5)

¿Cómo es que BigDecimal de Java puede ser tan doloroso?

Double d = 13.3D; BigDecimal bd1 = new BigDecimal(d); BigDecimal bd2 = new BigDecimal(String.valueOf(d)); System.out.println("RESULT 1: "+bd1.toString()); System.out.println("RESULT 2: "+bd2.toString()); RESULT 1: 13.300000000000000710542735760100185871124267578125 RESULT 2: 13.3

¿Hay alguna situación en la que se desee el resultado 1? Sé que Java 1.5 cambió el método toString() pero ¿era esta la consecuencia prevista?

También me doy cuenta de que BigDecimal tiene doubleValue() etc, pero la biblioteca con la que estoy trabajando usa un toString() y no puedo cambiar eso :-(

Aclamaciones.


Su problema no tiene nada que ver con BigDecimal , y todo con Double , que no puede representar 13.3 con precisión, ya que usa fracciones binarias internamente.

Entonces su error se introduce en la primera línea. El primer BigDecimal simplemente lo conserva, mientras que String.valueOf() realiza un redondeo a pescado que hace que el segundo tenga el contenido deseado, casi por suerte.


Bueno, la API aborda esta aparente inconsistencia en el constructor BigDecimal(double val) :

  1. Los resultados de este constructor pueden ser algo impredecibles. Uno podría suponer que escribir un nuevo BigDecimal (0.1) en Java crea un BigDecimal que es exactamente igual a 0.1 (un valor sin escala de 1, con una escala de 1), pero en realidad es igual a 0.1000000000000000055511151231257827021181583404541015625. Esto se debe a que 0.1 no se puede representar exactamente como un doble (o, para el caso, como una fracción binaria de cualquier longitud finita). Por lo tanto, el valor que se transfiere al constructor no es exactamente igual a 0.1, a pesar de las apariencias.

  2. El constructor String, por otro lado, es perfectamente predecible: escribir un nuevo BigDecimal ("0.1") crea un BigDecimal que es exactamente igual a 0.1, como era de esperar. Por lo tanto, generalmente se recomienda utilizar el constructor String con preferencia a este.

  3. Cuando se debe usar un doble como fuente para un BigDecimal , tenga en cuenta que este constructor proporciona una conversión exacta; no da el mismo resultado que convertir el doble en una cadena usando el método Double.toString (doble) y luego usar el constructor BigDecimal (String). Para obtener ese resultado, use el método estático valueOf (double) .

Moraleja de la historia: el dolor parece autoinfligido, solo usa el new BigDecimal(String val) o BigDecimal.valueOf(double val) lugar =)


Es posible que desee informarse acerca de cómo se implementan los valores de coma flotante ( IEEE 754-1985 ). Y de repente, todo quedará claro como el cristal.


Esto no es culpa de BigDecimal , es la culpa del double . BigDecimal representa con precisión el valor exacto de d . String.valueOf solo muestra el resultado con algunos decimales.


Las fracciones representadas con tipos de números binarios (es decir, double , float ) no se pueden almacenar con precisión en esos tipos.

Double d = 13.3; BigDecimal bdNotOk = new BigDecimal(d); System.out.println("not ok: " + bdNotOk.toString()); BigDecimal bdNotOk2 = new BigDecimal(13.3); System.out.println("not ok2: " + bdNotOk2.toString()); double x = 13.3; BigDecimal ok = BigDecimal.valueOf(x); System.out.println("ok: " + ok.toString()); double y = 13.3; // pretty lame, constructor''s behavior is different from valueOf static method BigDecimal bdNotOk3 = new BigDecimal(y); System.out.println("not ok3: " + bdNotOk3.toString()); BigDecimal ok2 = new BigDecimal("13.3"); System.out.println("ok2: " + ok2.toString()); Double e = 0.0; for(int i = 0; i < 10; ++i) e = e + 0.1; // some fractions cannot be accurately represented with binary System.out.println("not ok4: " + e.toString()); // should be 1 BigDecimal notOk5 = BigDecimal.valueOf(e); System.out.println("not ok5: " + notOk5.toString()); // should be 1 /* * here are some fractions that can be represented exactly in binary: * 0.5 = 0.1 = 1 / 2 * 0.25 = 0.01 = 1 / 4 * 0.75 = 0.11 = 3 / 4 * 0.125 = 0.001 = 1 / 8 */

salida:

not ok: 13.300000000000000710542735760100185871124267578125 not ok2: 13.300000000000000710542735760100185871124267578125 ok: 13.3 not ok3: 13.300000000000000710542735760100185871124267578125 ok2: 13.3 not ok4: 0.9999999999999999 not ok5: 0.9999999999999999

Simplemente use BigDecimal.valueOf(d) o new BigDecimal(s) .