In meinem Code berechne ich oft Dinge wie das folgende Stück (hier C-Code zur Vereinfachung):
%Vor% Bei diesem Beispiel ignorieren Sie, dass das Argument der Quadratwurzel aufgrund von Ungenauigkeiten negativ sein kann. Ich habe das mit zusätzlichen fdimf
Call behoben. Ich frage mich jedoch, ob das Folgende genauer ist:
cos_theta
liegt zwischen -1
und +1
, also wird es für jede Wahl Situationen geben, in denen ich ähnliche Zahlen subtrahiere und dadurch die Präzision verliere, richtig? Was ist das genaueste und warum?
Der genaueste Weg mit floats ist wahrscheinlich, sin und cos mit einer einzigen x87-Anweisung zu berechnen, fsincos .
Wenn Sie die Berechnung jedoch manuell durchführen müssen, ist es am besten, Argumente mit ähnlichen Größen zu gruppieren. Dies bedeutet, dass die zweite Option präziser ist, insbesondere wenn cos_theta
nahe bei 0 liegt, wo es auf Präzision ankommt.
Wie der Artikel Was jeder Informatiker über Fließkomma-Arithmetik wissen sollte :
>Der Ausdruck x 2 - y 2 ist eine andere Formel, die katastrophal ist Stornierung. Es ist genauer , um es als (x - y) (x + y) zu bewerten.
Bearbeiten: es ist komplizierter als das. Obwohl das Obige allgemein wahr ist, ist (x - y) (x + y) etwas weniger genau , wenn x und y sehr unterschiedliche Größen haben, wie die Fußnote zu der Aussage erklärt:
In diesem Fall hat (x - y) (x + y) drei Rundungsfehler, aber x 2 - y 2 hat nur zwei seit dem Rundungsfehler festgeschrieben wenn die Berechnung der kleineren von x 2 und y 2 die endgültige Subtraktion nicht beeinflusst.
Mit anderen Worten, nehmen x - y, x + y und das Produkt (x - y) (x + y) jeweils Rundungsfehler (3 Schritte des Rundungsfehlers) auf. x 2 , y 2 , und die Subtraktion x 2 - y 2 führen ebenfalls jeweils Rundungsfehler ein, aber die Der Rundungsfehler, der durch Quadrieren einer relativ kleinen Zahl (der kleineren von x und y) erhalten wird, ist so vernachlässigbar, dass es effektiv nur zwei Schritte des Rundungsfehlers gibt, wodurch die Differenz der Quadrate präziser wird.
Also wird Option 1 genauer sein. Dies wird durch den Java-Test von dev.brutus bestätigt.
Ich habe einen kleinen Test geschrieben. Es berechnet den erwarteten Wert mit doppelter Genauigkeit. Dann berechnet es einen Fehler mit Ihren Optionen. Die erste Option ist besser:
%Vor%Der Java-Code:
%Vor%Nebenbei bemerkt, Sie werden immer ein Problem haben, wenn Theta klein ist, weil der Kosinus flach um Theta = 0 ist. Wenn Theta zwischen -0,0001 und 0,0001 ist, dann ist cos (Theta) in float genau eins, also Ihre sin_theta wird genau Null sein.
Um Ihre Frage zu beantworten, wenn cos_theta nahe bei Eins ist (entspricht einem kleinen Theta), ist Ihre zweite Berechnung deutlich genauer. Dies wird durch das folgende Programm gezeigt, das die absoluten und relativen Fehler für beide Berechnungen für verschiedene Werte von cos_theta auflistet. Die Fehler werden durch Vergleichen mit einem Wert berechnet, der mit 200 Bits Genauigkeit unter Verwendung der GNU MP-Bibliothek berechnet und dann in einen Gleitkommawert umgewandelt wird.
%Vor%Ausgabe:
%Vor%Wenn cos_theta nicht nahe bei eins ist, dann liegt die Genauigkeit beider Methoden sehr nahe beieinander und bei Abrundungsfehlern.
Der richtige Weg, über die numerische Genauigkeit einiger Ausdrücke nachzudenken, ist:
Vor diesem Hintergrund erzeugen version_1: sqrt (1 - x * x) und version_2: sqrt ((1 - x) * (1 + x)) signifikant unterschiedliche Ergebnisse. Wie im folgenden Diagramm dargestellt, zeigt version_1 eine katastrophale Leistung für x nahe bei 1 mit dem Fehler & gt; 1_000_000 ulps, während sich andererseits der Fehler von version_2 gut verhält.
Deshalb empfehle ich immer version_2, d. h. die quadratische Differenzformel zu verwenden.
Python 3.6-Code, der die square_diff_error.csv-Datei erzeugt:
%Vor%Mathematica-Code, der das endgültige Diagramm erzeugt:
%Vor%Kein Unterschied in meiner Option, da (1-x) die Genauigkeit erhält, die das getragene Bit nicht beeinflusst. Dann gilt für (1 + x) das Gleiche. Dann ist die Multiplikation die einzige Sache, die die Genauigkeit des Übertragsbits beeinflusst. In beiden Fällen gibt es also eine einzige Multiplikation, so dass beide wahrscheinlich den gleichen Übertragsbitfehler liefern.
Tags und Links c c++ numerical-analysis