使用 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
即使 value1
和 value2
可能高于当前范围,我如何才能正确执行此操作? (它们是用单独的方法计算的)。
我应该只使用舍入吗?
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
更新
-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
,输入将是最接近您所写值的双倍值。
我有一个输入两个 double
值的方法。当尝试将它们加在一起时,我得到了超过某个阈值的不正确值,所以我开始使用 BigDecimal
。
然而即使 BigDecimal
我仍然有不正确的值?
double value1 = 2789.45;
double value2 = 557.89;
System.out.println(BigDecimal.valueOf(value1 + value2));
打印
3347.3399999999997
当它应该读作
3347.34
即使 value1
和 value2
可能高于当前范围,我如何才能正确执行此操作? (它们是用单独的方法计算的)。
我应该只使用舍入吗?
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
更新
-1. Instead of using
BigDecimal.valueOf
, which is still fragile, you should be usingBigDecimal
from the beginning and create them withnew BigDecimal("2789.45")
,new BigDecimal("557.89")
. As soon as you've used adouble
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
,输入将是最接近您所写值的双倍值。