2014-01-27 42 views
12

添加相同的数字时,为什么输出不同?以不同的顺序添加相同的双打时的不同结果

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

如何获得相同的输出?

+11

没有违法,但为什么这么多upvotes?只是另一个浮点问题。答案每次都是一样的。 – Radiodef

回答

8

浮点数lose precision你做更多的操作。一般来说,通过首先添加最小的数字可以获得最高的精度。 (所以结果确实取决于操作的顺序)

除了保持相同的操作顺序,你也必须使用strictfp拿到不同平台上相同的结果。

或者更好的是,不使用浮动点:使用BigDecimal代替。

+0

你能解释为什么我们做更多的操作时会失去精确度吗?为什么我们通过首先添加最小的数字来获得最高的精度? – Keerthivasan

+0

@Octopus错误累积。请参阅:[传播错误](https://en.wikipedia.org/wiki/Propagation_of_uncertainty)。 (我想我应该停止链接维基百科,但我现在有点懒惰;) – Navin

+0

认为在10/3的例子。结果是3.333333 ...但计算机需要停止某个地方,所以它存储信息直到给定的精度。然后再次将它添加到10/3,并且最后这些被丢弃的数字将累积到您的操作的“错误”,并且这会继续 – Leo

0

因为双打和其他浮点数据类型有当您执行操作处理的四舍五入问题。精度不是无限的。如果将10/3分开,结果为3.33333333 ...但计算机仅存储此数字的一部分。

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

+0

这个答案没有解决为什么改变求和顺序对结果有影响的问题。 –

+0

我们可以显示位和字节,但解释是一样的...... – Leo

1

在浮点算术运算的一个序列中的每个步骤中,该系统具有以产生结果是在浮点格式表示的。这可能导致舍入误差,一些信息的丢失。

当添加不同大小的两个数字,较大的一个趋向于控制哪些位必须被丢弃。如果添加大数和小数,由于结果的大小,小数的许多比特将丢失舍入误差。添加相似数量的数字时,效果会降低。首先添加几个小数字,让大数量的数字结束,可以使小数字的影响积累起来。

例如,考虑{ 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左右的数字。

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