使用BigDecimal将两个数相乘会返回错误的值

时间:2014-08-07 09:38:51

标签: java math bigdecimal

执行以下代码:

new BigDecimal(0.06 * 3).toString()

返回0.179999999999999993338661852249060757458209991455078125而不是0.18

执行

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

返回相同的结果。

这怎么可能?

3 个答案:

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

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

答案 2 :(得分:1)

BigDecimal#valueOf合作更好:

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

打印正确的结果0.18