2011-11-10 61 views
5

在Apache的百科全书对于round来源是这样的:为什么我们需要将double转换为字符串,然后才能将其转换为BigDecimal?

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.toString),而不是简单地使用双待双转换为字符串本身?

换句话说,这有什么问题? :

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

回答

7

这是因为在javadoc中提到的BigDecimal(double)构造函数的结果是不可预知的。

人们可能会认为写入new BigDecimal(0.1)在Java中创建一个 BigDecimal正好等于0。1(1未测量的值,与 比例为1),但它实际上是等于 0.1000000000000000055511151231257827021181583404541015625

String构造,在另一方面,是完全可以预测的: 写入new BigDecimal(“0.1”)正如人们所期望的那样,创建一个等于0.1的BigDecimal,正是 。因此,一般建议 使用String构造函数而不是此 之一。

测试用例:

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

@@致谢谢谢! – Pacerier

1

您不必转换为字符串。
使用静态方法BigDecimal.valueOf(double val)

要在代码中使用:

... 
return (BigDecimal.valueOf(x).setScale(scale, roundingMethod)).doubleValue(); 
.... 
+0

该文档写道:BigDecimal.valueOf(x)'相当于'new java.math.BigDecimal(Double.toString(x))',所以基本上我想知道'new java.math .BigDecimal(Double.toString(x))''和'new java.math.BigDecimal(x)'? – Pacerier

+0

如果这就是它的实现方式,那就这样吧。这在未来的JDK中可能会发生变化。关注API - 实现不应该担心你(除非它真的影响你的设计决策,这可能意味着你的设计在某种程度上存在缺陷) – Bohemian

4

从文档here的构造BigDecimal(String val)

注:对于不是float和double NaN以外的值和±Infinity,这个 构造函数与由 Float.toString(float)和Double.toString(double)返回的值兼容。这通常是 将float或double转换为BigDecimal的首选方式,因为它不受BigDecimal(double) 构造函数的不可预测性影响。

+0

如果你真的想看到不同之处,记得BigDecimal源代码是可用。 http://www.docjar.com/html/api/java/math/BigDecimal.java.html – madth3

1

在我看来,关键是在此声明:

的BigDecimal(double val)将
double转换为BigDecimal,后者是double的二进制浮点的准确的十进制表示值。

的BigDecimal(字符串VAL)
将BigDecimal的字符串表示转换为BigDecimal。

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

更新:什么Borodin说。

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)将

+0

是的,如果我们想要工作,我们必须'new java.math.BigDecimal(“0.1000000000000000055511151231257827021181583404541015625”)' – Pacerier

相关问题