Warum optimiert MSVS +0 nicht weg? [duplicate]

Lesezeit: 4 Minuten

Benutzeravatar von Vorac
Vorac

Diese Frage zeigt ein sehr interessantes Phänomen: denormalisiert Floats verlangsamen den Code um mehr als eine Größenordnung.

Das Verhalten wird in der akzeptierten Antwort gut erklärt. Es gibt jedoch einen Kommentar mit derzeit 153 Upvotes, auf den ich keine zufriedenstellende Antwort finden kann:

Warum lässt der Compiler in diesem Fall nicht einfach +/- 0 fallen?!? –
Michael Dorgan

Nebenbemerkung: Ich habe den Eindruck, dass 0f genau darstellbar ist / sein muss (außerdem muss die binäre Darstellung nur aus Nullen bestehen), kann aber im c11-Standard keine solche Behauptung finden. Ein Zitat, das dies beweist, oder ein Argument, das diese Behauptung widerlegt, wäre sehr willkommen. Trotzdem, MichaelDie Frage von ist hier die Hauptfrage.


§5.2.4.2.2

Eine Implementierung kann Null und Werten, die keine Gleitkommazahlen sind (wie Unendlichkeiten und NaNs), ein Vorzeichen geben oder sie ohne Vorzeichen belassen.

  • Dies wird in einem der letzten Kommentare in der Antwort auf die verknüpfte Frage beantwortet: “@s73v3r: Das +0.f kann nicht optimiert werden, da Gleitkomma eine negative 0 hat und das Ergebnis der Addition von +0.f zu – .0f ist +0.f. Das Hinzufügen von 0.f ist also keine Identitätsoperation und kann nicht optimiert werden. – Eric Postpischil”

    – Michael Burr

    10. Mai 2013 um 7:20 Uhr


  • Und um es klar zu sagen – es ist nicht das +0.f oder -0.f die denormalisiert sind – es ist der Wert im Array, dem Null hinzugefügt wird, der denormalisiert wird (und die Verlangsamung verursacht).

    – Michael Burr

    10. Mai 2013 um 7:25 Uhr


  • Ich glaube nicht, dass die Bearbeitung etwas ändert. Die von MSVC verwendete Gleitkommaimplementierung verwendet vorzeichenbehaftete Nullen. Das ist möglicherweise nicht vom C-Standard erforderlich, aber möglicherweise von IEEE 754 (ich weiß es ehrlich gesagt nicht). Allerdings ist die /fp:fast Option kann dazu führen, dass der Compiler optimiert wird +0.f – Ich weiß nicht.

    – Michael Burr

    10. Mai 2013 um 7:33 Uhr

  • Ich glaube nicht, dass die C- oder C++-Standards angeben, wie eine Gleitkomma-Null dargestellt werden soll. Mein Verständnis ist jedoch, dass IEEE 754 angibt, dass Null durch alle Nullbits dargestellt wird (mit Ausnahme des Vorzeichenbits im Fall einer negativen Null). Aber ich bin weit davon entfernt, ein Gleitkomma-Experte zu sein, und weiß so gut wie nichts über die Details des IEEE-Standards. Was ich in diesem Kommentar sage, ist also wahrscheinlich nicht sehr nützlich.

    – Michael Burr

    10. Mai 2013 um 7:37 Uhr

  • Jetzt hat sie 153 Stimmen.

    – LF

    15. Juni 2019 um 4:42 Uhr

Benutzeravatar von Eric Postpischil
Eric Postpischil

Der Compiler kann das Hinzufügen einer positiven Gleitkommazahl von Null nicht eliminieren, da es sich nicht um eine Identitätsoperation handelt. Nach IEEE 754-Regeln das Ergebnis der Addition von +0. bis −0. ist nicht −0.; es ist +0.

Der Compiler kann die Subtraktion von +0 eliminieren. oder die Addition von –0. denn das sind Identitätsoperationen.

Zum Beispiel, wenn ich das kompiliere:

double foo(double x) { return x + 0.; }

mit Apple GNU C 4.2.1 verwenden -O3 auf einem Intel-Mac enthält der resultierende Assembler-Code addsd LC0(%rip), %xmm0. Wenn ich das kompiliere:

double foo(double x) { return x - 0.; }

es gibt keine add-Anweisung; die Assembly gibt lediglich ihre Eingabe zurück.

Es ist also wahrscheinlich, dass der Code in der ursprünglichen Frage eine Hinzufügungsanweisung für diese Anweisung enthielt:

y[i] = y[i] + 0;

enthielt aber keine Anweisung für diese Anweisung:

y[i] = y[i] - 0;

Die erste Anweisung beinhaltete jedoch Arithmetik mit subnormalen Werten y[i]also war es ausreichend, das Programm zu verlangsamen.

Es ist nicht die Nullkonstante 0.0f das ist denormalisiert, es sind die Werte, die sich bei jeder Iteration der Schleife Null nähern. Je näher sie Null kommen, desto genauer müssen sie dargestellt werden, daher die Denormalisierung. In der ursprünglichen Frage sind dies die y[i] Werte.

Der entscheidende Unterschied zwischen der langsamen und der schnellen Version des Codes ist die Anweisung y[i] = y[i] + 0.1f;. Sobald diese Zeile ausgeführt wird, geht die zusätzliche Genauigkeit im Gleitkommawert verloren, und die zur Darstellung dieser Genauigkeit erforderliche Denormalisierung wird nicht mehr benötigt. Danach Gleitkommaoperationen weiter y[i] bleiben schnell, weil sie nicht denormalisiert sind.

Warum geht die zusätzliche Genauigkeit verloren, wenn Sie hinzufügen 0.1f? Weil Gleitkommazahlen nur so viele signifikante Stellen haben. Angenommen, Sie haben dann genug Speicherplatz für drei signifikante Ziffern 0.00001 = 1e-5und 0.00001 + 0.1 = 0.1zumindest für dieses Float-Beispielformat, da es keinen Platz zum Speichern des niedrigstwertigen Bits hat 0.10001.

  • Ich kann sehen, warum ich kürzlich eine Ablehnung erhalten habe, weil ich die Frage nicht so beantwortet habe, wie sie jetzt erscheint. Ursprünglich lautete der Titel dieser Frage: „Warum optimiert MSVS +0 nicht weg? Stattdessen verwandelt es es in einen denormalisierten Float?“ und meine Antwort war ein Versuch, die Verwirrung im zweiten Teil zu klären. Natürlich gibt es auch den Unterschied zwischen +0.0f und -0.0f, der die Hauptfrage beantwortet.

    – Recycling

    17. September 2018 um 20:14 Uhr

1414460cookie-checkWarum optimiert MSVS +0 nicht weg? [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy