Wenn Sie nach einer guten Grenze für Ihren Rundungsfehler suchen, benötigen Sie nicht unbedingt eine Bibliothek mit beliebiger Genauigkeit. Sie können stattdessen die laufende Fehleranalyse verwenden.
Ich konnte keine gute Online-Referenz finden, aber alles ist in Abschnitt 3.3 von Nick Highams Buch "Genauigkeit und Stabilität numerischer Algorithmen" beschrieben. Die Idee ist ganz einfach:
- Berechnen Sie Ihren Code neu, sodass Sie in jeder Zeile eine einzelne Zuordnung einer einzelnen arithmetischen Operation haben.
x
Erstellen Sie z. B. für jede Variable eine Variable, x_err
die auf Null initialisiert wird, wenn x
eine Konstante zugewiesen wird.
z = x * y
Aktualisieren Sie für jede Operation z. B. die Variable z_err
mit dem Standardmodell der Gleitkomma-Arithmetik und den daraus resultierenden z
und den ausgeführten Fehlern x_err
und y_err
.
- Dem Rückgabewert Ihrer Funktion sollte dann auch ein entsprechender
_err
Wert zugeordnet sein. Dies ist eine datenabhängige Grenze Ihres gesamten Rundungsfehlers.
Der knifflige Teil ist Schritt 3. Für die einfachsten Rechenoperationen können Sie die folgenden Regeln verwenden:
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))
wo u = eps/2
ist die gerundete Einheit. Ja, die Regeln für +
und -
sind gleich. op(x)
Mit der Taylor-Reihen-Erweiterung des Ergebnisses, auf das angewendet wird, können Regeln für jede andere Operation einfach extrahiert werden op(x + x_err)
. Oder Sie können versuchen, zu googeln. Oder mit Nick Highams Buch.
Betrachten Sie als Beispiel den folgenden Matlab / Octave-Code, der Polynome in den Koeffizienten a
an einem Punkt unter x
Verwendung des Horner-Schemas auswertet :
function s = horner ( a , x )
s = a(end);
for k=length(a)-1:-1:1
s = a(k) + x*s;
end
Für den ersten Schritt teilen wir die beiden Operationen in 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
Wir führen dann die _err
Variablen ein. Beachten Sie, dass die Eingaben a
und x
als genau angenommen werden, aber wir könnten genauso gut auch den Benutzer auffordern, entsprechende Werte für a_err
und zu übergeben 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
Schließlich wenden wir die oben beschriebenen Regeln an, um die Fehlerausdrücke zu erhalten:
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
Beachten Sie, dass die entsprechenden Ausdrücke in den Fehlerausdrücken einfach ignoriert werden , da wir keine haben a_err
oder x_err
z. B. angenommen werden, dass sie Null sind.
Et voilà! Wir haben jetzt ein Horner-Schema, das eine datenabhängige Fehlerschätzung (Anmerkung: Dies ist eine Obergrenze für den Fehler) neben dem Ergebnis zurückgibt .
Als Randnotiz: Da Sie C ++ verwenden, können Sie eine eigene Klasse für Gleitkommawerte erstellen, die den _err
Term enthält, und alle arithmetischen Operationen überladen, um diese Werte wie oben beschrieben zu aktualisieren. Bei großen Codes kann dies die einfachere, wenn auch rechnerisch weniger effiziente Route sein. Allerdings können Sie eine solche Klasse möglicherweise online finden. Eine schnelle Google-Suche gab mir diesen Link .
± ux ( 1 ± u )