Numerische Genauigkeit für die Differenz von Quadraten

8

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:

%Vor%

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?

    
cschwan 13.08.2013, 15:13
quelle

6 Antworten

4

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.

    
1'' 13.08.2013, 15:23
quelle
3

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%     
dev.brutus 13.08.2013 15:47
quelle
1

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.

    
Jitse Niesen 14.08.2013 14:16
quelle
1

Der richtige Weg, über die numerische Genauigkeit einiger Ausdrücke nachzudenken, ist:

  1. Messen Sie die Ergebnisdiskrepanz relativ zum korrekten Wert in ULPs (Einheit an letzter Stelle), die 1960 eingeführt wurde. von WH Kahan. Sie finden C, Python & amp; Mathematica-Implementierungen hier , und erfahren Sie mehr zum Thema hier .
  2. Unterscheiden Sie zwischen zwei oder mehr Ausdrücken basierend auf dem Worst Case, den sie erzeugen, und nicht den absoluten Durchschnittswert, wie in anderen Antworten oder durch eine andere willkürliche Metrik. Auf diese Weise werden numerische Approximationspolynome konstruiert ( Remez Algorithmus ), wie die Implementierungen der Standardbibliotheksmethoden sind analysiert (zB Intel atan2 ), etc ...

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%     
ahrvoje 24.11.2017 00:06
quelle
0

[Bearbeitet für major think-o] Es sieht so aus, als wäre Option 2 besser, denn für eine Zahl wie 0.000001 zum Beispiel gibt Option 1 den Sinus als 1 zurück, während Option eine Zahl zurückgibt, die kleiner als 1 ist .

    
Mark B 13.08.2013 15:27
quelle
0

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.

    
Eamonn Kenny 19.07.2016 11:22
quelle

Tags und Links