BigDecimal 添加错误的值
BigDecimal adding wrong value
我有一个 BigDecimal
定义如下:
private static final BigDecimal sd = new BigDecimal(0.7d);
如果我打印它,我得到值:
0.6999999999999999555910790149937383830547332763671875
这会导致一些错误的计算。有谁知道如何将 0.7
的精确值设为 BigDecimal
?改成0.71
会看到正确的结果,但不应该是这样的
使用字符串文字:
private static final BigDecimal sd = new BigDecimal("0.7");
如果您使用 double
,实际上会调用 public BigDecimal(double val)
。你没有得到 0.7 的原因是它不能用 double
精确表示。有关详细信息,请参阅链接的 JavaDoc。
您应该使用字符串文字中的声明值,例如 new BigDecimal("0.7");
这里有三种方法:
private static final BigDecimal sd = new BigDecimal("0.7");
private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL32);
private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL64)
也许如果您费心阅读文档,即您正在使用的 constructor 的 javadoc,您就已经知道答案了。
- When a
double
must be used as a source for a BigDecimal
, note that this constructor provides an exact conversion; it does not give the same result as converting the double
to a String
using the Double.toString(double)
method and then using the BigDecimal(String)
constructor. To get that result, use the static
valueOf(double)
method.
当您查看 BigDecimal.valueOf(double)
的 javadoc 时,您会发现:
Note: This is generally the preferred way to convert a double
(or float
) into a BigDecimal
, as the value returned is equal to that resulting from constructing a BigDecimal
from the result of using Double.toString(double)
.
所以有你的答案:使用BigDecimal.valueOf(0.7d)
,而不是new BigDecimal(0.7d)
。
从 double
构建 BigDecimal
非常复杂。首先,它只能通过绕行字符串来完成。 (你不能得到带有 double
和 MathContext
的构造函数。我已经尝试了很多。最近在小数点前的位数需要更改的情况下舍入,它变得困难。因此 Javadoc 中警告你不应该使用它。)
然而,即使在那里,简单的 String.format()
也是不够的,因为 String.format()
对默认值 Locale
敏感,并根据 [=27= 输出不同的小数点分隔符] 设置,而 BigDecimal
构造函数始终需要一个点作为小数点分隔符。所以你必须用 Locale.US
构造你自己的 Formatter
。如果你有这个并且运行,你会收到一个未关闭资源的警告。
我发现这个有效:
static BigDecimal toBigDecimal(double value, int decimalPlaces) {
String format = "%." + decimalPlaces + "f";
try (Formatter formatter = new Formatter(Locale.US)) {
String formatted = formatter.format(format, value).toString();
return new BigDecimal(formatted);
}
}
我有一个 BigDecimal
定义如下:
private static final BigDecimal sd = new BigDecimal(0.7d);
如果我打印它,我得到值:
0.6999999999999999555910790149937383830547332763671875
这会导致一些错误的计算。有谁知道如何将 0.7
的精确值设为 BigDecimal
?改成0.71
会看到正确的结果,但不应该是这样的
使用字符串文字:
private static final BigDecimal sd = new BigDecimal("0.7");
如果您使用 double
,实际上会调用 public BigDecimal(double val)
。你没有得到 0.7 的原因是它不能用 double
精确表示。有关详细信息,请参阅链接的 JavaDoc。
您应该使用字符串文字中的声明值,例如 new BigDecimal("0.7");
这里有三种方法:
private static final BigDecimal sd = new BigDecimal("0.7");
private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL32);
private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL64)
也许如果您费心阅读文档,即您正在使用的 constructor 的 javadoc,您就已经知道答案了。
- When a
double
must be used as a source for aBigDecimal
, note that this constructor provides an exact conversion; it does not give the same result as converting thedouble
to aString
using theDouble.toString(double)
method and then using theBigDecimal(String)
constructor. To get that result, use thestatic
valueOf(double)
method.
当您查看 BigDecimal.valueOf(double)
的 javadoc 时,您会发现:
Note: This is generally the preferred way to convert a
double
(orfloat
) into aBigDecimal
, as the value returned is equal to that resulting from constructing aBigDecimal
from the result of usingDouble.toString(double)
.
所以有你的答案:使用BigDecimal.valueOf(0.7d)
,而不是new BigDecimal(0.7d)
。
从 double
构建 BigDecimal
非常复杂。首先,它只能通过绕行字符串来完成。 (你不能得到带有 double
和 MathContext
的构造函数。我已经尝试了很多。最近在小数点前的位数需要更改的情况下舍入,它变得困难。因此 Javadoc 中警告你不应该使用它。)
然而,即使在那里,简单的 String.format()
也是不够的,因为 String.format()
对默认值 Locale
敏感,并根据 [=27= 输出不同的小数点分隔符] 设置,而 BigDecimal
构造函数始终需要一个点作为小数点分隔符。所以你必须用 Locale.US
构造你自己的 Formatter
。如果你有这个并且运行,你会收到一个未关闭资源的警告。
我发现这个有效:
static BigDecimal toBigDecimal(double value, int decimalPlaces) {
String format = "%." + decimalPlaces + "f";
try (Formatter formatter = new Formatter(Locale.US)) {
String formatted = formatter.format(format, value).toString();
return new BigDecimal(formatted);
}
}