21

我最近在一个项目中开始使用 Sonar,我得到了一条关于使用构造函数的 PMD 规则new BigDecimal(double val)。当我阅读 java 文档时,我发现 new BigDecimal(double val) 有点不可预测,我应该使用new BigDecimal(String val)可预测的。

这是 javadoc 所说的BigDecimal public BigDecimal(double val)

将 double 转换为 BigDecimal,BigDecimal 是 double 的二进制浮点值的精确十进制表示。返回的 BigDecimal 的小数位数是使 (10scale × val) 为整数的最小值。

笔记:

此构造函数的结果可能有些不可预测。有人可能会假设new BigDecimal(0.1)用 Java 编写的 a BigDecimal正好等于 0.1(未缩放的值 1,比例为 1),但它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 不能完全表示为双精度数(或者,就此而言,不能表示为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于 0.1,尽管看起来如此。

另一方面,String 构造函数是完全可预测的:编写new BigDecimal("0.1")创建的 aBigDecimal正好等于 0.1,正如人们所期望的那样。因此,一般建议优先使用 String 构造函数。

当必须将 double 用作 a 的源时BigDecimal,请注意此构造函数提供了精确转换;它与使用 Double.toString(double)方法将双精度转换为字符串然后使用 BigDecimal(String)构造函数给出的结果不同。要获得该结果,请使用静态 valueOf(double)方法。

为什么这个构造函数真的存在?这还new BigDecimal(String val)不够吗?我什么时候应该使用new BigDecimal(double val)构造函数?

4

6 回答 6

16

为什么这个构造函数真的存在?

它将实际表示的值转换double为 BigDecimal。BigDecimal 的全部意义在于提供尽可能高的精度,这就是这个构造函数的作用。

如果您想通过少量四舍五入获得Double.toString(double)可以使用的值

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

印刷

0.1

我什么时候应该使用新的 BigDecimal(double val) 构造函数

当你想知道double真正代表的价值。您可以根据需要应用自己的舍入。

使用double时,应始终应用合理的舍入。但是,如果你这样做了,你可能会发现你不需要 BigDecimal。;)

于 2012-08-31T15:40:15.123 回答
6

When should I use the new BigDecimal(double val) constructor?

最好 - 无处。

如果您愿意使用 BigDecimals,则使用带有 double 的构造函数意味着失去精确数字表示的所有好处。

Why does this constructor really exists?

因为有时你只有双倍,你想翻译成 BigDecimal。强迫你在中间使用.toString()会很愚蠢;)

于 2012-08-31T15:39:30.147 回答
4

因为如果您已经从一个double值作为数据开始,那么您已经失去了这种精确性。因此,没有它会迫使您将其转换为StringforBigDecimal以将其转换回来。

而且,也许有时你只需要那个值。

于 2012-08-31T15:37:41.907 回答
1

当您要使用的数据已经作为双精度值存在时,您将使用双精度构造函数。在这种情况下,必须在将其转换为 BigDecimal 之前将其转换为字符串将是一种浪费。

于 2012-08-31T15:39:18.080 回答
0

不可预料的?我不同意。

final double before = 0.1;
BigDecimal bd = new BigDecimal(before);
double after = bd.doubleValue();
assert before == after;

理解的关键:

assert 0.1 == 0.1000000000000000055511151231257827021181583404541015625;

如果你的意思是“0.1”,那么是的,使用 String 构造函数 =) 但是如果你已经有一个double,那么那个 double 不是“0.1”。

您引用的 JavaDoc 说:

当必须将 double 用作 BigDecimal 的源时,请注意此构造函数提供了精确的转换;

我看不出确切的转换是如何“不可预测的”,我非常赞成从这句话中删除“必须”这个词。

归根结底,两个构造函数都按预期工作。如果你有字符串“0.1”,那么 BigDecimal(String) 会精确地转换这个值。如果你有一个 double 0.1,那么 BigDecimal(double) 会精确地转换这个值。

于 2016-06-24T23:00:14.243 回答
0
double val = 0.1; // this is not 0.1, but an approximination as pointed out in other answers.
BigDecimal biggy = new BigDecimal(val); // this variable conatains the "same" value as val does, however it is not 0.1, but as pointed out in other answers: 0.100000000000000005551115123`

因此,在此处列出的情况下,您可以完全控制源代码,您应该将val写为 'String val = "0.1"'

但是BigDecimal(double val),如果您从文件中读取二进制双精度数,则构造函数很有用。显然,在几乎所有情况下,您都需要与“双打”完全相同的 BigDecimal

于 2015-11-26T14:20:26.510 回答