Ich kenne die Bedeutung des Modifikators strictfp
für Methoden (und für Klassen) gemäß der JLS:
JLS 8.4.3.5, strictfp-Methoden:
Der Effekt des Modifikators strictfp besteht darin, alles float oder double zu machen Ausdrücke innerhalb des Methodenkörpers werden explizit FP-strict (§15.4).
JLS 15.4 FP-strikte Ausdrücke:
Innerhalb eines FP-strikten Ausdrucks müssen alle Zwischenwerte sein Elemente der Float-Wert-Menge oder der doppelten Wert-Menge, was bedeutet, dass Die Ergebnisse aller FP-strikten Ausdrücke müssen von denen vorhergesagt werden IEEE 754-Arithmetik für Operanden, die mit Einzel- und Doppeloperanden dargestellt werden Formate.
Innerhalb eines Ausdrucks, der nicht FP-strikt ist, wird ein gewisser Spielraum gewährt eine Implementierung, um einen erweiterten Exponentenbereich zur Repräsentation zu verwenden Zwischenergebnisse; der Nettoeffekt ist, grob gesagt, dass a Berechnung könnte "die richtige Antwort" in Situationen erzeugen, in denen es könnte die ausschließliche Verwendung des Gleitkomma-Wertes oder des doppelten Wertes resultieren in Überlauf oder Unterlauf.
Ich habe versucht, einen Weg zu finden, um einen tatsächlichen Unterschied zwischen einem Ausdruck in einer strictfp
-Methode und einem, der nicht strictfp
ist, zu erhalten. Ich habe das auf zwei Laptops versucht, einen mit einer Intel Core i3 CPU und einen mit einer Intel Core i7 CPU. Und ich kann keinen Unterschied machen.
Viele Beiträge weisen darauf hin, dass der native Fließkommawert, der strictfp
nicht verwendet, 80-Bit-Fließkommazahlen verwenden kann und dass zusätzliche darstellbare Zahlen unterhalb des kleinsten möglichen Java-Doppels (am nächsten bei Null) oder oberhalb des höchstmöglichen Wertes liegen 64-Bit-Java-Double.
Ich habe diesen Code unten mit und ohne strictfp
-Modifikator ausprobiert und es gibt genau die gleichen Ergebnisse.
Tatsächlich nehme ich an, dass jeder Unterschied nur dann auftauchen würde, wenn der Code in Assembly kompiliert wird, sodass ich ihn mit dem -Xcomp
JVM-Argument ausführe. Aber kein Unterschied.
Ich habe einen weiteren Beitrag gefunden, der erklärt, wie Sie die Assembly erhalten können von HotSpot generierter Code ( OpenJDK-Dokumentation ). Ich verwende meinen Code mit java -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
.
Der erste Ausdruck ( v * 1.0000001 / 1.0000001
) mit dem strictfp
-Modifikator und auch derselbe ohne ihn wird nach:
Es gibt nichts in diesem Code, das das Ergebnis jedes Schritts auf 64 Bits abschneidet, wie ich es erwartet hatte. Ansehen Dokumentation von movsd
, mulsd
und divsd
, sie alle erwähnen, dass diese (SSE-) Anweisungen auf 64-Bit-Gleitkommawerten, nicht auf 80-Bit-Werten, wie erwartet, arbeiten. Daher erscheint es logisch, dass der doppelte Wert, auf den diese Anweisungen angewendet werden, bereits der IEEE 754-Wert ist, so dass es keinen Unterschied zwischen strictfp
und dem nicht geben würde.
Meine Fragen sind:
strictfp
Modifikator gibt? Wenn Sie mit "modern" Prozessoren meinen, die die Art von SSE2-Anweisungen unterstützen, die Sie in Ihrer Frage als von Ihrem Compiler ( mulsd
, ...) zitiert haben, dann ist die Antwort nein, strictfp
macht keinen Unterschied , weil der Befehlssatz es nicht erlaubt, die Abwesenheit von strictfp
zu nutzen. Die verfügbaren Anweisungen sind bereits optimal, um die genauen Spezifikationen von strictfp
zu berechnen. Mit anderen Worten, auf dieser Art von moderner CPU erhalten Sie strictfp
Semantik die ganze Zeit für den gleichen Preis.
Wenn Sie unter "modern" die historische 387 FPU verstehen, dann ist es möglich, einen Unterschied zu beobachten, wenn eine intermediäre Berechnung in strictfp
mode über- oder unterlaufen würde (der Unterschied ist, dass sie nicht überläuft oder bei Unterlauf halte mehr Präzisionsbits als erwartet).
Eine typische strictfp
Berechnung, die für den 387 kompiliert wurde, wird wie die Assembly in dieser Antwort aussehen, mit einer guten Platzierung Multiplikationen mit gut gewählten Zweierpotenzen zum Unterlaufen verhalten sich genauso wie in IEEE 754 binary64. Ein Round-Trip des Ergebnisses über einen 64-Bit-Speicherplatz sorgt dann für Überläufe.
Die gleiche Berechnung, die ohne strictfp
kompiliert wurde, würde einen 387-Befehl pro Grundoperation erzeugen, beispielsweise nur den Multiplikationsbefehl fmulp
für eine Multiplikation auf Quellenebene. (Der 387 wäre so konfiguriert worden, dass er die gleiche Signifikanzbreite wie binary64, 53 Bits, am Anfang des Programms verwendet.)
Tags und Links java assembly sse expression-evaluation strictfp