Different results when adding same doubles in different order

五迷三道 提交于 2021-02-18 20:09:48

问题


Why is the output different when adding same numbers?

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;
    }
}

Output is : 15.7

and if I interchange values

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

I am getting Output as : 15.700000000000001

How do I get the same Output ?


回答1:


Floating point numbers lose precision as you do more operations. Generally, you get the highest precision by adding the smallest numbers first. (So the result does depend on the order of operations)

In addition to maintaining the same order of operations, you'll also have to use strictfp to get the same result on different platforms.

Or better yet, don't use floating points: use a BigDecimal instead.




回答2:


At each step in a sequence of floating point arithmetic operations, the system has to produce a result that is representable in the floating point format. That may lead to rounding error, the loss of some information.

When adding two numbers of different magnitudes, the larger one tends to control which bits have to be dropped. If you add a large and a small number, many bits of the small number will be lost to rounding error, because of the large magnitude of the result. That effect is reduced when adding numbers of similar magnitude. Adding several small numbers first, leaving the large magnitude numbers to the end, allows the effect of the small numbers to accumulate.

For example, consider { 1e17, 21.0, 21.0, 21.0, 21.0, 21.0, 21.0, 21.0, -1e17 }. The exact answer, without any rounding, would be 147. Adding in the order shown above gives 112. Each addition of a "21.0" has to be rounded to fit in a number with magnitude around 1e17. Adding in ascending order of absolute magnitude gives 144, much closer to the exact answer. The partial result of adding the 7 small numbers is exactly 147, which then has to be rounded to fit in a number around 1e17.




回答3:


Simply adding up all the values will lead to a comparatively large error for longer arrays anyhow (or more precisely: the error will be "large" when the sum already is "large", and further "small" numbers should be added).

As one possibility to reduce the numerical error, you might consider the 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;        
}



回答4:


because doubles and other floating-point data types have to deal with rounding issues when you perform operations. The precision is not infinite. If you divide 10/3, the result is 3.33333333... but the computer stores just part of this number.

check http://floating-point-gui.de/



来源:https://stackoverflow.com/questions/21373865/different-results-when-adding-same-doubles-in-different-order

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!