Habré hatte bereits mehrere Artikel (
eins ,
zwei ,
zweieinhalb ) über das neue Posit-Gleitkommaformat, dessen Autoren es in jeder Hinsicht dem Standard-Float nach IEEE 754 überlegen präsentieren. Das neue Format fand auch Kritiker (
eins ,
zwei ), die behaupten, dass die Fehler von Posit die Vorzüge überwiegen. Aber was ist, wenn wir wirklich ein neues revolutionäres Format haben und die Kritik einfach durch den Neid und die Inkompetenz derjenigen verursacht wird, die kritisieren? Der beste Weg, dies herauszufinden, besteht darin, sich selbst zu berechnen.
Einführung
Die Vorteile des neuen Formats werden anhand einfacher Beispiele mit Addition / Multiplikation von Zahlen ähnlicher Ordnung demonstriert, die zu einer um ein oder zwei Stellen höheren Genauigkeit führen. Bei realen Berechnungen spielt jedoch das Plus / Minus-Bit des Fehlers einer einzelnen Operation keine Rolle, da wir ohnehin mit begrenzter Genauigkeit berechnen. Die
Anhäufung von Fehlern infolge der Abfolge von Operationen ist wichtig, wenn nach einiger Zeit die Fehler in den unteren Ziffern zu Fehlern in den älteren führen. Das werden wir versuchen zu erleben.
Vorbereitung
Zum Testen habe ich die Posit-Implementierung mit einem Pathos-Titel
von hier genommen . Um es in Visual Studio zu kompilieren, mussten wir die Zeile #define CLZ (n) __lzcnt (n) in die Datei util.h einfügen und 0.f / 0.f in der Datei posit.cpp durch std :: numeric_limits <float> :: quiet_NaN ersetzen (). Übrigens wurden in dieser Bibliothek auch keine Implementierungen für elementare mathematische Funktionen (mit Ausnahme der Wurzel) gefunden - dies ist ein weiterer Grund für den Verdacht, dass etwas nicht stimmte.
Test 1. Multiplikation komplexer Zahlen
Die mit komplexer Arithmetik berechnete Fourier-Transformation wird nach Möglichkeit verwendet. Zuerst wollte ich Posit auf der Fourier-Transformation testen; Da die Genauigkeit jedoch stark von der Implementierung abhängt, müssen Sie für korrekte Tests alle grundlegenden Algorithmen berücksichtigen, was etwas zeitaufwändig ist. Daher können Sie mit einer einfacheren Operation beginnen - der Multiplikation komplexer Zahlen.
Wenn wir einen bestimmten Vektor nehmen und ihn 360 Mal um 1 ° drehen, sollten wir am Ende den gleichen Originalvektor erhalten. Tatsächlich wird das Ergebnis aufgrund der Anhäufung von Fehlern geringfügig abweichen - und je größer die Anzahl der Windungen ist, desto größer ist der Fehler. Verwenden Sie also diesen einfachen Code
complex<T> rot(cos(a), sin(a)); complex<T> vec(length, 0); for (long i = 0; i < count; i++) { vec *= rot; } cout << "error: " << stdev(vec.real() - length, vec.imag()) << endl;
Wir drehen einen Vektor mit verschiedenen Datentypen und betrachten den Fehler als mittlere quadratische Abweichung des resultierenden Vektors vom Original (die auch als Länge des Differenzvektors interpretiert werden kann).
Nehmen Sie zunächst den Einheitsvektor als den unterstützendsten von Posit:
Hier gibt es noch keinen offensichtlichen Anführer - der Vorteil ist doppelt so groß wie der des einen oder anderen. Erhöhen Sie die Länge des gedrehten Vektors auf 1000:
Die Fehlerwerte sind nahezu gleich. Gehen Sie voran - 1.000.000:
Hier bleibt Posit bereits souverän zurück und der Doppelfehler beginnt sich in den Schwimmer zu schleichen. Nehmen wir eine noch längere Länge - 10
10 , um die Vorteile von Gleitkommaformaten voll auszuschöpfen:
Hier das Interessanteste am Anfang, bei 4 Iterationen - wenn der Float einen Fehler ergibt, der dem Double entspricht, und Posit bereits ein völlig falsches Ergebnis hat.
Test 2. Berechnung eines rationalen Polynoms
Da die ursprüngliche Bibliothek keine mathematischen Funktionen enthielt, werden wir versuchen, etwas selbst zu tun. Viele Funktionen werden durch die Erweiterung in einer Taylor-Reihe schlecht approximiert, und sie sind bequemer durch Approximation durch ein rationales Polynom zu berechnen. Diese Annäherung kann auf verschiedene Arten erhalten werden, auch rein analytisch - durch die
Padé-Näherung . Wir werden es außerdem zum Testen mit ausreichend großen Koeffizienten verwenden, so dass sie vor der Berechnung ebenfalls gerundet werden.
Verwenden von Wolfram Mathematica und des PadeApproximant-Befehls [Sin [x], {x, 0, {11, 11}}]
Wir erhalten ein solches rationales Polynom zur Approximation des Sinus, das eine doppelte Genauigkeit im Bereich von etwa -2 bis 2 liefert:
\ frac {- \ frac {481959816488503 x ^ {11}} {363275871831577908403200} + \ frac {23704595077729 x ^ 9} {42339845201815607040} - \ frac {2933434889971 x ^ 7} {33603051747472704} } {617703157122660} - \ frac {109061004303 x ^ 3} {722459832892} + x} {\ frac {37291724011 x ^ {10}} {11008359752472057830400} + \ frac {3924840709 x ^ 8} {20161831048483640 x ^ 6} {168015258737363520} + \ frac {1679739379 x ^ 4} {13726736824948} + \ frac {34046903537 x ^ 2} {2167379498676} +1}
Das Horner-Schema wird normalerweise direkt für Berechnungen verwendet, um Berechnungen zu sparen. In unserem Fall (mit HornerForm) sieht es so aus
template< typename T > T padesin(T x) { T xx = x*x; return (x*(T(363275871831577908403200.) + xx*(-T(54839355237791393068800.) + xx*(T(2120649063015013090560.) + xx*(-T(31712777908498486800.) + xx*(T(203385425766914820.) - T(481959816488503.) * xx)))))) / (T(363275871831577908403200.) + xx*(T(5706623400804924998400.) + xx*(T(44454031219351353600.) + xx* (T(219578286347980560.) + xx*(T(707177798947620.) + T(1230626892363.) * xx))))); }
Mal sehen:
Wie Sie sehen können, sieht die Situation mit Posit hier bedauerlich aus - kaum zwei signifikante Nummern werden gewählt.
Fazit
Leider ist kein Wunder geschehen und die Revolution ist abgesagt. Der Vorteil von Posit, der bei Einzelberechnungen demonstriert wurde, ist nichts anderes als ein Trick, dessen Preis eine katastrophale Abnahme der Genauigkeit bei "schweren" realen Berechnungen darstellt. Der einzige Grund, warum es sinnvoll ist, Posit anstelle von IEEE 754 Float oder Fixpunkt zu verwenden, ist religiös. Die Verwendung des magischen Formats, dessen Genauigkeit durch den heiligen Glauben seiner Schöpfer gewährleistet wird, kann viele Wunder in Ihre Programme bringen!
PS-
Quellcode zur Überprüfung und Kritik .
PPS
Fortsetzung .