【问题标题】:"new BigDecimal(13.3D)" results in imprecise "13.3000000000000007105.."?“new BigDecimal(13.3D)”导致不精确的“13.3000000000000007105..”?
【发布时间】:2009-01-20 10:36:26
【问题描述】:

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(),我无法更改它:-(

干杯。

【问题讨论】:

  • 其实 toString() 版本可能就是你想要的。十进制数不能正确地表示为双精度数,虽然 BigDecimals 解决了这个问题,但在构造函数中给它们一个双精度数会破坏解决方案,因为它们没有一个准确的数字作为起点。

标签: java precision bigdecimal


【解决方案1】:

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

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

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

  3. 当必须使用双精度作为 BigDecimal 的源时,请注意 这个构造函数提供了一个精确的 转换;它不一样 结果将双精度转换为 字符串使用 Double.toString(double) 方法和 然后使用 BigDecimal(String) 构造函数。要获得该结果,请使用 静态 valueOf(double) 方法

故事的寓意:痛苦似乎是自己造成的,请改用new BigDecimal(String val)BigDecimal.valueOf(double val) =)

【讨论】:

  • +1:这就是 Double 真正起作用的方式。与 BigDecimal 关系不大。
  • 不错的一个。所以真的有人应该向我扔一个 RTFM ;-)
  • 请注意, new BigDecimal(d+"") 也可以正常工作。结果是“13.3”,就像使用 valueOf(d) 时一样
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    您可能想了解一下浮点值是如何实现的 (IEEE 754-1985)。突然间,一切都会变得晶莹剔透。

    【讨论】:

      【解决方案4】:

      这不是 BigDecimal 的错 - 这是 double 的错。 BigDecimal 准确地表示了d精确 值。 String.valueOf 只显示小数点后几位的结果。

      【讨论】:

        【解决方案5】:

        用二进制数类型(即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)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-06-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-03
          • 1970-01-01
          • 2013-03-05
          相关资源
          最近更新 更多