usar redondear limitar float decimales con como java math bigdecimal

java - redondear - Multiplicando dos números usando BigDecimal devuelve un valor incorrecto



limitar decimales en java netbeans (3)

Ejecutando el siguiente código:

new BigDecimal(0.06 * 3).toString()

devuelve 0.179999999999999993338661852249060757458209991455078125 lugar de 0.18 .

Ejecutando

new BigDecimal(0.06).multiply(new BigDecimal(3)).toString()

devuelve el mismo resultado

¿Cómo es esto posible?


Como escribe Jon Skeet arriba, la razón por la que obtiene 0.179999999999999993338661852249060757458209991455078125 lugar de 0.18 es porque 0.06 * 3 se calcula como un double IEEE 754 y luego este double valor se convierte en un BigDecimal .

Aunque 0.06 parece lo suficientemente simple en el código fuente, el número 0.06 no es exactamente representable como un double IEEE 754, entonces lo que 0.06 realmente representa es una aproximación de 0.06 igual a 0.059999999999999997779553950749686919152736663818359375. El número 0.06 en notación decimal no es exactamente representable porque el número es igual a 0b0.0 00011110101110000101 en notación binaria (donde negrita representa una secuencia de dígitos repetidos). La computadora debe truncar esta secuencia infinita de dígitos binarios, lo que lleva a la aproximación de 0.0599999 ...

Como detallé en mi respuesta a la pregunta sobre IEEE 754, ¿se duplican 64 bits? , puede usar la ARIBAS decode_float() para determinar la mantisa y el exponente de un número de coma flotante:

==> set_floatprec(double_float). -: 64 ==> set_printbase(2). -: 0y10 ==> decode_float(0.06). -: (0y11110101_11000010_10001111_01011100_00101000_11110101_11000010_10001111, -0y1000100) ==> set_printbase(10). -: 10 ==> -0y1000100. -: -68 ==> set_floatprec(128). -: 128 ==> 1/2**4 + 1/2**5 + 1/2**6 + 1/2**7 + 1/2**9 + 1/2**11 + 1/2**12 + 1/2**13 + 1/2**18 + 1/2**20. -: 0.11999_98855_59082_03125_00000_00000_00000_00

( ** es exponenciación en ARIBAS).

Y tenemos 0.06 = Σ i = 0..∞ 0.11999988555908203125 / 2 1 + 20 × i

Puede evaluar esta serie en un sistema de álgebra computacional como Maxima:

(%i1) sum ( 0.11999988555908203125 / 2 ^ (1 + 20 * i), i, 0, inf ), simpsum; (%o1) 0.06

http://maxima-online.org/?inc=r760264757


No estás multiplicando dos números usando BigDecimal . Los está multiplicando utilizando aritmética double y pasando el resultado al constructor BigDecimal .

Usted quiere:

new BigDecimal("0.06").multiply(new BigDecimal("3")).toString()

Tenga en cuenta que desea los valores en cadenas; de lo contrario, está utilizando el valor double para 0.06, que no es exactamente 0.06 ... ha perdido información antes de comenzar. (Realmente no necesitas la forma de cadena de 3, pero lo he hecho por consistencia).

Por ejemplo:

System.out.println(new BigDecimal(0.06));

huellas dactilares

0.059999999999999997779553950749686919152736663818359375


Trabajando mejor con BigDecimal#valueOf :

BigDecimal.valueOf(0.06).multiply(BigDecimal.valueOf(3))

imprime el resultado correcto 0.18