<p>假设您有一个很大的浮点数数组,各种大小。哪种计算和的方法最正确,误差最小?例如,当数组如下所示时:</p>
<pre><code>[1.0, 1e-10, 1e-10, ... 1e-10.0]
</code></pre>
<p>从左到右加上一个简单的循环,比如</p>
<pre><code>sum = 0
numbers.each do |val|
sum += val
end
</code></pre>
<p>每当你加起来,较小的数字可能会低于精度阈值,因此误差会越来越大。据我所知,最好的方法是对数组进行排序,并开始从最低到最高的数字相加,但我想知道是否有更好的方法(更快、更精确)?</p>
<p><strong>编辑</strong>:感谢您的回答,我现在有了一个工作代码,它完美地总结了Java中的两个值。这是一个直接从Python端口发送的获胜答案。这个解决方案通过了我所有的单元测试。(这里有一个更长但优化的版本<a href="http://github.com/martinus/java-playground/tree/master/src/java/com/ankerl/math/Summarizer.java" rel="noreferrer">Summarizer.java</a>)</p>
<pre><code>/**
* Adds up numbers in an array with perfect precision, and in O(n).
*
* @see http://code.activestate.com/recipes/393090/
*/
public class Summarizer {
/**
* Perfectly sums up numbers, without rounding errors (if at all possible).
*
* @param values
* The values to sum up.
* @return The sum.
*/
public static double msum(double... values) {
List<Double> partials = new ArrayList<Double>();
for (double x : values) {
int i = 0;
for (double y : partials) {
if (Math.abs(x) < Math.abs(y)) {
double tmp = x;
x = y;
y = tmp;
}
double hi = x + y;
double lo = y - (hi - x);
if (lo != 0.0) {
partials.set(i, lo);
++i;
}
x = hi;
}
if (i < partials.size()) {
partials.set(i, x);
partials.subList(i + 1, partials.size()).clear();
} else {
partials.add(x);
}
}
return sum(partials);
}
/**
* Sums up the rest of the partial numbers which cannot be summed up without
* loss of precision.
*/
public static double sum(Collection<Double> values) {
double s = 0.0;
for (Double d : values) {
s += d;
}
return s;
}
}
</code></pre>