88

在 Java 中,我想取一个 double 值并将其转换为 aBigDecimal并将其 String 值打印到一定精度。

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 可以限制转换为字符串的精度吗?

4

8 回答 8

139

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

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

此构造函数的结果可能有些不可预测。有人可能会假设用 Java 编写 new BigDecimal(0.1) 会创建一个正好等于 0.1 的 BigDecimal(未缩放的值 1,缩放为 1),但它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 不能完全表示为双精度数(或者,就此而言,不能表示为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于 0.1,尽管看起来如此。

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

double val = 77.48;
new BigDecimal(val);

采用

BigDecimal.valueOf(val);

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

于 2013-05-27T13:24:34.470 回答
63

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

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

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

于 2012-09-12T19:57:52.480 回答
19

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

关于精度问题:您首先存储47.48在 中double c,然后从中制作新BigDecimaldouble. 精度的损失在于分配给c。你可以做

BigDecimal b = new BigDecimal("47.48")

以避免丢失任何精度。

于 2012-09-12T20:00:22.913 回答
8

为什么不 :

b = b.setScale(2, RoundingMode.HALF_UP);
于 2016-10-20T07:21:49.563 回答
6

它打印出double.

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

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

于 2012-09-12T20:07:44.770 回答
3

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
于 2013-03-07T07:50:53.480 回答
2
BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP);
于 2017-05-05T02:18:35.270 回答
1

在 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
于 2017-12-01T13:59:55.270 回答