39

あらゆる種類のサイズの浮動小数点数の大きな配列があるとします。誤差が最も少なく、合計を計算する最も正しい方法は何ですか? たとえば、配列が次のようになっている場合:

[1.0, 1e-10, 1e-10, ... 1e-10.0]

次のような単純なループで左から右に合計します

sum = 0
numbers.each do |val|
    sum += val
end

小さい数値を合計すると、精度のしきい値を下回る可能性があるため、エラーがどんどん大きくなります。私の知る限り、最良の方法は、配列を並べ替えて、数値を最小から最大に加算することですが、もっと良い方法 (より速く、より正確) があるかどうか疑問に思っています。

編集:答えてくれてありがとう、Javaでdouble値を完全に合計する作業コードができました。これは、勝利した回答の Python 投稿からのストレート ポートです。ソリューションは、すべての単体テストに合格します。(これのより長いが最適化されたバージョンは、ここで利用可能ですSummarizer.java )

/**
 * 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;
    }
}
4

5 に答える 5

24

「より正確に」: Python クックブックのこのレシピには、 (小計を追跡することによって) 完全な精度を維持する合計アルゴリズムがあります。コードは Python で書かれていますが、Python を知らなくても、他の言語に適応できるほど明確です。

すべての詳細はこのペーパーに記載されています。

于 2008-12-26T19:46:02.060 に答える
15

参照: Kahan 総和アルゴリズムO(n) ストレージは必要なく、O(1) のみが必要です。

于 2009-01-27T22:30:56.523 に答える
5

必要なものに応じて、多くのアルゴリズムがあります。通常、それらは部分的な合計を追跡する必要があります。合計x[k+ 1]-x [k]のみを保持すると、カハンアルゴリズムが得られます。すべての部分和を追跡すると(したがって、O(n ^ 2)アルゴリズムが生成されます)、@dFの答えが得られます。

あなたの問題に加えて、異なる符号の数を合計することは非常に問題があることに注意してください。

現在、すべての部分的な合計を追跡するよりも簡単なレシピがあります。

  • 合計する前に数値を並べ替え、すべてのネガティブとポジティブを個別に合計します。数値を並べ替えた場合は問題ありません。そうでない場合は、O(n log n)アルゴリズムを使用します。マグニチュードを増やして合計します。
  • ペアで合計し、次にペアのペアなど。

個人的な経験によれば、通常、カハンの方法よりも凝ったものは必要ありません。

于 2010-12-30T14:07:55.103 に答える
0

アプリケーションが任意精度の算術ライブラリの数値処理検索に依存している場合、この種の Python ライブラリがあるかどうかはわかりません。もちろん、必要な精度の桁数によってすべてが異なります。注意して使用すれば、標準の IEEE 浮動小数点で良い結果を得ることができます。

于 2008-12-26T21:09:21.470 に答える
0

ソートしたくない場合は、個々の値よりも精度の高い型の変数に合計を単純に保持できます (たとえば、浮動小数点数の合計を保持するには double を使用し、浮動小数点数を保持するには「quad」を使用します)。 double の合計)。これによりパフォーマンスが低下しますが、並べ替えのコストよりも少ない可能性があります。

于 2008-12-26T21:02:12.267 に答える