在Java中,使用double类型可以保持精度。

184
public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out.println(total);
    }
}

上面的代码输出:

11.399999999999

如何使其只打印(或者能够使用它作为) 11.4?


5
相关内容:浮点数运算是否存在问题? - Bernhard Barker
24个回答

5
        /*
        0.8                     1.2
        0.7                     1.3
        0.7000000000000002      2.3
        0.7999999999999998      4.2
        */
        double adjust = fToInt + 1.0 - orgV;
        
        // The following two lines works for me. 
        String s = String.format("%.2f", adjust);
        double val = Double.parseDouble(s);

        System.out.println(val); // output: 0.8, 0.7, 0.7, 0.8

4

请使用java.math.BigDecimal

由于Double在内部是二进制小数,所以它们有时无法精确表示十进制小数。


1
-1 盲目推荐 BigDecimal。如果你实际上不需要十进制算术(例如,如果你在处理货币计算),那么 BigDecimal 对你没有帮助。它不能解决所有浮点数错误:你仍然必须处理 1/3*3=0.9999999999999999999999999999 和 sqrt(2)**2=1.999999999999999999999999999。此外,BigDecimal 会带来巨大的速度惩罚。更糟糕的是,由于 Java 缺乏运算符重载,你必须重新编写所有代码。 - dan04
2
@dan04 - 如果您在进行货币计算时使用了浮点表示,为什么要知道其中固有的误差呢?由于没有几分之一美分,您可以使用小数并计算美分,而不是使用近似的美元数,您可以得到精确的美分金额。如果您真的想要使用几分之一美分,可以使用long类型变量并计算成千上万的美分。此外,OP没有提到无理数,他只关心加法。请仔细阅读帖子并理解问题,然后再回答,这可能会为您节省一些尴尬。 - Newtopian
3
@Newtopian:我没有什么好尴尬的。发帖者没有提到钱,也没有任何暗示他的问题与十进制数有任何内在联系。 - dan04
@ dan04 - 不,原帖作者并没有...是你自己。而且你盲目地提供了脱离上下文的观点,对于提供了很少细节的问题,最可能是一个完全可以接受的答案。 - Newtopian

3

浮点数是Java源代码中十进制数字的近似值。你看到的是双精度浮点数(double)和源代码(十进制编码)之间不匹配的结果。

Java会生成最接近的二进制近似值。你可以使用java.text.DecimalFormat来显示更好看的十进制值。


3
始终使用BigDecimal类,并确保你使用的是带String参数的构造函数,而不是double类型的构造函数。
回到你的示例,下面的代码将打印11.4,符合你的期望。
public class doublePrecision {
    public static void main(String[] args) {
      BigDecimal total = new BigDecimal("0");
      total = total.add(new BigDecimal("5.6"));
      total = total.add(new BigDecimal("5.8"));
      System.out.println(total);
    }
}

2

计算机以二进制方式存储数字,无法准确表示像33.333333333或100.0这样的数字。这是使用双精度浮点数时需要注意的一点。在向用户展示答案之前,您需要对其进行四舍五入处理。幸运的是,在大多数应用程序中,您不需要太多小数位。


我正在进行一些奇数计算,我希望拥有尽可能高的精度。但我知道存在一些限制。 - Aly

2
浮点数与实数的不同在于对于任何给定的浮点数,都有一个比它更高的浮点数存在。与整数相同。1和2之间没有整数。
无法将1/3表示为浮点数。它下面有一个浮点数,上面有一个浮点数,并且它们之间有一定的距离。而1/3就在那个空间里。
Java的Apfloat声称可以处理任意精度的浮点数,但我从未使用过。可能值得一看。 http://www.apfloat.org/apfloat_java/ 此前也有类似的问题: Java浮点高精度库

2
把所有数都乘以100并存储到long类型中作为分。

2
@Draemon - 看看最后一次编辑之前的帖子 - 所有那些“shoppingTotal”、“calcGST”和“calcPST”的东西对我来说都像是钱。 - Paul Tomblin

1
为什么不使用 Math 类中的 round() 方法?
// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4

1
使用BigDecimal。它甚至允许您指定舍入规则(例如ROUND_HALF_EVEN,如果两个相邻数字距离相等,则通过四舍五入到偶数邻居来最小化统计误差;即1.5和2.5都会四舍五入为2)。

0
如果您除了使用双精度值之外别无选择,可以使用以下代码。
public static double sumDouble(double value1, double value2) {
    double sum = 0.0;
    String value1Str = Double.toString(value1);
    int decimalIndex = value1Str.indexOf(".");
    int value1Precision = 0;
    if (decimalIndex != -1) {
        value1Precision = (value1Str.length() - 1) - decimalIndex;
    }

    String value2Str = Double.toString(value2);
    decimalIndex = value2Str.indexOf(".");
    int value2Precision = 0;
    if (decimalIndex != -1) {
        value2Precision = (value2Str.length() - 1) - decimalIndex;
    }

    int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
    sum = value1 + value2;
    String s = String.format("%." + maxPrecision + "f", sum);
    sum = Double.parseDouble(s);
    return sum;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接