“新BigDecimal(13.3D)”导致不精确的“13.3000000000000007105 ..”?

时间:2009-01-20 10:36:26

标签: java precision bigdecimal

Java的BigDecimal怎么会这么痛苦?

Double d = 13.3D;

BigDecimal bd1 = new BigDecimal(d);
BigDecimal bd2 = new BigDecimal(String.valueOf(d));


System.out.println("RESULT 1: "+bd1.toString());
System.out.println("RESULT 2: "+bd2.toString());

RESULT 1: 13.300000000000000710542735760100185871124267578125
RESULT 2: 13.3

是否存在需要结果1的情况?我知道Java 1.5改变了toString()方法,但这是预期的后果吗?

我也意识到BigDecimaldoubleValue()等,但我正在使用的图书馆使用了toString()并且我无法改变: - (

干杯。

5 个答案:

答案 0 :(得分:50)

好吧,API确实解决了构造函数BigDecimal(double val)中明显不一致的问题:

  
      
  1. 此构造函数的结果可能有些不可预测。有人可能   假设写新   Java中的BigDecimal(0.1)创建了一个   BigDecimal完全等于   0.1(未缩放值为1,刻度为1),但实际上是相等的   至   0.1000000000000000055511151231257827021181583404541015625。这是因为0.1 不能   完全代表双重(或   就此而言,作为二元分数   任何有限长度)。因此,价值   正在被传递到   构造函数不完全等于   0.1,尽管有外表。

  2.   
  3. 另一方面,String构造函数是完全可预测的:   写新的BigDecimal(“0.1”)创建   一个完全等于的BigDecimal   0.1,正如人们所期望的那样。因此,一般建议使用   可以使用字符串构造函数   偏好这个。

  4.   
  5. 当必须将double用作BigDecimal 的来源时,请注意   这个构造函数提供了精确的   转换;它没有给出相同的   结果将double转换为a   字符串使用   Double.toString(double)方法和   然后使用BigDecimal(String)   构造函数。要获得该结果,使用   静态valueOf(double)方法

  6.   

故事的道德:痛苦似乎是自己造成的,只需使用new BigDecimal(String val)BigDecimal.valueOf(double val)代替=)

答案 1 :(得分:11)

您的问题与BigDecimal以及Double的所有内容无关,因为它在内部使用二进制分数,因此无法准确表示13.3。

所以你的错误是在第一行引入的。第一个BigDecimal只是保留了它,而String.valueOf()做了一些可疑的圆形,导致第二个具有所需的内容,几乎是通过运气。

答案 2 :(得分:8)

您可能想要了解浮点值的实现方式(IEEE 754-1985)。突然之间,一切都会变得清晰。

答案 3 :(得分:5)

这不是BigDecimal的错误 - 这是double的错误。 BigDecimal准确表示d完全值。 String.valueOf仅将结果显示为小数位。

答案 4 :(得分:3)

以二进制数字类型表示的分数(即doublefloat)无法准确存储在这些类型中。

    Double d = 13.3;        
    BigDecimal bdNotOk = new BigDecimal(d);
    System.out.println("not ok: " + bdNotOk.toString());

    BigDecimal bdNotOk2 = new BigDecimal(13.3);
    System.out.println("not ok2: " + bdNotOk2.toString());

    double x = 13.3;
    BigDecimal ok = BigDecimal.valueOf(x);
    System.out.println("ok: " + ok.toString());

    double y = 13.3;
    // pretty lame, constructor's behavior is different from valueOf static method
    BigDecimal bdNotOk3 = new BigDecimal(y);
    System.out.println("not ok3: " + bdNotOk3.toString());

    BigDecimal ok2 = new BigDecimal("13.3");
    System.out.println("ok2: " + ok2.toString());

    Double e = 0.0;
    for(int i = 0; i < 10; ++i) e = e + 0.1; // some fractions cannot be accurately represented with binary
    System.out.println("not ok4: " + e.toString()); // should be 1


    BigDecimal notOk5 = BigDecimal.valueOf(e);
    System.out.println("not ok5: " + notOk5.toString()); // should be 1

    /* 
     * here are some fractions that can be represented exactly in binary:
     * 0.5   = 0.1   = 1 / 2
     * 0.25  = 0.01  = 1 / 4
     * 0.75  = 0.11  = 3 / 4
     * 0.125 = 0.001 = 1 / 8
     */

输出:

not ok: 13.300000000000000710542735760100185871124267578125
not ok2: 13.300000000000000710542735760100185871124267578125
ok: 13.3
not ok3: 13.300000000000000710542735760100185871124267578125
ok2: 13.3
not ok4: 0.9999999999999999
not ok5: 0.9999999999999999

只需使用 BigDecimal.valueOf(d) new BigDecimal(s)