15

我知道以下行为是一个老问题,但我仍然不明白。

System.out.println(0.1 + 0.1 + 0.1);    

或者即使我使用BigDecimal

System.out.println(new BigDecimal(0.1).doubleValue()
    + new BigDecimal(0.1).doubleValue()
    + new BigDecimal(0.1).doubleValue());

为什么这个结果是:0.30000000000000004而不是:0.3

我该如何解决这个问题?

4

5 回答 5

31

你真正想要的是

new BigDecimal("0.1")
 .add(new BigDecimal("0.1"))
 .add(new BigDecimal("0.1"));

构造函数获得了的new BigDecimal(double)所有不精确性double,所以当您说0.1时,您已经引入了舍入误差。使用String构造函数避免了与通过double.

于 2012-03-20T22:07:17.140 回答
9

首先,永远不要使用 BigDecimal 的双重构造函数。在某些情况下这可能是正确的,但大多数情况下并非如此

如果您可以控制您的输入,请使用已经提出的 BigDecimal String 构造函数。这样你就可以得到你想要的。如果您已经有一个 double (毕竟可能发生),请不要使用 double 构造函数,而是使用静态valueOf方法。这有一个很好的优势,即我们得到了双精度的规范表示,这至少可以缓解问题……而且结果通常更加直观。

于 2012-03-20T23:39:12.803 回答
4

这不是Java的问题,而是一般计算机的问题。核心问题在于从十进制格式(人类格式)到二进制格式(计算机格式)的转换。一些十进制格式的数字在没有无限重复小数的情况下无法以二进制格式表示。

例如,十进制的 0.3 是 0.01001100... 二进制 但是计算机有一个有限的“槽”(位)来保存一个数字,所以它不能保存所有的无限表示。它仅节省 0.01001100110011001100(例如)。但是十进制数不再是 0.3,而是 0.30000000000000004。

于 2012-03-20T21:45:53.747 回答
3

试试这个:

BigDecimal sum = new BigDecimal(0.1).add(new BigDecimal(0.1)).add(new BigDecimal(0.1));

编辑:实际上,查看 Javadoc,这将与原来的问题相同。构造函数BigDecimal(double)将生成一个 BigDecimal 对应于 0.1 的精确浮点表示,它不完全等于 0.1。

然而,这给出了准确的结果,因为整数总是可以精确地以浮点表示形式表示:

BigDecimal one = new BigDecimal(1);
BigDecimal oneTenth = one.divide(new BigDecimal(10));

BigDecimal sum = oneTenth.add(oneTenth).add(oneTenth);
于 2012-03-20T21:41:22.453 回答
3

您遇到的问题是 0.1 用稍高的数字表示,例如

System.out.println(new BigDecimal(0.1));

印刷

0.1000000000000000055511151231257827021181583404541015625

Double.toString() 考虑了这种表示错误,因此您看不到它。

类似地,0.3 由一个比实际值略低的值表示。

0.299999999999999988897769753748434595763683319091796875

如果将 0.1 的表示值乘以 3,则不会得到 0.3 的表示值,而是会得到更高的值

0.3000000000000000166533453693773481063544750213623046875

这不仅是表示错误,而且是操作引起的舍入错误。这比 Double.toString() 更正,因此您会看到舍入错误。

故事的寓意,如果您使用floatdouble也适当地使用解决方案。

double d = 0.1 + 0.1 + 0.1;
System.out.println(d);
double d2 = (long)(d * 1e6 + 0.5) / 1e6; // round to 6 decimal places.
System.out.println(d2);

印刷

0.30000000000000004
0.3
于 2012-03-21T09:15:07.677 回答