Imaginez que vous avez un grand tableau de nombres flottants, de toutes sortes de tailles. Quelle est la plus correcte pour calculer la somme, avec le moins d'erreur? Par exemple, lorsque le tableau ressemble à ceci:
[1.0, 1e-10, 1e-10, ... 1e-10.0]
et vous ajoutez de gauche à droite avec une simple boucle, comme
sum = 0
numbers.each do |val|
sum += val
end
chaque fois que vous ajoutez les petits nombres peuvent tomber au-dessous du seuil de précision afin que l'erreur devient de plus en plus gros. Autant que je sache, la meilleure façon est de trier le tableau et commencer à ajouter des numéros à partir de la plus basse à la plus haute, mais je me demande si il est encore mieux (plus rapide, plus précis)?
EDIT: Merci pour la réponse, j'ai maintenant un code de travail qui résume parfaitement le double des valeurs en Java. C'est un droit de port à partir de Python post de la bonne réponse. La solution passe tous mes tests unitaires. A plus long, mais la version optimisée de ce qui est disponible ici 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;
}
}