在Java中保留double的精度

问题

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?


#1 热门回答(112 赞)

正如其他人所提到的,如果你想要一个11.4的精确表示,你可能想要使用31640991class。

现在,解释为什么会发生这种情况:

Java中的floatdouble原型类型是floating pointnumbers,其中数字存储为分数和指数的二进制表示。

更具体地说,双精度浮点值,如doubletype是64位值,其中:

  • 1位表示符号(正或负)。
  • 指数为11位。
  • 有效数字为52位(小数部分为二进制)。

这些部分组合在一起产生一个值的代表。

(来源:Wikipedia: Double precision)

有关如何在Java中处理浮点值的详细说明,请参阅Java语言规范的Section 4.2.3: Floating-Point Types, Formats, and Values

630302428,char,int,long类型是fixed-point个数字,它们是数字的精确表示。与定点数不同,浮点数有时会(可以安全地假设"大部分时间")无法返回数字的精确表示。这就是为什么你最终得到11.399999999999的结果5.6 + 5.8

当需要精确的值(例如1.5或150.1005)时,你将需要使用其中一种定点类型,它们能够准确地表示数字。

正如已经多次提到的那样,Java有一个BigDecimal类,可以处理非常大的数字和非常小的数字。

来自BigDecimal类的Java API参考:

不可变,任意精度的带符号十进制数。 BigDecimal由任意精度整数非标度值和32位整数标度组成。如果为零或正数,则比例是小数点右侧的位数。如果是负数,则将数字的未缩放值乘以10来表示比例的否定。因此,BigDecimal表示的数字的值是(unscaledValue×10 ^ -scale)。

Stack Overflow上有很多关于浮点数及其精度的问题。以下是可能感兴趣的相关问题列表:

  • 为什么我看到一个双变量初始化为某个值,如21.4为21.399999618530273?
  • 如何在C中打印真正的大数字
  • 如何存储浮点数?什么时候重要?
  • 使用Float或Decimal作为会计应用程序的美元金额?

如果你真的想了解浮点数的细节,请看看What Every Computer Scientist Should Know About Floating-Point Arithmetic


#2 热门回答(95 赞)

当你输入双精度数(例如,33.33333333333333)时,你获得的值实际上是最接近的可表示的双精度值,它恰好是:

33.3333333333333285963817615993320941925048828125

除以100得出:

0.333333333333333285963817615993320941925048828125

它也不能表示为双精度数,因此它再次舍入到最接近的可表示值,这恰好是:

0.3333333333333332593184650249895639717578887939453125

当你打印出这个值时,它再次获得roundyet到17个十进制数字,给出:

0.33333333333333326

#3 热门回答(23 赞)

如果你只想将值作为分数处理,则可以创建一个包含分子和分母字段的Fraction类。

编写加,减,乘和除的方法以及toDouble方法。这样,你可以在计算过程中避免浮动。

编辑:快速实施,

public class Fraction {

private int numerator;
private int denominator;

public Fraction(int n, int d){
    numerator = n;
    denominator = d;
}

public double toDouble(){
    return ((double)numerator)/((double)denominator);
}


public static Fraction add(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop + bTop, a.denominator * b.denominator);
    }
    else{
        return new Fraction(a.numerator + b.numerator, a.denominator);
    }
}

public static Fraction divide(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}

public static Fraction multiply(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}

public static Fraction subtract(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop-bTop, a.denominator*b.denominator);
    }
    else{
        return new Fraction(a.numerator - b.numerator, a.denominator);
    }
}

}