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
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