Heim  >  Artikel  >  Backend-Entwicklung  >  Warum führt mein Gleitkomma-Rundungscode bei aktivierten Compiler-Optimierungen zu unterschiedlichen Ergebnissen?

Warum führt mein Gleitkomma-Rundungscode bei aktivierten Compiler-Optimierungen zu unterschiedlichen Ergebnissen?

Susan Sarandon
Susan SarandonOriginal
2024-11-14 19:39:02850Durchsuche

Why Does My Floating-Point Rounding Code Produce Different Results with Compiler Optimizations Enabled?

Gleitkomma-Rundungsunterschiede bei aktivierter Optimierung: Ein Compiler-Fehler oder ein Optimierungsdilemma?

Gleitkommaberechnungen können oft unerwartetes Verhalten zeigen, insbesondere wenn Compileroptimierungen sind aktiviert. Betrachten Sie das folgende Code-Snippet:

#include <cstdlib>
#include <iostream>
#include <cmath>

double round(double v, double digit)
{
    double pow = std::pow(10.0, digit);
    double t = v * pow;
    double r = std::floor(t + 0.5);
    return r / pow;
}

int main()
{
    std::cout << round(4.45, 1) << std::endl;
    std::cout << round(4.55, 1) << std::endl;
}

Erwartete Ausgabe:

4.5
4.6

Wenn dieser Code jedoch mit g mit Optimierungen (O1 – O3) kompiliert wird, sieht die Ausgabe wie folgt aus:

4.5
4.5

Ursache der Ungleichheit:

Diese Inkonsistenz ist auf die Tatsache zurückzuführen, dass x86-Prozessoren intern eine erweiterte 80-Bit-Präzision für Gleitkommaberechnungen verwenden. Double-Variablen sind jedoch normalerweise 64 Bit breit. Wenn Gleitkommawerte von den CPU-Registern im Speicher gespeichert werden, werden sie von 80-Bit-Präzision auf 64-Bit-Präzision gerundet. Diese Rundung kann zu geringfügigen Fehlern führen.

Auswirkungen der Optimierungsstufen:

Unterschiedliche Optimierungsstufen können sich auf die Häufigkeit auswirken, mit der Gleitkommawerte im Speicher gespeichert werden. Bei höheren Optimierungsstufen kommt dies häufiger vor. Dadurch wird der Rundungsfehler stärker ausgeprägt.

Lösungen:

  1. Verwenden Sie die GCC-Option -ffloat-store: Dies Die Option weist den Compiler an, Gleitkommavariablen im Speicher statt in Registern zu speichern. Dies erzwingt, dass die Rundung über verschiedene Optimierungsstufen hinweg konsistent erfolgt.
  2. Verwenden Sie den Long-Double-Typ: Long-Double ist in der Regel 80 Bit breit auf g . Durch die Verwendung dieses Typs kann das Rundungsproblem vollständig vermieden werden.
  3. Variablenspeicher ändern:Zwischenberechnungsergebnisse in Variablen speichern, um den Rundungsfehler zu minimieren.

Weitere Überlegungen:

  • Intel x86_64-Builds sind von diesem Problem weniger betroffen, da Compiler standardmäßig SSE-Register für Float und Double verwenden, wodurch keine erweiterte Genauigkeit erforderlich ist.
  • - Die Compileroption mfpmath kann verwendet werden, um die in x86_64-Builds verwendete Gleitkommagenauigkeit zu steuern.
  • Ob die Option -ffloat-store immer aktiviert werden soll, hängt von der jeweiligen Anwendung und ihrer Empfindlichkeit gegenüber Gleitkommagenauigkeit ab. Bei kritischen Anwendungen kann es sinnvoll sein, diese Option zu verwenden, um konsistente Ergebnisse sicherzustellen.
  • Die Untersuchung vorhandener C-Codes und Bibliotheken auf potenzielle Probleme kann zeitaufwändig sein. Erwägen Sie die Verwendung von Tools oder die Implementierung von Tests, um Probleme mit der Gleitkommagenauigkeit zu erkennen und zu beheben.

Das obige ist der detaillierte Inhalt vonWarum führt mein Gleitkomma-Rundungscode bei aktivierten Compiler-Optimierungen zu unterschiedlichen Ergebnissen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn