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

Java 为什么我们需要先将double转换为字符串,然后才能将其转换为BigDecimal?,java,math,Java,Math,apache commons中的源代码如下所示: 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 e

apache commons中的源代码如下所示:

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

您不必转换为字符串。
使用静态方法:

要在代码中使用:

...
return (BigDecimal.valueOf(x).setScale(scale, roundingMethod)).doubleValue();
....
从构造函数的文档
BigDecimal(String val)

注:对于浮点、双NaN和±无穷大以外的值,此 构造函数与 Float.toString(Float)和Double.toString(Double)。这通常是 将float或double转换为BigDecimal的首选方法,如 它不受BigDecimal(double)不可预测性的影响 构造器


在我看来,关键在于这句话:

BigDecimal(双值)
将double转换为BigDecimal,BigDecimal是双精度二进制浮点值的精确十进制表示形式

BigDecimal(字符串val)
将BigDecimal的字符串表示形式转换为BigDecimal

通过首先使用字符串,您只会看到double是BigDecimal,但是如果直接从double构造,您将使用位级表示,我敢打赌您将得到一个微妙的不同答案。请记住,浮点值是用64位的一部分表示整个部分,用一部分表示分数部分,用一部分表示指数(在基数2中)——这都是非常深奥的东西,不同的机器不同,我认为唯一的形式定义是在《诅咒》中找到的


更新:怎么说。

这是因为
BigDecimal(double)
构造函数的结果是不可预测的,正如javadoc中提到的那样

有人可能会认为,在Java中编写新的BigDecimal(0.1)会创建 BigDecimal正好等于0.1(未标度值为1,带 比例为1),但实际上等于 0.10000000000000055115123125782702118158340454015625

另一方面,字符串构造函数是完全可预测的: 写入新的BigDecimal(“0.1”)将创建一个完全相同的BigDecimal 等于0.1,正如人们所料。因此,一般来说 建议优先使用字符串构造函数 一个

测试用例:

System.out.println(java.math.BigDecimal.valueOf(0.1).toString());
System.out.println(new java.math.BigDecimal(0.1).toString());

然而,我发现了一个问题:

System.out.println(java.math.BigDecimal.valueOf(0.1000000000000000055511151231257827021181583404541015625).toString());
它将打印0.1

我认为关键是java.lang.Double.toString(双d)。当我们输入0.1(在Java中,精确值为0.10000000000000055115123125782702118158340451015625)时,函数将掉尾,我们得到0.1。然而。如果我们输入0.10000000000000055115123125782702118158340454015625,它总是掉尾,我们也得到0.1,这与我们的预期相反


因此,我们必须了解选择java.math.BigDecimal.valueOf(double-val)java.math.BigDecimal.BigDecimal(double-val)

的要求,文档写道
BigDecimal.valueOf(x)
相当于做
新的java.math.BigDecimal(double.toString(x))
,所以基本上我想知道
新java.math.BigDecimal(Double.toString(x))
新java.math.BigDecimal(x)
之间有什么区别?如果这就是它的实现方式,那就这样吧。这在未来的JDK中可能会改变。关注API——实现不应该让您担心(当然,除非它确实影响您的设计决策,这可能意味着您的设计在某些方面存在缺陷),如果您真的想看到差异,请记住BigDecimal源代码是可用的。是的,如果我们想让它起作用,我们必须
新建java.math.BigDecimal(“0.1000000000000005555115123125782702118158340451015625”)