BigDecimal(double)构造函数的不可预测性

时间:2012-08-31 15:35:09

标签: java

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

以下是javadoc对BigDecimal public BigDecimal(double val)所说的内容:

  

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

     

注意:

     

这个构造函数的结果可能有些不可预测。一   可能会假设在Java中编写new BigDecimal(0.1)会创建一个   BigDecimal正好等于0.1(未缩放值为1,   比例为1),但它实际上等于   0.1000000000000000055511151231257827021181583404541015625。这是因为0.1不能完全表示为double(或者为此)   重要的是,作为任何有限长度的二进制分数)。因此,价值   传入构造函数的不完全等于   0.1,尽管有外表。

     

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

     

当必须将double用作BigDecimal的来源时,请注意   这个构造函数提供了精确的转换;它没有给出   使用。将double转换为String的结果相同   Double.toString(double)方法,然后使用   BigDecimal(String)构造函数。要获得该结果,请使用静态   valueOf(double)方法。

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

6 个答案:

答案 0 :(得分:7)

  

为什么这个构造函数确实存在?

它将实际表示的double值转换为BigDecimal。 BigDecimal的重点是提供尽可能多的精度,这就是这个构造函数的作用。

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

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

打印

0.1
  

何时应该使用新的BigDecimal(双val)构造函数

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

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

答案 1 :(得分:2)

因为如果您已经以double值作为数据开头,那么您已经失去了这种精确度。因此,没有它会迫使您将String转换为BigDecimal以将其转换回来。

而且,有时候你可能只需要那个值。

答案 2 :(得分:2)

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

最好 - 无处。

如果您愿意使用BigDecimals,那么使用带有双精度的构造函数会失去确切数字表示的所有好处。

Why does this constructor really exists?

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

答案 3 :(得分:1)

当您要使用的数据已作为double值存在时,您将使用double构造函数。

,在将其转换为BigDecimal之前将其转换为字符串将是一种浪费

答案 4 :(得分: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)非常有用。显然你几乎在所有情况下都会想要与'双打'完全相同的BigDecimals

答案 5 :(得分: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)会完全转换这个值。如果你有一个双0.1,那么BigDecimal(double)将完全转换这个值。