新的 BigDecimal(双)与新的 BigDecimal(字符串)

new BigDecimal(double) vs new BigDecimal(String)

BigDecimal 与输入 double 一起使用时,BigDecimal 与输入 String 一起使用时,似乎会出现不同的结果。

BigDecimal a = new BigDecimal(0.333333333);
BigDecimal b = new BigDecimal(0.666666666);

BigDecimal c = new BigDecimal("0.333333333");
BigDecimal d = new BigDecimal("0.666666666");

BigDecimal x = a.multiply(b);
BigDecimal y = c.multiply(d);

System.out.println(x);
System.out.println(y);

x 输出为

0.222222221777777790569747304508155316795087227497352441864147715340493949298661391367204487323760986328125

而 y 是

0.222222221777777778

我说这是因为双重不精确,我说错了吗?不过既然是BigDecimal,不应该是一样的吗?

是的,这是浮点数错误。问题是文字 0.3333333330.666666666 在作为参数传递给 BigDecimal 之前被表示为双精度数——值得注意的是,BigDecimal 的构造函数采用 double 作为参数。

这是标准所支持的,它表示floating point literals default to double unless otherwise specified

Am I wrong in saying that this is because of double imprecision?

你说得很对,这正是因为double的不精确。

But since this is a BigDecimal, shouldn't it be the same?

不,不应该。该错误是在您创建 new BigDecimal(0.333333333) 时引入的,因为 0.333333333 常量中已经嵌入了错误。到那时,您将无能为力来修复此表示错误:众所周知那匹马那时已经离开了谷仓,所以关门已经太晚了。

另一方面,当您传递 String 时,十进制表示与字符串完全匹配,因此您会得到不同的结果。

当您以任何方式定义双精度变量时,在大多数情况下,它不会是您定义的值,而是最接近的二进制表示形式。您正在向构造函数传递一个双精度值,因此已经提供了那个小的不精确性。

Java 文档有答案。根据 Java BigDecimal(double val)

的文档

The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double.