以不同顺序添加相同的双精度时的结果不同

时间:2014-01-27 05:50:26

标签: java floating-point floating-accuracy

为什么添加相同数字时输出会有所不同?

public class Test {

    public static void main(String a[]) {

        double[] x = new double[]{3.9, 4.3, 3.6, 1.3, 2.6};
        System.out.println(">>>>>>> " + sum(x));
    }

    public static double sum(double[] d) {

        double sum = 0;
        for (int i = 0; i < d.length; i++) {
            sum += d[i];
        }
        return sum;
    }
}

输出为:15.7

如果我互换价值

double[] x = new double[] {2.6, 3.9, 4.3, 3.6, 1.3};

我的输出为:15.700000000000001

如何获得相同的输出?

4 个答案:

答案 0 :(得分:11)

当您执行更多操作时,浮点数lose precision。通常,通过首先添加最小数字来获得最高精度。 (因此结果 取决于操作的顺序)

除了保持相同的操作顺序外,您还必须使用strictfp在不同平台上获得相同的结果。

或者更好的是,不要使用浮点数:改为使用BigDecimal

答案 1 :(得分:2)

在一系列浮点算术运算的每一步中,系统必须产生一个可以浮点格式表示的结果。这可能会导致舍入错误,丢失一些信息。

当添加两个不同大小的数字时,较大的一个倾向于控制必须丢弃哪些位。如果添加一个大数字和一个小数字,由于结果的大小,很小的数字位将丢失到舍入误差。当添加相似幅度的数字时,该效果会减少。首先添加几个小数字,将大量数字留到最后,允许小数字的影响累积。

例如,考虑{ 1e17, 21.0, 21.0, 21.0, 21.0, 21.0, 21.0, 21.0, -1e17 }。确切的答案,没有任何舍入,将是147.按上面显示的顺序添加给出112.每次添加“21.0”必须舍入到适合数量大约1e17的数字。按绝对量值的升序加上144,更接近确切的答案。添加7个小数字的部分结果正好是147,然后必须进行舍入以适合1e17左右的数字。

答案 2 :(得分:0)

因为双精度数据和其他浮点数据类型在执行操作时必须处理舍入问题。精度不是无限的。如果除以10/3,结果为3.33333333 ...但计算机只存储此数字的一部分。

检查http://floating-point-gui.de/

答案 3 :(得分:0)

无论如何,简单地将所有值相加将导致更长阵列的相对较大的误差(或者更确切地说:当总和已经“大”时,误差将是“大”,并且应该添加更多“小”数字)。

作为减少数字错误的一种可能性,您可以考虑http://en.wikipedia.org/wiki/Kahan_summation_algorithm

public static double kahanSum(double d[])
{
    double sum = 0.0;
    double c = 0.0;
    for (int i=0; i<d.length; i++)
    {
        double y = d[i] - c;
        double t = sum + y;
        c = (t - sum) - y;
        sum = t;
    }
    return sum;        
}