Java BigDecimal(double)构造函数的不可预测性
我最近在一个项目中开始使用Sonar,我在使用构造函数Java BigDecimal(double)构造函数的不可预测性,java,Java,我最近在一个项目中开始使用Sonar,我在使用构造函数new BigDecimal(double val)时违反了PMD规则。当我阅读java文档时,我发现新的BigDecimal(double val)有些不可预测,我应该使用可预测的新的BigDecimal(String val) 下面是javadoc对BigDecimal公共BigDecimal(double val)的说明: 将double转换为BigDecimal,即精确的十进制 表示双精度二进制浮点值。天平 返回的BigDecimal
new BigDecimal(double val)
时违反了PMD规则。当我阅读java文档时,我发现新的BigDecimal(double val)有些不可预测,我应该使用可预测的新的BigDecimal(String val)
下面是javadoc对BigDecimal
公共BigDecimal(double val)
的说明:
将double转换为BigDecimal,即精确的十进制
表示双精度二进制浮点值。天平
返回的BigDecimal的最小值为(10scale×)
val)是一个整数
注:
此构造函数的结果可能有些不可预测。一个
可能假设在Java中编写新的BigDecimal(0.1)
会创建
BigDecimal
正好等于0.1(未标度值1,
比例为1),但实际上等于
0.1000000000000000055511151231257827021181583404541015625. 这是因为0.1不能精确地表示为double(或者
物质,作为任何有限长度的二元分数)。因此,价值
传递给构造函数的不完全等于
0.1,尽管有外观
另一方面,字符串构造函数是完全可预测的:
写入新的BigDecimal(“0.1”)将创建一个
正如人们所预料的,正好等于0.1。因此,一般来说
建议优先使用字符串构造函数
一个
当双精度必须用作BigDecimal
的源时,请注意
此构造函数提供精确的转换;它没有给出正确的答案
与使用
Double.toString(Double)
方法,然后使用
BigDecimal(字符串)
constructor。要获得该结果,请使用静态
valueOf(double)
方法
为什么这个构造函数真的存在?新的BigDecimal(stringval)对于这个问题还不够吗?什么时候我应该使用新的BigDecimal(double val)构造函数?因为如果您已经开始使用一个
double
值作为数据,那么您已经失去了精度。因此,没有它将迫使您将其转换为String
forbigdecimic
以将其转换回
而且,有时您可能只需要这个值。当您要处理的数据已经作为双精度值存在时,您可以使用双精度构造函数。在这种情况下,在将其转换为BigDecimal之前必须将其转换为字符串将是一种浪费。
我应该在什么时候使用新的BigDecimal(double val)构造函数?
最好是没有
如果您愿意使用大小数,使用带双精度的构造函数意味着失去精确数字表示的所有好处
为什么这个构造函数真的存在?
因为有时候你只有double,你想转换成BigDecimal。强迫您在两者之间使用.toString()
将是愚蠢的;)
为什么这个构造函数真的存在
它将实际表示的double
值转换为一个BigDecimal。BigDecimal的全部目的是提供尽可能多的精度,这就是这个构造函数所做的
如果您想获取通过少量四舍五入得到的值,可以使用Double.toString(Double)
uses
System.out.println(BigDecimal.valueOf(0.1));
印刷品
0.1
我应该什么时候使用新的BigDecimal(double val)构造函数
当您想知道double
真正代表的值时。您可以根据需要应用自己的舍入
当您使用double
时,应始终应用合理的舍入。但是,如果你这样做了,你可能会发现你不需要大十进制
因此,在这里列出的情况下,您可以完全控制源代码,您应该将val写为'String val=“0.1”'
但是,如果从文件中读取二进制双精度值,则构造函数
BigDecimal(double val)
非常有用。很明显,在几乎所有情况下,您都希望使用与“double”完全相同的大小数。不可预测?我不同意
final double before = 0.1;
BigDecimal bd = new BigDecimal(before);
double after = bd.doubleValue();
assert before == after;
理解的关键:
assert 0.1 == 0.1000000000000000055511151231257827021181583404541015625;
如果您真正的意思是“0.1”,那么是的,使用字符串构造函数=),但是如果您已经有了一个double
,那么这个double就不是“0.1”
你引用的JavaDoc说:
当必须将double用作BigDecimal的源时,请注意
此构造函数提供精确的转换
我不明白确切的转换是如何“不可预测”的,我非常赞成从这段引文中删除“必须”一词
在一天结束时,两个构造器都像预期的那样工作。如果有字符串“0.1”,则BigDecimal(字符串)会精确转换此值。如果你有一个双精度0.1,那么BigDecimal(double)会准确地转换这个值。那么,如果我使用的是双精度值,然后转换成字符串,然后转换成BigDecimal,我会失去精度吗?例如,使用Double.toString?可以,因为Double.toString()是一种狡猾的野兽。它实际上并没有返回传递给它的双精度的确切值。相反,它返回最短的字符串,在解析该字符串时,该字符串仍将转换为指定的双精度值。这有点让人困惑,但基本上,这意味着如果Double.toString(0.10000000000000055115123)是“0.1”,则可以保证Double.parseDouble(“0.1”)也是0.10000000000000055115123。这是一个棘手的问题,为什么会丢失精度,但在控制台上打印双精度值时,它看起来从来都不像。之所以会丢失精度,是因为新的BigDecimal(double.toString(0.1d)),实际上表示精确的“0.1”值,即使0.1d是
assert 0.1 == 0.1000000000000000055511151231257827021181583404541015625;