为什么在添加相同数字时输出会有所不同?
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
如何获得相同的输出?
浮点数数字会随着更多操作而失去精度。通常,首先添加最小的数字,您可以获得最高的精度。(因此结果 die 取决于操作的顺序)
除了维护相同的操作顺序外,您还必须使用Strictfp在不同平台上获得相同的结果。
或更好的是,不要使用浮点:改用bigdecimal。
在一个浮点算术操作序列的每个步骤中,系统必须产生以浮点格式表示的结果。这可能会导致四舍五入错误,丢失了一些信息。
添加两个不同的幅度时,较大的幅度倾向于控制哪些必须掉落。如果您添加一个大数量和少量数量,则由于结果的幅度很大,因此少量数量的许多位将丢失在舍入错误中。添加相似幅度的数量时,这种效果会降低。首先添加几个小数字,将较大的数字留在末端,使小数的效果累积。
例如,考虑{ 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的数字。
简单地添加所有值将导致较长数组的误差相对较大(或更确切地说:当总和已经"大"时,错误将是"大",并且还应添加进一步的"小"数字)。
作为减少数值错误的一种可能性,您可以考虑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;
}
,因为执行操作时,双打和其他浮点数据类型必须处理四舍五入问题。精度不是无限的。如果您将10/3划分,结果为3.33333333 ...但是计算机存储只是此数字的一部分。
检查http://floating-point-gui.de/