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 )
Eine schöne portable und Open-Source-Bibliothek für Gleitkomma-Arithmetik mit beliebiger Genauigkeit (und vieles mehr) ist Victor Shoups NTL , die in C ++ - Quellform verfügbar ist.
Auf einer niedrigeren Ebene befindet sich die GNU Multiple Precision (GMP) Bignum Library , ebenfalls ein Open-Source-Paket.
NTL kann mit GMP verwendet werden, wenn eine schnellere Leistung erforderlich ist. NTL stellt jedoch eigene Basisroutinen zur Verfügung, die auf jeden Fall verwendet werden können, wenn Sie sich nicht für Geschwindigkeit interessieren. GMP behauptet, die "schnellste Bignumbibliothek" zu sein. GMP ist größtenteils in C geschrieben, verfügt jedoch über eine C ++ - Schnittstelle.
Hinzugefügt: Während Intervallarithmetik auf automatisierte Weise obere und untere Grenzen für die exakte Antwort festlegen kann, misst dies den Fehler bei einer "Standard" -Präzisionsberechnung nicht genau, da die Intervallgröße normalerweise mit jeder Operation wächst (entweder relativ oder relativ) absoluter Fehlersinn).
Die typische Methode zum Ermitteln der Fehlergröße, entweder für Rundungsfehler oder für Diskretisierungsfehler usw., besteht darin, einen zusätzlichen Präzisionswert zu berechnen und diesen mit dem "Standard" -Präzisionswert zu vergleichen. Es ist nur eine bescheidene zusätzliche Genauigkeit erforderlich, um die Fehlergröße selbst mit angemessener Genauigkeit zu bestimmen, da die Rundungsfehler allein in der "Standard" -genauigkeit wesentlich größer sind als in der Berechnung mit zusätzlicher Genauigkeit.
Der Punkt kann durch Vergleichen von Berechnungen mit einfacher und doppelter Genauigkeit veranschaulicht werden. Beachten Sie, dass in C ++ Zwischenausdrücke immer mit (mindestens) doppelter Genauigkeit berechnet werden. Wenn Sie also veranschaulichen möchten, wie eine Berechnung mit "reiner" einfacher Genauigkeit aussehen würde, müssen Sie die Zwischenwerte mit einfacher Genauigkeit speichern.
C-Code-Snippet
Die Ausgabe von oben (Cygwin / MinGW32 GCC-Toolkette):
Der Fehler ist also ungefähr das, was man erwartet, wenn man 1/3 auf einfache Genauigkeit rundet. Es würde einem (ich vermute) nichts ausmachen , mehr als ein paar Nachkommastellen im Fehler zu korrigieren, da die Messung des Fehlers nach der Größe und nicht nach der Genauigkeit erfolgt.
quelle
GMP (dh die GNU Multiple Precision Library) ist die beste beliebige Präzisionsbibliothek, die ich kenne.
Ich kenne keine programmatische Methode, um den Fehler in den Ergebnissen einer beliebigen Gleitkommafunktion zu messen. Sie könnten versuchen, eine Intervallverlängerung einer Funktion mit Intervallarithmetik zu berechnen . In C ++ müssten Sie eine Bibliothek verwenden, um die Intervallerweiterungen zu berechnen. Eine solche Bibliothek ist die Boost Interval Arithmetic Library. Um den Fehler zu messen, würden Sie als Argumente für Ihre Funktionsintervalle angeben, die eine Breite von 2-facher Rundung (ungefähr) haben, zentriert auf die interessierenden Werte, und dann wäre Ihre Ausgabe eine Sammlung von Intervallen, die Breite von das würde Ihnen eine konservative Schätzung des Fehlers geben. Eine Schwierigkeit bei diesem Ansatz besteht darin, dass die auf diese Weise verwendete Intervallarithmetik Fehler erheblich überschätzen kann, aber dieser Ansatz ist der "programmatischste", den ich mir vorstellen kann.
quelle
Eine rigorose und automatische Fehlerabschätzung kann durch Intervallanalyse erreicht werden . Sie arbeiten mit Intervallen anstelle von Zahlen. Zum Beispiel Zugabe:
Rundung kann auch rigoros gehandhabt werden, siehe Abgerundete Intervallarithmetik .
Solange Ihre Eingabe aus engen Intervallen besteht, sind die Schätzungen in Ordnung und können nicht billig berechnet werden. Leider wird der Fehler oft überschätzt, siehe das Abhängigkeitsproblem .
Ich kenne keine Arithmetikbibliothek für beliebige Präzisionsintervalle.
Es hängt von Ihrem Problem ab, ob die Intervallarithmetik Ihren Anforderungen entspricht oder nicht.
quelle
Die GNU MPFR-Bibliothek ist eine Float-Bibliothek mit beliebiger Genauigkeit, die eine hohe Genauigkeit (insbesondere korrekte Rundung für alle Operationen, was nicht so einfach ist, wie es sich anhört) als einen ihrer Hauptschwerpunkte aufweist. Es verwendet GNU MP unter der Haube. Es hat eine Erweiterung namens MPFI , die Intervall-Arithmetik ausführt , was - wie Geoffs Antwort nahelegt - für Überprüfungszwecke nützlich sein könnte: Erhöhen Sie die Arbeitsgenauigkeit so lange, bis das resultierende Intervall innerhalb kleiner Grenzen liegt.
Dies wird jedoch nicht immer funktionieren. Insbesondere ist es nicht unbedingt effektiv, wenn Sie so etwas wie numerische Integration ausführen, bei der jeder Schritt einen "Fehler" enthält, der von Rundungsproblemen unabhängig ist. Versuchen Sie in diesem Fall ein spezielles Paket wie COSY infinity, das dies sehr gut mit spezifischen Algorithmen zur Begrenzung des Integrationsfehlers erledigt (und sogenannte Taylor-Modelle anstelle von Intervallen verwendet).
quelle
Mir wurde gesagt, dass MPIR eine gute Bibliothek ist, wenn Sie mit Visual Studio arbeiten:
http://mpir.org/
quelle