执行以下代码:
new BigDecimal(0.06 * 3).toString()
返回0.179999999999999993338661852249060757458209991455078125
而不是0.18
。
执行
new BigDecimal(0.06).multiply(new BigDecimal(3)).toString()
返回相同的结果。
这怎么可能?
答案 0 :(得分:50)
您没有使用BigDecimal
将两个数字相乘。您使用double
算术将它们相乘,并将结果传递给BigDecimal
构造函数。
你想:
new BigDecimal("0.06").multiply(new BigDecimal("3")).toString()
请注意,你做想要字符串中的值 - 否则你使用0.06的double
值,这不是0.06 ...你之前丢失了信息你先来。 (你真的不需要3的字符串形式,但为了保持一致性,我已经这样做了。)
例如:
System.out.println(new BigDecimal(0.06));
打印
0.059999999999999997779553950749686919152736663818359375
答案 1 :(得分:2)
正如Jon Skeet在上面写的那样,你得到0.179999999999999993338661852249060757458209991455078125
而不是0.18
的原因是因为0.06 * 3
被计算为IEEE 754 double
,然后是double
} value转换为BigDecimal
。
即使0.06
在源代码中看起来很简单,但数字0.06并不能完全代表IEEE 754 double
,因此0.06
实际代表的是近似值< / em> 0.06等于0.05999999999999997779553950749686919152736663818359375。十进制表示法中的数字0.06不能完全表示,因为数字等于二进制表示法中的0b0.0 00011110101110000101 (其中粗体表示重复数字序列)。计算机必须截断这个无限的二进制数字序列,导致0.0599999 ...近似。
正如我在my answer to Question regarding IEEE 754, 64 bits double?中详述的那样,您可以使用ARIBAS'decode_float()
函数来确定浮点数的尾数和指数:
==> 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
(**
是ARIBAS中的取幂)。
我们有0.06 =Σ i =0..∞ 0.11999988555908203125 / 2 1 + 20×i
您可以在计算机代数系统(例如Maxima:
)中评估此系列(%i1) sum ( 0.11999988555908203125 / 2 ^ (1 + 20 * i), i, 0, inf ), simpsum; (%o1) 0.06
答案 2 :(得分:1)
与BigDecimal#valueOf
合作更好:
BigDecimal.valueOf(0.06).multiply(BigDecimal.valueOf(3))
打印正确的结果0.18