Maison  >  Article  >  développement back-end  >  Pourquoi mon code d'arrondi à virgule flottante produit-il des résultats différents avec les optimisations du compilateur activées ?

Pourquoi mon code d'arrondi à virgule flottante produit-il des résultats différents avec les optimisations du compilateur activées ?

Susan Sarandon
Susan Sarandonoriginal
2024-11-14 19:39:02906parcourir

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

Disparités d'arrondi à virgule flottante avec l'optimisation activée : bug du compilateur ou dilemme d'optimisation ?

Les calculs à virgule flottante peuvent souvent présenter un comportement inattendu, en particulier lorsque les optimisations du compilateur sont activées. Considérez l'extrait de code suivant :

#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;
}

Résultat attendu :

4.5
4.6

Cependant, lorsque ce code est compilé à l'aide de g avec des optimisations (O1 - O3), le résultat devient :

4.5
4.5

Cause de la disparité :

Ceci L'incohérence vient du fait que les processeurs x86 utilisent en interne une précision étendue de 80 bits pour les calculs en virgule flottante. Cependant, les variables doubles ont généralement une largeur de 64 bits. Lorsque les valeurs à virgule flottante sont stockées depuis les registres du processeur vers la mémoire, elles sont arrondies d'une précision de 80 bits à une précision de 64 bits. Cet arrondi peut introduire de légères erreurs.

Impact des niveaux d'optimisation :

Différents niveaux d'optimisation peuvent affecter la fréquence à laquelle les valeurs à virgule flottante sont enregistrées en mémoire. Avec des niveaux d’optimisation plus élevés, cela se produit plus fréquemment. En conséquence, l'erreur d'arrondi devient plus prononcée.

Solutions :

  1. Utilisez l'option GCC -ffloat-store : Ceci L'option demande au compilateur de stocker les variables à virgule flottante en mémoire au lieu des registres. Cela force l'arrondi à se produire de manière cohérente sur différents niveaux d'optimisation.
  2. Utilisez le long double Type : long double a généralement une largeur de 80 bits sur g . L'utilisation de ce type peut éviter complètement le problème d'arrondi.
  3. Modifier le stockage des variables : Stockez les résultats de calcul intermédiaires dans des variables pour minimiser l'erreur d'arrondi.

Considérations supplémentaires :

  • Les builds Intel x86_64 sont moins affectées par ce problème car les compilateurs utilisent les registres SSE pour float et double par défaut, éliminant ainsi le besoin d'une précision étendue.
  • L'option du compilateur -mfpmath peut être utilisée pour contrôler la précision en virgule flottante utilisée dans les builds x86_64.
  • Que ce soit Activer toujours l'option -ffloat-store dépend de l'application spécifique et de sa sensibilité à la précision de la virgule flottante. Pour les applications critiques, il peut être judicieux d'utiliser cette option pour garantir des résultats cohérents.
  • L'enquête sur le code C et les bibliothèques existantes à la recherche de problèmes potentiels peut prendre beaucoup de temps. Pensez à utiliser des outils ou à mettre en œuvre des tests pour détecter et résoudre tout problème de précision en virgule flottante.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn