【问题标题】:Convert double to BigDecimal and set BigDecimal Precision将 double 转换为 BigDecimal 并设置 BigDecimal 精度
【发布时间】:2012-09-05 21:25:41
【问题描述】:

在 Java 中,我想获取一个双精度值并将其转换为 BigDecimal 并将其字符串值打印到一定精度。

import java.math.BigDecimal;
public class Main {
    public static void main(String[] args) {
        double d=-.00012;
        System.out.println(d+""); //This prints -1.2E-4

        double c=47.48000;
        BigDecimal b = new BigDecimal(c);
        System.out.println(b.toString()); 
        //This prints 47.47999999999999687361196265555918216705322265625 
    }
}

它打印出这个巨大的东西:

47.47999999999999687361196265555918216705322265625

而不是

47.48

我进行BigDecimal 转换的原因是有时双精度值会包含很多小数位(即-.000012),而将双精度值转换为字符串时会产生科学记数法-1.2E-4。我想以非科学记数法存储字符串值。

我希望 BigDecimal 始终具有两个精度单位,例如:“47.48”。 BigDecimal 可以限制转换为字符串的精度吗?

【问题讨论】:

  • 注意:BigDecimal 有时也会使用科学记数法(我相信数字

标签: java double bigdecimal


【解决方案1】:

这种行为的原因是打印的字符串是准确的值 - 可能不是你所期望的,但这是存储在内存中的真实值 - 这只是浮点表示的限制。

根据 javadoc,如果不考虑此限制,BigDecimal(double val) 构造函数的行为可能会出乎意料:

此构造函数的结果可能有些不可预测。一 可能会假设用 Java 编写 new BigDecimal(0.1) 会创建一个 BigDecimal 正好等于 0.1(未缩放的值 1,与 比例为 1),但实际上等于 0.10000000000000000055511151231257827021181583404541015625。这是因为 0.1 不能完全表示为双精度数(或者,对于 物质,作为任何有限长度的二进制分数)。因此,价值 传递给构造函数的不完全等于 0.1,尽管出现了。

所以在你的情况下,而不是使用

double val = 77.48;
new BigDecimal(val);

使用

BigDecimal.valueOf(val);

BigDecimal.valueOf 返回的值等于调用Double.toString(double) 产生的值。

【讨论】:

  • 今天遇到了完全相同的问题,恕我直言,这是最合适的答案!谢谢!
  • 我建议在BigDecimal.valueOf(val) 之后添加.stripTrailingZeros() 以省略尾随零。示例:BigDecimal.valueOf(15.0).stripTrailingZeros(); -> 15(如果您不调用 .stripTrailingZeros(),则不是 15.0@
【解决方案2】:

如果您使用另一个 MathContext,它会打印 47.48000:

BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64);

只需选择您需要的上下文。

【讨论】:

  • 不推荐使用双重构造函数。
  • BigDecimal b = BigDecimal.valueOf(d);
  • @rvazquezglez 喜欢你的解决方案
  • 其他值仍然存在缺陷。例如new BigDecimal( 1E-11, MathContext.DECIMAL64).toPlainString() 打印0.000000000009999999999999999,但BigDecimal.valueOf 按预期工作。
【解决方案3】:

您想尝试String.format("%f", d),它将以十进制表示法打印您的双精度数。根本不要使用BigDecimal

关于精度问题:您首先将47.48 存储在double c 中,然后从该double 中创建一个新的BigDecimal。精确度的损失在于分配给c。你可以这样做

BigDecimal b = new BigDecimal("47.48")

避免丢失任何精度。

【讨论】:

    【解决方案4】:

    为什么不:

    b = b.setScale(2, RoundingMode.HALF_UP);
    

    【讨论】:

    • 为什么不 BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP);
    【解决方案5】:

    它正在打印出double 的实际准确值。

    Double.toString(),将doubles 转换为Strings, 打印输入的确切十进制值——如果x 是您的双精度值,它会打印出足够的数字,x 是最接近它打印的值的double

    关键是 没有像 47.48 这样的double。 Doubles 将值存储为 binary 分数,而不是小数,因此它不能存储精确的十进制值。 (这就是BigDecimal 的用途!)

    【讨论】:

      【解决方案6】:

      String.format 语法帮助我们将双精度数和 BigDecimals 转换为任何精度的字符串。

      这个java代码:

      double dennis = 0.00000008880000d;
      System.out.println(dennis);
      System.out.println(String.format("%.7f", dennis));
      System.out.println(String.format("%.9f", new BigDecimal(dennis)));
      System.out.println(String.format("%.19f", new BigDecimal(dennis)));
      

      打印:

      8.88E-8
      0.0000001
      0.000000089
      0.0000000888000000000
      

      【讨论】:

        【解决方案7】:
        BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP);
        

        【讨论】:

          【解决方案8】:

          在 Java 9 中,以下内容已被弃用:

          BigDecimal.valueOf(d).setScale(2, BigDecimal.ROUND_HALF_UP);

          改为使用:

          BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP);
          

          例子:

              double d = 47.48111;
          
              System.out.println(BigDecimal.valueOf(d)); //Prints: 47.48111
          
              BigDecimal bigDecimal = BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP);
              System.out.println(bigDecimal); //Prints: 47.48
          

          【讨论】:

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