apache commons中round的来源如下所示:
public static double round(double x, int scale, int roundingMethod) {
try {
return (new java.math.BigDecimal(Double.toString(x)).setScale(scale, roundingMethod)).doubleValue();
} catch (NumberFormatException ex) {
if (Double.isInfinite(x)) {
return x;
} else {
return Double.NaN;
}
}
}
我想知道,在创建BigDecimal
时,为什么他们选择将double转换为字符串(使用Double.toString
)而不是简单地使用double本身?
换句话说,这有什么问题? :
public static double round(double x, int scale, int roundingMethod) {
try {
return (new java.math.BigDecimal(x).setScale(scale, roundingMethod)).doubleValue();
} catch (NumberFormatException ex) {
if (Double.isInfinite(x)) {
return x;
} else {
return Double.NaN;
}
}
}
答案 0 :(得分:7)
这是因为BigDecimal(double)
构造函数的结果是不可预测的,如javadoc中所述。
有人可能会认为在Java中编写新的BigDecimal(0.1)会创建一个 BigDecimal正好等于0.1(未缩放的值为1,带有 比例为1),但它实际上等于 0.1000000000000000055511151231257827021181583404541015625
另一方面,String构造函数是完全可预测的: 编写新的BigDecimal(“0.1”)会创建一个完全正确的BigDecimal 等于0.1,正如人们所期望的那样。因此,一般来说 建议首先使用String构造函数 之一。
测试用例:
System.out.println(java.math.BigDecimal.valueOf(0.1).toString());
System.out.println(new java.math.BigDecimal(0.1).toString());
答案 1 :(得分:4)
来自构建函数BigDecimal(String val)
的文档here:
注意:对于float和double NaN以及±Infinity以外的值,请执行此操作 构造函数与返回的值兼容 Float.toString(float)和Double.toString(double)。这通常是 将float或double转换为BigDecimal的首选方法,如 它没有遭受BigDecimal(双重)的不可预测性 构造
答案 2 :(得分:1)
您不必转换为String
使用静态方法BigDecimal.valueOf(double val)
:
在您的代码中使用:
...
return (BigDecimal.valueOf(x).setScale(scale, roundingMethod)).doubleValue();
....
答案 3 :(得分:1)
在我看来,关键在于这句话:
BigDecimal(double val)
将double转换为BigDecimal,它是double的二进制浮点值的精确十进制表示。
与
BigDecimal(String val)
将BigDecimal的字符串表示形式转换为BigDecimal。
首先转到String,你只看到double为BigDecimal,但如果直接从double构造,你正在使用位级表示,我愿意打赌你会得到一个巧妙的不同的答案。请记住,浮点值使用64位的部分表示整个部分,一部分表示分数部分,一部分表示指数(在基数2中) - 它们都是非常深奥的东西,不同从机器到机器,我认为唯一正式的定义是在被诅咒的Necronomicon中找到的。
更新:Borodin说的是什么。
答案 4 :(得分:1)
然而,我发现了一个问题:
System.out.println(java.math.BigDecimal.valueOf(0.1000000000000000055511151231257827021181583404541015625).toString());
将打印 0.1 。
我认为关键是 java.lang.Double.toString(double d)。当我们输入 0.1 (在Java中,确切的值是 0.1000000000000000055511151231257827021181583404541015625 )时,函数将丢弃尾部,我们得到 0.1 。然而。如果我们输入 0.1000000000000000055511151231257827021181583404541015625 ,它总是会下降,我们也会得到 0.1 ,这与我们的预期不符。
所以我们必须意识到我们要求选择 java.math.BigDecimal.valueOf(double val)或 java.math.BigDecimal.BigDecimal(double val)