执行以下代码:
new BigDecimal(0.06 * 3).toString()
返回0.179999999999999993338661852249060757458209991455078125
而不是0.18
。
new BigDecimal(0.06).multiply(new BigDecimal(3)).toString()
返回相同的结果。
这怎么可能?
您没有使用BigDecimal
将两个数字相乘。您正在使用double
算术将它们相乘,并将结果传递给BigDecimal
构造函数。
你想:
new BigDecimal("0.06").multiply(new BigDecimal("3")).toString()
请注意,确实想要字符串形式的值-否则您将使用double
值表示0.06,这并不完全是0.06…你在开始之前就丢失了信息。(您实际上并不需要3的字符串形式,但我这样做是为了保持一致性。)
System.out.println(new BigDecimal(0.06));
打印
0.059999999999999997779553950749686919152736663818359375
正如Jon Skeet上面所写的,您获得0.179999999999999993338661852249060757458209991455078125
而不是0.18
的原因是因为0.06 * 3
被计算为IEEE 754 double
,然后将此double
值转换为BigDecimal
。
尽管0.06
在源代码中看起来足够简单,但数字0.06不能精确地表示为IEEE 754 double
,因此0.06
实际上表示的是0.06的近似值等于0.059999999999999997779553950749686919152736663818359375。十进制记数法中的数字0.06不能精确表示,因为该数字等于二进制记数法中的0b0.000011110101110000101(其中粗体表示重复的数字序列)。计算机必须截断这个无限的二进制数字序列,得到0.0599999…近似。
正如我在回答关于IEEE 754, 64位双精度的问题时详细说明的那样?,您可以使用ARIBAS的decode_float()
函数来确定浮点数的尾数和指数:
(**
是ARIBAS中的幂运算).
有0.06 = Σ i = 0..0.11999988555908203125∞<一口>一口>/<子> 2 <一口> 1 + 20×我一口>子>
您可以在Maxima等计算机代数系统中计算该级数:
<>之前(% 1) sum (0.11999988555908203125/2 ^ (1 + 20 * i), i, 0, inf),简单和;(% o1群 ) 0.06之前http://maxima-online.org/?inc=r760264757使用BigDecimal#valueOf
效果更好:
BigDecimal.valueOf(0.06).multiply(BigDecimal.valueOf(3))
打印正确的结果0.18