将 double 转换为 BigDecimal 并设置 BigDecimal 精度

Posted

技术标签:

【中文标题】将 double 转换为 BigDecimal 并设置 BigDecimal 精度【英文标题】:Convert double to BigDecimal and set BigDecimal Precision 【发布时间】: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 有时也会使用科学记数法(我相信数字 【参考方案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);

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

【讨论】:

不推荐使用双重构造函数。 ***.com/questions/1056722/… 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

【讨论】:

以上是关于将 double 转换为 BigDecimal 并设置 BigDecimal 精度的主要内容,如果未能解决你的问题,请参考以下文章

BigDecimal类的用法

Scala 将BigDecimal转换为Long

java - 如何将浮点数转换为 BigDecimal? [复制]

如何修复java.lang.ClassCastException:java.lang.Double无法转换为变量表达式的java.math.BigDecimal错误?

BigDecimal与double

BigDecimal类的加减乘除