簡體   English   中英

如何最好地總結大量浮點數?

[英]How best to sum up lots of floating point numbers?

想象一下,您有一大堆各種大小的浮點數。 計算總和的最正確方法是什么,誤差最小? 例如,當數組如下所示時:

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

然后你用一個簡單的循環從左到右加起來,比如

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

每當您加起來時,較小的數字可能會低於精度閾值,因此誤差會越來越大。 據我所知,最好的方法是對數組進行排序並開始從最低到最高的數字相加,但我想知道是否有更好的方法(更快、更精確)?

編輯:感謝您的回答,我現在有一個工作代碼,可以完美地總結 Java 中的雙精度值。 這是來自獲勝答案的 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;
    }
}

為了“更精確”: Python Cookbook 中的這個配方具有保持完整精度的求和算法(通過跟蹤小計)。 代碼是用 Python 編寫的,但即使您不了解 Python,它也足夠清晰以適應任何其他語言。

所有細節都在本文中給出。

另請參閱: Kahan summation algorithm它不需要 O(n) 存儲,而只需要 O(1)。

有很多算法,取決於你想要什么。 通常他們需要跟蹤部分總和。 如果只保留 x[k+1] - x[k] 的總和,則會得到 Kahan 算法。 如果您跟蹤所有部分和(因此產生 O(n^2) 算法),您會得到 @dF 的答案。

請注意,除了您的問題之外,對不同符號的數量求和是非常有問題的。

現在,有比跟蹤所有部分總和更簡單的方法:

  • 在求和之前對數字進行排序,獨立求和所有負數和正數。 如果您對數字進行了排序,那很好,否則您將使用 O(n log n) 算法。 通過增加幅度求和。
  • 按對求和,然后成對求和,等等。

個人經驗表明,您通常不需要比卡漢的方法更花哨的東西。

好吧,如果你不想排序,那么你可以簡單地將總數保存在一個比單個值精度更高的變量中(例如,使用 double 來保持浮點數的總和,或使用“quad”來保持雙打總和)。 這將施加性能損失,但它可能低於排序成本。

如果您的應用程序依賴於對任意精度算術庫的數字處理搜索,但是我不知道是否有這種 Python 庫。 當然,這一切都取決於您想要多少個精度數字——如果您小心使用標准 IEEE 浮點數,您可以獲得良好的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM