Unterschied in der floating-point-Arithmetik zwischen x86 und x64
Stolperte ich über einen Unterschied in der Art floating-point-Arithmetik getan werden zwischen MS VS 2010 baut für x86 und x64 (sowohl ausgeführt auf die gleiche 64-bit-Maschine).
Dies ist ein reduziertes Codebeispiel:
float a = 50.0f;
float b = 65.0f;
float c = 1.3f;
float d = a*c;
bool bLarger1 = d<b;
bool bLarger2 = (a*c)<b;
Den booleschen bLarger1, ist immer falsch (d 65.0 in beiden builds).
Variable bLarger2 false für x64, aber wahr für x86!
Ich bin mir wohl bewusst floating-point-Arithmetik und Rundung-Effekte statt. Ich weiß auch, dass 32-bit manchmal verwendet verschiedene Anweisungen für Gleitkomma-Operationen als 64-bit-builds. Aber in diesem Fall bin ich es fehlten einige Informationen.
Warum gibt es eine Diskrepanz zwischen bLarger1 und bLarger2 auf den ersten Platz? Warum ist es nur auf der 32-bit-build?
- meine Vermutung ist, dass die x86-version ist die Verwendung der FPU-Register für, die und die x64 ist die Verwendung der SSE-Register für die. Aber Sie wahrscheinlich benötigen, zu betrachten, IL-code und auch in den Maschinen-code.
- Sicherlich x86 ist mit x87-Einheit, und die x64 ist die Verwendung der SSE-Einheit. Aber es nicht wirklich erklären, den Unterschied. Sie sollten beide die gleiche Antwort erhalten. @Oliver kann Ihnen zeigen, wie Sie kompilieren den code, weil meiner ziemlich Versuch einer repro gescheitert. Beide bools sind
false
für x86 und x64 für mich. - OK, jetzt habe ich ein repro!
- Es geht um die Art und Weise ein*c behandelt wird, in den Ausdruck für
bLarger2
. Ich denke, es wird eine float-mult in einem und ein Doppel-mult in die andere, oder so ähnlich - Die Frage ist, warum ist dies überraschend, wohl wissend, dass floating-point nicht genau. Je nach compiler, compiler-Optionen, etc. Ergebnisse können abweichen.
- Auch der Unterschied zwischen den zwei Vergleich-Operationen auf der gleichen Plattform, die gleich Aussehen, war besonders verwirrend für mich
- Während die floating point Arithmetik nicht exakt repräsentieren alle realen Werte, es ist wiederholbar und gut definiert. Es ist nicht unvernünftig, zu hoffen, dass für Kohärenz zwischen den verschiedenen Compilern.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Das Problem Scharniere auf diesen Ausdruck:
Ich schaute auf den code, der generiert unter VS2008, nicht mit VS2010 zur hand. Für 64-bit-code ist:
Für 32-bit-code ist:
Also unter 32 bit die Berechnung erfolgt in der x87-Einheit, und die unter 64 bit ausgeführt wird, indem die x 64 Gerät.
- Und der Unterschied hier ist, dass die x87-Operationen werden alle durchgeführt, die höher ist als einfacher Genauigkeit. Standardmäßig werden die Berechnungen durchgeführt, die die doppelte Genauigkeit. Auf der anderen Seite der SSE-unit-Operationen sind Reine single-precision-Berechnungen.
Können Sie überzeugen, die 32-bit-Einheit, um alle Berechnungen durchzuführen, single precision Genauigkeit wie diese:
Wenn Sie hinzufügen, dass Ihre 32-bit-Programm werden Sie feststellen, dass die booleans sind beide auf false gesetzt.
Gibt es einen fundamentalen Unterschied in der Art und Weise, dass die x87 and SSE floating point-Einheiten arbeiten. Die x87-Einheit verwendet die gleichen Anweisungen für die single-und double-precision-Arten. Das laden der Daten in Registern in die x87-FPU-stack und die Register sind immer 10 byte Intel erweitert. Sie können Einfluss auf die Genauigkeit mit der floating-point-control-Wort. Aber die Anweisungen, die der compiler schreibt, sind nichts von diesem Staat.
Auf der anderen Seite, die die SSE-Einheit verwendet verschiedene Anweisungen für Operationen, die auf single-und double-precision. Das bedeutet, dass der compiler emittieren kann code, ist die volle Kontrolle über die Genauigkeit der Berechnung.
So, die x87-Einheit ist der "bad guy" hier. Sie kann vielleicht versuchen Sie zu überzeugen, einen compiler zu emittieren SSE-Instruktionen auch für 32-bit-targets. Und sicherlich, wenn ich kompiliert deinen code unter VS2013 ich festgestellt, dass die beiden 32-und 64-bit-targets emittiert SSE-Anweisungen.
/arch:SSE2
und vermeiden Sie alle, die x87-Schmerzen. Aber Ihr Programm läuft nur auf Rechnern mit SSE2-Einheiten.Floating-points-Operationen sind immer ungenau und der Vergleich der beiden schwebt dieser in der Nähe (oder gleich) fast nie wieder die richtige Leistung.
Gleitkommazahlen gespeichert und verarbeitet, die sich anders als auf 32bit und 64bit Maschinen (wie auch vorgeschlagen, durch Kommentare). Wenn ich mich richtig erinnere, in VC 32-bit floats gespeichert werden, auf den Stapel und FPU (Floating-Point Unit) verarbeitet, in der Erwägung, dass schwimmt auf einer 64bit-Maschine gespeichert werden können, in speziellen Registern (SSE) und berechnet mithilfe von anderen Einheiten in der CPU.
Habe ich keine eindeutige Quelle zu meiner Antwort, aber bitte schauen Sie auf auf dieser Seite oder diese.