【问题标题】:new BigDecimal(double) vs new BigDecimal(String) [duplicate]new BigDecimal(double) vs new BigDecimal(String) [重复]
【发布时间】:2015-04-14 16:19:04
【问题描述】:

BigDecimaldouble 的输入一起使用和BigDecimalString 的输入一起使用时,似乎会出现不同的结果。

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,不应该是一样的吗?

【问题讨论】:

  • 看看 a,b 和 c,d ...这已经不一样了 ;) 看看 stackoverflow.com/questions/12395281/…
  • 这是因为double 的精度有限;那是适合你的 IEEE 754。
  • 您可以使用.setScale(10, BigDecimal.ROUND_HALF_UP);进行更正

标签: java bigdecimal double-precision


【解决方案1】:

我说这是因为双重不精确,我错了吗?

你完全正确,这正是因为double的不精确。

但既然这是BigDecimal,不应该是一样的吗?

不,不应该。该错误在您创建 new BigDecimal(0.333333333) 时引入,因为 0.333333333 常量已经嵌入了一个错误。到那时,您无法解决此表示错误:众所周知,到那时马已经离开谷仓了,所以关门已经太迟了。

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

【讨论】:

    【解决方案2】:

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

    这是由标准支持的,它说floating point literals default to double unless otherwise specified

    【讨论】:

    • 不是浮点错误。浮点代码的行为与预期的行为完全相同。唯一的问题是程序员期望它的行为方式。 “问题”是0.333333333 表示的有理数与new BigDecimal("0.333333333") 表示的有理数不同。但是,这不是一个错误,它不能被“修复”,除非通过更改 Java 语言规范使得 0.333333333 不再被解释为 IEEE 二进制双精度。
    • @jameslarge 我知道 IEEE 二进制双精度是如何工作的——使用它们导致的不精确通常被称为“错误”。例如,请参见 wikipediaOracle docs。这是statistical error 意义上的错误,而不是FileNotFoundError
    • 哦,...对... 种错误。我想我最近有点专注于软件缺陷(请不要问我为什么),我开始看到它们,即使它们不在。
    【解决方案3】:

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

    此构造函数的结果可能有些不可预测。一 可能会假设用 Java 编写 new BigDecimal(0.1) 会创建一个 BigDecimal 正好等于 0.1(未缩放的值 1,与 比例为 1),但实际上等于 0.10000000000000000055511151231257827021181583404541015625。这是因为 0.1 不能完全表示为双精度数。

    【讨论】:

    • 好的,这是有道理的。谢谢!
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-03
      • 1970-01-01
      • 2019-10-08
      • 2021-02-13
      • 2015-03-31
      • 2011-03-25
      • 1970-01-01
      相关资源
      最近更新 更多