Extended (80 bit) double floating-point-in-x87, nicht SSE2 - wir verpassen Sie es nicht?
Las ich heute über Forscher entdecken, dass NVidia Phys-X-Bibliotheken verwenden, x87-FP vs. SSE2. Natürlich wird dies suboptimal für die parallele Datensätze, wo Geschwindigkeit Trumpf Präzision. Allerdings, der Autor des Artikels geht auf Zitat:
Intel begonnen, entmutigt die Verwendung von x87-mit der Einführung der P4 Ende 2000. AMD veralteten x87-seit dem K8 von 2003 als x86-64 definiert ist, mit SSE2-support; ÜBER die C7 unterstützt SSE2 seit 2005. In 64-bit-Versionen von Windows, x87 ist veraltet user-Modus, und gänzlich verboten im kernel-Modus. So ziemlich jeder in der Branche hat empfohlen SSE über x87-seit 2005 und es gibt keine Gründe für die Verwendung von x87, es sei denn, die software ist zum ausführen auf einem embedded-Pentium oder 486.
Ich wunderte mich über dieses. Ich weiß, dass x87 nutzt 80-bit-extended-doubles, die intern zur Berechnung der Werte, und SSE2 nicht. Ist das nicht eine Sache für jedermann? Es scheint für mich überraschend. Ich weiß, wenn ich Berechnungen für Punkte, Linien und Polygone in einer Ebene, können die Werte überraschend falsch, wenn dabei die Subtraktionen, und Bereiche können zusammenbrechen und Zeilen-alias einem anderen aufgrund mangelnder Präzision. Mit 80-bit-Werte im Vergleich zu 64-bit-Werte helfen könnte, würde ich mir überlegen.
Ist das falsch? Wenn nicht, was können wir verwenden, um führen Sie erweiterte Doppel-FP-Operationen, wenn x87 ausgelaufen?
- Nicht wirklich eine Antwort auf deine Frage, aber ich persönlich bin der Hoffnung, für die 128-bit-IEEE-754 binären format zu mainstream geworden.
- im ernst, genau das, was dauert da so lange? AVX kann ein standard vor, der steigt aus...
- Dieser ist eine gute Antwort auf das, was war der Grund zu entmutigen x87. Und ja, SSE-Berechnungen sind weniger präzise, es ist deutlich zu erkennen auf modernen JIT-Compiler (im Vergleich zu herkömmlichen x87-Basis-Compiler).
Du musst angemeldet sein, um einen Kommentar abzugeben.
Das größte problem mit x87-ist im Grunde, dass alle register Operationen werden durchgeführt in 80 bits, während die meisten der Zeit, die Menschen nur 64-bit-floats (also double-precision floats). Was passiert, ist, laden Sie eine 64-bit-float in die x87-stack, und es wird umgewandelt zu 80 bits. Sie haben einige Operationen in 80 bits, dann speichern Sie es zurück in den Speicher, die Umwandlung in 64 bit. Erhalten Sie ein anderes Ergebnis, als wenn Sie alles getan hatte, was den Betrieb mit nur 64 bits, und mit einem optimierenden compiler kann sehr unberechenbar sein, wie viele conversions könnte der Wert gehen durch, so ist es schwer, stellen Sie sicher, dass Sie immer die "richtige" Antwort, wenn dabei die regression-tests.
Das andere problem, das nur Angelegenheiten aus der Sicht von jemandem schreiben, der Versammlung (oder indirekt schreiben der Montage, in dem Fall von jemandem schreiben einen code-generator für ein compiler), ist, dass die x87-verwendet ein register, stack, in der Erwägung, dass SSE verwendet individuell zugänglichen Registern. Mit x87-Sie haben eine Reihe von zusätzlichen Anweisungen, um den stack zu manipulieren, und ich denke mir, Intel und AMD würden lieber Ihre Prozessoren schnell laufen mit SSE-code, als der Versuch zu machen, diese extra-stack-manipulation x87-Instruktionen schnell laufen.
BTW, wenn Sie Probleme mit der Ungenauigkeit, werden Sie wollen, um einen Blick auf den Artikel "Was jeder Programmierer wissen sollte, über floating-point Arithmetik", und dann vielleicht mit einer beliebiger Genauigkeit Mathematik-Bibliothek (z.B. GMP) statt.
strictfp
Schlüsselwort. Dies zwingt die Mathematik zu IEEE 754 und nicht, was die native Plattform bietet (x87 auf 32b intel zum Beispiel). en.wikipedia.org/wiki/Strictfpdouble
jeder Zeit, die Sie nicht passen in Registern, also, wennsomeDouble=f1()*f2()+f3()*f4()
ausgewertet wurde in Links-zu-rechts-Sequenz, es könnte die Rundef1()*f2()
zu einemdouble
aber nicht rund, f3()*f4 - () [, da keine weitere Funktionsaufrufe erforderlich wäre, zwischen der Zeit, es wurde berechnet und die ZeitsomeDouble
gespeichert wurde]. Diese Art von Verhalten ist eklig und böse. Aber wenn die Regeln für, wenn Dinge wurden auf-oder abgerundet wurden, unabhängig von dem, was getan oder nicht getan fit in Registern, ich würde nicht sehen, ein problem.ieee float
,fast float
, undshort real
, wo das Produkt von zwei IEEE-floats würde immer werden gerundet, umfloat
währendfast float
würde gerundet werden oder nicht so bequem. Einshort real
wäre ein 32-bit-floating-point-Wert, aber würde umgewandelt werden, um die maximale Genauigkeit Typ bei der Durchführung math es, wenn eine solche Umwandlung könnte zur Verbesserung der Genauigkeit des Ergebnisses [z.B. Umstellung erforderlich sein würde, wenn computingf1=f2+f3+f4;
, aber nichtf1=f2+f3;
].float
Präzision für Ihren gesamten Prozess!Zur korrekten Verwendung der extended-precision math, ist es notwendig, dass eine Sprache unterstützt einen Typ, der verwendet werden kann zum speichern des Ergebnisses der intermediate-Berechnungen, und kann ersetzt werden, für die Ausdrücke, die nachgeben, diese Ergebnisse. Also, gegeben:
sollte es einige geben, die verwendet werden könnten, zu erfassen und zu ersetzen, die gemeinsame Teilausdrücke
x2-x1
undy2-y1
, so dass der code wie folgt umgeschrieben werden:ohne änderung der Semantik des Programms. Leider ANSI-C nicht angeben, jede Art, die verwendet werden könnte, für
some_type
auf Plattformen, die extended-precision-Berechnungen, und es wurde weit mehr üblich, die Schuld von Intel, um die Existenz der extended-precision-Typen als Schuld ANSI verkrachte unterstützen.In der Tat, das extended-precision-Arten haben nur so viel Wert auf den Plattformen ohne floating-point-Einheiten, wie Sie tun, auf x87-Prozessoren, da auf solchen Prozessoren eine Berechnung wie x+y+z würde die folgenden Schritte aus:
Verwendung eines extended-precision-Typ wird erlauben, die Schritte 4, 5 und 6 eliminiert werden. Seit ein 53-bit-Mantisse zu groß ist, um in weniger als vier 16-bit-Register oder zwei 32-bit-Register, das durchführen einer addition mit einem 64-bit-Mantisse ist nicht langsamer als ein 53-bit-Mantisse, also die Verwendung von extended-precision math bietet eine schnellere Berechnung ohne Nachteil in einer Sprache, die unterstützt eine richtige Art zu halten Sie temporäre Ergebnisse. Es gibt keinen Grund, die Schuld von Intel für die Bereitstellung eine FPU, die erfüllen könnten, Gleitkommaoperationen in der Mode-das war auch die effizienteste Methode, die auf non-FPU-chips.
d1=f1*f2
...d1=(float)(f1*f2);
[nichtd1=(double)(f1*f2);
!]. Ich würde vermuten, dass in Fällen, in denen jemand schreibtd1=f1*f2;
gibt es eine sehr hohe Wahrscheinlichkeit, dass (1) würde der code entweder nicht beabsichtigt gewesen zu sagend1=(double)f1*f2;
, (2) ein Programmierer sieht der code denkt, es bedeutet, dass, oder (3) ein Programmierer sieht der code denkt, es war gemeint, dass. Dass der code so geschrieben werden, alsd1=(float)(f1*f2);
in Fällen, in denen dieses Verhalten ist beabsichtigt, zu beseitigen diese Gefahren.long double
eine erweiterte Präzision geben?Y_SCALE
, und selbst wenn der gleiche WertY_SCALE
war manchmal verwendet, infloat
unddouble
Berechnungen. Mit einemlong double
Art, die ist nicht austauschbar inprintf
macht die Sache umständlich, wie...long double d=0.1;
setd
zu 0.10000000000000000555 eher als 0.10000000000000000000813151629364.Die andere Antwort scheint nahe zu legen, dass mit 80-bit-Genauigkeit ist eine schlechte Idee, ist es aber nicht. Es führt eine manchmal entscheidende Rolle in halten Ungenauigkeit in der Bucht, siehe z.B. die Schriften von W. Kahan.
Verwenden Sie immer die 80-bit-Mittelstufe-Arithmetik, wenn Sie können Weg mit es Geschwindigkeit her. Wenn das bedeutet, dass Sie verwenden müssen, x87-Mathematik, sowie, dazu. Die Unterstützung für Sie ist allgegenwärtig und solange die Leute immer das richtige zu tun, bleibt er allgegenwärtig.
1e16 + 2.9999
auf IEEE-754 binary64 Werte gibt ein korrekt gerundetes Ergebnis von10000000000000002.0
auf einer Maschine mit SSE2-Unterstützung, aber eine falsch-abgerundete Ergebnis der10000000000000004.0
bei der Verwendung mit x87-FPU Genauigkeit nicht verändert gegenüber dem Standardwert von 64-bit-Präzision Dank Doppel-Rundung.Double Kommazahl ist 11 bits weniger als f80 (etwa 2,5 Knabbereien/Ziffern), viele Apps (meist Spiele), es würde nicht Schaden. Aber Sie müssen alle die Genauigkeit verfügbar für sagen -, Raum-Programm oder medizinische app.
Es ist ein bisschen irreführend, wenn einige sagen, dass der f80 (und entmutigen Sie es), das auf stack. FPU-Register und Operationen ähnlich stack-Betrieb, vielleicht ist das, was die Menschen verwirrt. Es tatsächlich Speicher basiert (load/store), nicht stapelbar, pro-se, im Vergleich zu, zum Beispiel, Aufrufkonvention wie cdecl stdcall was tun eigentlich die übergabe von Parametern via stack. und nichts falsch mit, dass.
Der große Vorteil von SSE ist eigentlich serialisieren Betrieb, 2, 4, 8 Werte auf einmal, mit vielen varian-Operationen. Ja, Sie können direkt transfer zu registrieren, aber Sie werden übertragen von Werten in den Speicher eh am Ende.
Der große Nachteil der f80 ist, seine seltsame 10 byte lang, es stören die Ausrichtung. man müsste so ausrichten, dass Sie 16 für einen schnelleren Zugriff. aber nicht wirklich praktikabel für array.
Haben Sie immer noch zu verwenden fpu für trigonometrische und andere trancedental mathematische Operationen. Für asm, es gibt viele f80 tricks, die wirklich Spaß und ist nützlich.
Für Spiele und regelmäßige einfache app, die (fast alle), können Sie nur verdoppeln, ohne dabei jemand gestorben ist. Aber für ein paar ernste, mathematische oder wissenschaftliche Anwendung, die Sie einfach nicht Graben f80.
serialize operation
. Du meinst "parallel-Betrieb". Oder SIMD-Betrieb.You still have to use fpu for trigonometric and other trancedental math operations
. Wenn du meinst x87 FSIN, FYL2X (log2), etc. dann Nein, das ist falsch. Mathematik-Bibliotheken implementieren diese Funktionen in software mit SSE-math.fsin
in der software ist nicht viel langsamer. Die interne Implementierung ist micro-codiert mit 71-100 uops (Intel Haswell), mit einer Gesamt-Wartezeit von 47-106 Zyklen, und (in diesem Fall) macht nichts, was nicht getan werden kann mit einfachen x86-Anweisungen, die jede Dekodierung nur eine einzige uop. Und re: Pi Präzision, der Artikel, den Sie verlinkt nicht sagen nichts über die katastrophale Absage oder floating-point-Probleme. Hast du auch gelesen, Bruce Dawson ' s Artikel, den ich verlinkte früher? Haben Sie schon von der katastrophalen Absage?