web-dev-qa-db-ja.com

順序付けられた数値の効率的な安定合計

浮動小数点正数のかなり長いリストがあります(std::vector<float>、サイズ〜1000)。番号は降順でソートされます。順序に従ってそれらを合計すると:

for (auto v : vec) { sum += v; }

ベクトルの終わり近くでsumvよりはるかに大きくなるため、数値の安定性の問題が発生する可能性があると思います。最も簡単な解決策は、ベクトルを逆の順序でトラバースすることです。私の質問は、前向きの場合と同様に効率的ですか?キャッシュが不足しますか?

他のスマートなソリューションはありますか?

12
Ruggero Turra

数値の安定性が正確さを意味する場合、はい、正確さの問題が発生する可能性があります。最大値と最小値の比率、および結果を正確にするための要件によっては、これが問題になる場合と問題にならない場合があります。

高精度が必要な場合は、 Kahan summation を検討してください。これは、誤差補正に追加の浮動小数点を使用します。 ペアワイズ総和 もあります。

精度と時間のトレードオフの詳細な分析については、 この記事 を参照してください。

C++ 17の更新:

他の回答のいくつかはstd::accumulate。 C++ 17以降、アルゴリズムの並列化を可能にする 実行ポリシー があります。

例えば

#include <vector>
#include <execution>
#include <iostream>
#include <numeric>

int main()
{  
   std::vector<double> input{0.1, 0.9, 0.2, 0.8, 0.3, 0.7, 0.4, 0.6, 0.5};

   double reduceResult = std::reduce(std::execution::par, std::begin(input), std::end(input));

   std:: cout << "reduceResult " << reduceResult << '\n';
}

これにより、非決定論的な丸めエラーを犠牲にして、大規模なデータセットの集計が速くなります(ユーザーがスレッドのパーティション分割を判断できないと想定しています)。

1
Paul Floyd