为什么我们需要将double转换为字符串,然后才能将其转换为BigDecimal?

时间:2011-11-10 01:17:04

标签: java math

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;
        }
    }
}

5 个答案:

答案 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)