Effizientes Rechnen von (a - K) / (a + K) mit verbesserter Genauigkeit

n verschiedenen Kontexten, zum Beispiel für die Argumentreduktion für mathematische Funktionen, muss man @ berechn(a - K) / (a + K), woa ist ein positives Variablenargument undK ist eine Konstante. In vielen Fällen,K ist eine Zweierpotenz. Dies ist der für meine Arbeit relevante Anwendungsfall. Ich suche nach effizienten Methoden, um diesen Quotienten genauer zu berechnen, als dies mit der einfachen Aufteilung möglich ist. Hardware-Unterstützung für Fused Multiply-Add (FMA) ist anzunehmen, da dieser Vorgang derzeit von allen wichtigen CPU- und GPU-Architekturen bereitgestellt wird und in C / C ++ über die Funktionen @ verfügbar isfma() undfmaf().

Zur Erleichterung der Erkundung experimentiere ich mitfloat Arithmetik. Da ich vorhabe den Ansatz auf @ zu portierdouble auch arithmetisch dürfen keine Operationen verwendet werden, die eine höhere als die native Genauigkeit von Argument und Ergebnis verwenden. Meine bisher beste Lösung ist:

 /* Compute q = (a - K) / (a + K) with improved accuracy. Variant 1 */
 m = a - K;
 p = a + K;
 r = 1.0f / p;
 q = m * r;
 t = fmaf (q, -2.0f*K, m);
 e = fmaf (q, -m, t);
 q = fmaf (r, e, q);

Für Argumentea in der Pause[K/2, 4.23*K], der obige Code berechnet den Quotienten für alle Eingaben fast richtig gerundet (der maximale Fehler liegt sehr nahe bei 0,5 ulps), vorausgesetzt,K ist eine Potenz von 2 und es gibt keinen Über- oder Unterlauf bei Zwischenergebnissen. ZumK keine Potenz von zwei, dieser Code ist immer noch genauer als der auf Division basierende naive Algorithmus. In Bezug auf die Leistung kann dieser Code @ seischnelle als der naive Ansatz auf Plattformen, bei denen der Gleitkomma-Kehrwert schneller berechnet werden kann als die Gleitkommadivision.

Ich mache die folgende Beobachtung, wennK = 2n: Wenn die Obergrenze des Arbeitsintervalls auf @ stei8*K, 16*K, ... maximaler Fehler steigt allmählich an und nähert sich langsam dem maximalen Fehler der naiven Berechnung von unten an. Leider scheint dies für die untere Grenze des Intervalls nicht der Fall zu sein. Wenn die Untergrenze auf @ fäl0.25*K, der maximale Fehler der oben beschriebenen verbesserten Methode entspricht dem maximalen Fehler der naiven Methode.

Gibt es eine Methode zur Berechnung von q = (a - K) / (a + K), mit der ein kleinerer maximaler Fehler (gemessen in @) erreicht werden kan ulp im Vergleich zum mathematischen Ergebnis) im Vergleich zur naiven Methode und zur obigen Codesequenz über einen größeren Zeitraum, insbesondere für Intervalle, deren Untergrenze kleiner als @ i0.5*K? Effizienz ist wichtig, aber ein paar Operationen mehr als im obigen Code verwendet werden, können wahrscheinlich toleriert werden.

n einer Antwort unten wurde darauf hingewiesen, dass ich die Genauigkeit verbessern könnte, indem ich den Quotienten als eine unbewertete Summe von zwei Operanden zurückgebe, das heißt als Kopf-Schwanz-Paaq:qlo, d.h. ähnlich dem bekannten Doppel-float und double-double Formate. In meinem obigen Code würde dies bedeuten, die letzte Zeile in @ zu änderqlo = r * e.

Dieser Ansatz ist sicherlich nützlich, und ich hatte bereits überlegt, ihn für einen Logarithmus mit erweiterter Genauigkeit in @ zu verwendepow(). Grundsätzlich hilft dies jedoch nicht bei der gewünschten Erweiterung des Intervalls, in dem die erweiterte Berechnung genauere Quotienten liefert. In einem bestimmten Fall, den ich betrachte, möchte ich @ verwendK=2 (für einfache Genauigkeit) oderK=4 (für doppelte Genauigkeit), um das primäre Approximationsintervall schmal zu halten, und das Intervall füra ist ungefähr [0,28]. Das praktische Problem, mit dem ich konfrontiert bin, ist, dass für Argumente <0,25 * K die Genauigkeit der verbesserten Division nicht wesentlich besser ist als mit der naiven Method

Antworten auf die Frage(12)

Ihre Antwort auf die Frage