使用 BigDecimal 将两个数字相乘会返回错误的值
执行以下代码:
new BigDecimal(0.06 * 3).toString()
返回而不是 。0.179999999999999993338661852249060757458209991455078125
0.18
执行
new BigDecimal(0.06).multiply(new BigDecimal(3)).toString()
返回相同的结果。
这怎么可能?
执行以下代码:
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()
请注意,您确实需要字符串中的值 - 否则您将使用0.06的值,该值并不完全是0.06...您在开始之前丢失了信息。(您并不需要字符串形式的 3,但我这样做是为了保持一致性。double
例如:
System.out.println(new BigDecimal(0.06));
指纹
0.059999999999999997779553950749686919152736663818359375
正如Jon Skeet在上面所写的那样,你得到而不是的原因是因为被计算为IEEE 754双精度,
然后这个值被转换为.0.179999999999999993338661852249060757458209991455078125
0.18
0.06 * 3
double
BigDecimal
尽管在源代码中看起来足够简单,但数字0.06并不能完全表示为IEEE 754,因此实际表示的是0.06的近似值,等于0.0599999999999999777953953950749686919152736663818359375。十进制表示法中的数字 0.06 不能完全表示,因为该数字等于二进制表示法中的 0b0.000011110101110000101(其中粗体表示重复的数字序列)。计算机必须截断这个无限的二进制数字序列,导致0.0599999...近似值。0.06
double
0.06
正如我在回答有关 IEEE 754,64 位双精度的问题时所详述的那样,您可以使用 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 / 21 + 20 × i
您可以在计算机代数系统(如 Maxima)中评估此序列:
(%i1) sum ( 0.11999988555908203125 / 2 ^ (1 + 20 * i), i, 0, inf ), simpsum; (%o1) 0.06