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



执行以下代码:

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()函数来确定浮点数的尾数和指数:

<>之前= => set_floatprec (double_float)。-: 64= => set_printbase(2)。-: 0日元= => decode_float(0.06)。: (0 y11110101_11000010_10001111_01011100_00101000_11110101_11000010_10001111,0 y1000100)= => set_printbase(10)。-: 10= => 0 y1000100。-: -68= => set_floatprec(128)。-: 128= => 1/2 * * 4 + 1/2 * * 5 + 1/2 * * 6 * * * * 7 + 1/2 + 1/2 + 1/2 * 9 * 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×我

您可以在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

相关内容

最新更新