web-dev-qa-db-fra.com

Somme stable efficace de nombres ordonnés

J'ai une assez longue liste de nombres positifs à virgule flottante (std::vector<float>, taille ~ 1000). Les nombres sont triés par ordre décroissant. Si je les additionne suite à la commande:

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

Je suppose que je peux avoir un problème de stabilité numérique, car près de la fin du vecteur sum sera beaucoup plus grand que v. La solution la plus simple serait de traverser le vecteur dans l'ordre inverse. Ma question est la suivante: est-ce efficace ainsi que le cas avancé? J'aurai plus de cache manquant?

Existe-t-il une autre solution intelligente?

12
Ruggero Turra

Si par stabilité numérique vous entendez la précision, alors oui, vous pouvez vous retrouver avec des problèmes de précision. Selon le rapport des valeurs les plus grandes aux plus petites, et vos exigences de précision dans le résultat, cela peut ou non être un problème.

Si vous voulez avoir une grande précision, alors considérez sommation de Kahan - cela utilise un flotteur supplémentaire pour la compensation des erreurs. Il y a aussi sommation par paire .

Pour une analyse détaillée du compromis entre précision et temps, voir cet article .

MISE À JOUR pour C++ 17:

Quelques autres réponses mentionnent std::accumulate. Depuis C++ 17, il existe politiques d'exécution qui permettent de paralléliser les algorithmes.

Par exemple

#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';
}

Cela devrait accélérer la sommation de grands ensembles de données au prix d'erreurs d'arrondi non déterministes (je suppose que l'utilisateur ne sera pas en mesure de déterminer le partitionnement des threads).

1
Paul Floyd