Si vous recherchez une bonne limite à votre erreur d'arrondi, vous n'avez pas nécessairement besoin d'une bibliothèque de précision aribtraire. Vous pouvez plutôt utiliser l'analyse des erreurs en cours d'exécution.
Je n'ai pas pu trouver une bonne référence en ligne, mais tout est décrit dans la section 3.3 du livre de Nick Higham "Accuracy and Stability of Numerical Algorithms". L'idée est assez simple:
- Re-factorisez votre code afin d'avoir une seule affectation d'une seule opération arithmétique sur chaque ligne.
- Pour chaque variable, par exemple
x
, créez une variable x_err
qui est initialisée à zéro lorsque x
une constante lui est affectée.
- Pour chaque opération, par exemple
z = x * y
, mettez à jour la variable en z_err
utilisant le modèle standard d'arithmétique à virgule flottante z
et les erreurs résultantes et en cours d'exécution x_err
et y_err
.
- La valeur de retour de votre fonction doit alors également avoir une
_err
valeur respective attachée à elle. Il s'agit d'une limite dépendante des données de votre erreur d'arrondi totale.
La partie délicate est l'étape 3. Pour les opérations arithmétiques les plus simples, vous pouvez utiliser les règles suivantes:
z = x + y
-> z_err = u*abs(z) + x_err + y_err
z = x - y
-> z_err = u*abs(z) + x_err + y_err
z = x * y
-> z_err = u*abs(z) + x_err*abs(y) + y_err*abs(x)
z = x / y
-> z_err = u*abs(z) + (x_err*abs(y) + y_err*abs(x))/y^2
z = sqrt(x)
-> z_err = u*abs(z) + x_err/(2*abs(z))
où u = eps/2
est l'arrondi de l'unité. Oui, les règles +
et -
sont les mêmes. Les règles pour toute autre opération op(x)
peuvent être facilement extraites en utilisant l'expansion de la série Taylor du résultat appliqué op(x + x_err)
. Ou vous pouvez essayer de googler. Ou en utilisant le livre de Nick Higham.
À titre d'exemple, considérons le code Matlab / Octave suivant qui évalue un polynôme dans les coefficients a
à un point en x
utilisant le schéma de Horner:
function s = horner ( a , x )
s = a(end);
for k=length(a)-1:-1:1
s = a(k) + x*s;
end
Pour la première étape, nous avons divisé les deux opérations en s = a(k) + x*s
:
function s = horner ( a , x )
s = a(end);
for k=length(a)-1:-1:1
z = x*s;
s = a(k) + z;
end
Nous introduisons ensuite les _err
variables. Notez que les entrées a
et x
sont supposées être exactes, mais nous pourrions tout aussi bien exiger que l'utilisateur passe des valeurs correspondantes pour a_err
et x_err
:
function [ s , s_err ] = horner ( a , x )
s = a(end);
s_err = 0;
for k=length(a)-1:-1:1
z = x*s;
z_err = ...;
s = a(k) + z;
s_err = ...;
end
Enfin, nous appliquons les règles décrites ci-dessus pour obtenir les termes d'erreur:
function [ s , s_err ] = horner ( a , x )
u = eps/2;
s = a(end);
s_err = 0;
for k=length(a)-1:-1:1
z = x*s;
z_err = u*abs(z) + s_err*abs(x);
s = a(k) + z;
s_err = u*abs(s) + z_err;
end
Notez que puisque nous n'avons pas a_err
ou x_err
, par exemple, ils sont supposés être nuls, les termes respectifs sont simplement ignorés dans les expressions d'erreur.
Et voilà! Nous avons maintenant un schéma de Horner qui renvoie une estimation d'erreur dépendante des données (remarque: il s'agit d'une limite supérieure de l'erreur) à côté du résultat.
En guise de remarque, puisque vous utilisez C ++, vous pouvez envisager de créer votre propre classe de valeurs à virgule flottante qui porte le _err
terme et de surcharger toutes les opérations arithmétiques pour mettre à jour ces valeurs comme décrit ci-dessus. Pour les grands codes, il peut s'agir de l'itinéraire le plus facile, bien que moins efficace sur le plan des calculs. Cela dit, vous pourrez peut-être trouver un tel cours en ligne. Une recherche rapide sur Google m'a donné ce lien .
PS Notez que tout cela ne fonctionne que sur les machines respectant strictement IEEE-754, c'est-à-dire que toutes les opérations arithmétiques sont précises à . Cette analyse donne également une limite plus stricte et plus réaliste que l'utilisation de l'arithmétique d'intervalle car, par définition, vous ne pouvez pas représenter un nombre en virgule flottante, c'est-à-dire que votre intervalle serait juste arrondi au nombre lui-même.x ( 1 ± u )± ux ( 1 ± u )