Frage Kann ich garantieren, dass der C ++ - Compiler meine Berechnungen nicht neu anordnet?


Ich lese gerade das Ausgezeichnete durch Bibliothek für Double-Double und Quad-Double Arithmetic Papier, und in den ersten Zeilen merke ich, dass sie eine Summe in der folgenden Weise ausführen:

std::pair<double, double> TwoSum(double a, double b)
{
    double s = a + b;
    double v = s - a;
    double e = (a - (s - v)) + (b - v);
    return std::make_pair(s, e);
}

Die Berechnung des Fehlers, e, beruht auf der Tatsache, dass die Berechnung dieser Reihenfolge von Operationen genau wegen der nicht assoziativen Eigenschaften von IEEE-754 Fließkomma-Mathematik folgt.

Wenn ich dies in einem modernen optimierenden C ++ - Compiler (z. B. MSVC oder gcc) kompiliere, kann ich dann sicherstellen, dass der Compiler die Art und Weise, wie diese Berechnung durchgeführt wird, nicht optimiert?

Zweitens, ist dies irgendwo innerhalb des C ++ - Standards garantiert?


7
2017-10-05 02:29


Ursprung


Antworten:


Ja, das ist sicher (zumindest in diesem Fall). Sie verwenden dort nur zwei "Operatoren", den primären Ausdruck (something) und die Binärdatei something +/- something (Zusatzstoff).

Sektion 1.9 Program execution (von C ++ 0x N3092) besagt:

Operatoren können nach den üblichen mathematischen Regeln nur dann neu gruppiert werden, wenn die Operatoren wirklich assoziativ oder kommutativ sind.

In Bezug auf die Gruppierung, 5.1 Primary expressions Zustände:

Ein eingeklammerter Ausdruck ist ein primärer Ausdruck, dessen Typ und Wert mit denen des eingeschlossenen Ausdrucks identisch sind. ... Der in Klammern gesetzte Ausdruck kann genau in denselben Kontexten verwendet werden, in denen der eingeschlossene Ausdruck verwendet werden kann, und mit derselben Bedeutung, sofern nicht anders angegeben.

Ich glaube die Verwendung des Wortes "identisch" in diesem Zitat erfordert eine konforme Implementierung, um zu garantieren, dass sie in der spezifizierten Reihenfolge ausgeführt wird, es sei denn, eine andere Bestellung kann den genau gleiche Ergebnisse.

Und zum Hinzufügen und Subtrahieren, Abschnitt 5.7 Additive operators hat:

Die additiven Operatoren + und - Gruppe von links nach rechts.

So diktiert der Standard die Ergebnisse. Wenn der Compiler sicherstellen kann, dass dieselben Ergebnisse mit unterschiedlicher Reihenfolge der Operationen erhalten werden können, kann er sie neu anordnen. Aber ob dies geschieht oder nicht, Sie werden keinen Unterschied erkennen können.


4
2017-10-05 02:47



Vielleicht möchten Sie sich die g ++ Handbuchseite ansehen: http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Optimize-Options.html#Optimize-Options

Besonders -assoziative-Mathe, -mathematische und -frost-speichern

Gemäß dem Handbuch von g ++ wird der Ausdruck nicht neu angeordnet, es sei denn, Sie fordern ihn ausdrücklich an.


6
2017-10-05 02:54



Dies ist ein sehr berechtigtes Problem, da der C ++ - Compiler von Intel, der sehr weit verbreitet ist, standardmäßig Optimierungen durchführt, die das Ergebnis ändern können.

Sehen http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/cpp/lin/compiler_c/copts/common_options/option_fp_model.htm#option_fp_model


5
2017-10-05 03:33



Ich wäre ziemlich überrascht, wenn irgendein Compiler die Assoziativität von arithmetischen Operatoren falsch mit Standard-Optimierungsoptionen angenommen hätte.

Aber Seien Sie vorsichtig bei der erweiterten Genauigkeit der FP-Register.

Sehen Sie in der Compilerdokumentation nach, um sicherzustellen, dass FP-Werte keine erweiterte Genauigkeit aufweisen.


2
2017-10-05 02:52



Im Allgemeinen sollten Sie in der Lage sein - der Optimierer sollte sich der Eigenschaften der realen Operationen bewusst sein.

Das heißt, ich würde den Compiler, den ich benutzt habe, ausgiebig testen.


0
2017-10-05 02:32



Ja. Der Compiler wird die Reihenfolge Ihrer Berechnungen innerhalb eines solchen Blocks nicht ändern.


0
2017-10-05 02:34



Zwischen Compiler-Optimierungen und Out-of-Order-Ausführung auf dem Prozessor ist es fast eine Garantie, dass die Dinge nicht genau so ablaufen, wie Sie sie bestellt haben.

JEDOCH ist garantiert, dass dies das Ergebnis NIE ändert. C ++ folgt der Standardreihenfolge von Vorgängen, und alle Optimierungen behalten dieses Verhalten bei.

Fazit: Mach dir keine Sorgen. Schreiben Sie Ihren C ++ - Code mathematisch korrekt und vertrauen Sie dem Compiler. Wenn irgendetwas schief läuft, ist das Problem mit ziemlicher Sicherheit nicht der Compiler.


0
2017-10-05 02:37



Wenn Sie wirklich brauchen, können Sie eine noinline Funktion no_reorder (float x) {return x; }, und verwenden Sie es dann anstelle von Klammern. Natürlich ist es keine besonders effiziente Lösung.


0
2017-12-02 14:11



Wie bei den anderen Antworten sollte man sich darauf verlassen können, dass der Compiler das Richtige tut - die meisten Compiler erlauben es Ihnen, den Assembler zu kompilieren und zu inspizieren (benutzen Sie -S für gcc) - Sie können das tun, um sicher zu gehen die Reihenfolge der Operation, die Sie erwarten.

Verschiedene Optimierungsstufen (in gcc, -O_O2 usw.) ermöglichen eine Neuanordnung von Code (sequentieller Code wie dieser ist jedoch wahrscheinlich nicht betroffen) - aber ich würde vorschlagen, dass Sie diesen bestimmten Teil des Codes in eine separate Datei isolieren sollten , so dass Sie die Optimierungsstufe nur für die Berechnung steuern können.


-1
2017-10-05 02:40