使用 Java BigDecimal 仍然没有正确解决

Using Java BigDecimal still not correctly solving

我有一个输入两个 double 值的方法。当尝试将它们加在一起时,我得到了超过某个阈值的不正确值,所以我开始使用 BigDecimal

然而即使 BigDecimal 我仍然有不正确的值?

double value1 = 2789.45;
double value2 = 557.89;
System.out.println(BigDecimal.valueOf(value1 + value2));

打印

3347.3399999999997

当它应该读作

3347.34

即使 value1value2 可能高于当前范围,我如何才能正确执行此操作? (它们是用单独的方法计算的)。

我应该只使用舍入吗?

Should I just use rounding?

NOPE,您遇到的是 double 和的精度丢失。


您首先对双精度求和 (value1 + value2),然后将双精度求和(已丢失精度)转换为 BigDecimal

要避免这种情况,请改用:

double value1 = 2789.45;
double value2 = 557.89;
System.out.println(BigDecimal.valueOf(value1).add(BigDecimal.valueOf(value2)));

输出:

3347.34

工作IDEONE DEMO here


更新

-1. Instead of using BigDecimal.valueOf, which is still fragile, you should be using BigDecimal from the beginning and create them with new BigDecimal("2789.45"), new BigDecimal("557.89"). As soon as you've used a double literal, you've introduced imprecision. BigDecimal.valueOf tries to get it back, but it doesn't always work. – Louis Wasserman

其实我并不完全同意这一点。您不能对创建新小数的值进行硬编码,我同意的是直接读取 String 中的值(如果可能的话)以避免 double 精度丢失:

String value1 = "2789.45"; 
BigDecimal one = new BigDecimal(value1);
String value2 = "557.89";
BigDecimal two = new BigDecimal(value2);
System.out.println(one.add(two));

输出:

3347.34

这将避免 Louis Wasserman 注意到的问题。

新的工作演示

因为编译器会先计算总和,所以它首先将两个 doubles 相加,因此你失去了精度,你实际上是这样做的

double value1 = 2789.45;
double value2 = 557.89;
double sum = value1 + value2; // precision lost here
System.out.println(BigDecimal.valueOf(sum));

当您将变量分配给双精度值时,您已经失去了精度。

考虑这个程序:

import java.math.BigDecimal;

public class Test {
  public static void main(String[] args) {
    System.out.println(new BigDecimal(2789.45));
    System.out.println(new BigDecimal("2789.45"));
  }
}

输出:

2789.4499999999998181010596454143524169921875
2789.45

在 BigDecimal 中进行加法会得到输入的精确总和,但如果您先转换为 double,输入将是最接近您所写值的双倍值。