Maison  >  Article  >  développement back-end  >  Pourquoi l'arithmétique à virgule flottante C produit-elle des résultats inattendus et comment pouvons-nous atténuer ces anomalies de précision ?

Pourquoi l'arithmétique à virgule flottante C produit-elle des résultats inattendus et comment pouvons-nous atténuer ces anomalies de précision ?

Barbara Streisand
Barbara Streisandoriginal
2024-11-04 21:38:02814parcourir

Why does C   floating-point arithmetic produce unexpected results, and how can we mitigate these precision anomalies?

Anomalie et résolution de précision en virgule flottante en C

Malgré leur utilisation répandue, les nombres à virgule flottante en C présentent des limites en termes de précision. Considérez l'extrait de code suivant :

<code class="cpp">double a = 0.3;
std::cout.precision(20);
std::cout << a << std::endl;

Ce code génère 0,299999999999999999889 au lieu du 0,3 attendu. Cet écart se produit parce que la variable a n'est pas stockée exactement sous la forme d'un nombre à virgule flottante double précision 0,3 mais plutôt comme une approximation de celui-ci en raison de la représentation finie des valeurs à virgule flottante.

Un comportement plus surprenant se produit lorsque a est ajouté à plusieurs reprises 50 fois :

<code class="cpp">double a, b;
a = 0.3;
b = 0;
for (char i = 1; i <= 50; i++) {
  b = b + a;
};
std::cout.precision(20);
std::cout << b << std::endl;

Ce code génère étonnamment 15.000000000000014211 au lieu de 15.0. En effet, chaque ajout accumule l'erreur d'approximation, conduisant à une erreur accumulée supérieure à la précision d'origine.

Résoudre l'anomalie de précision

Pour obtenir des résultats précis, il est Il est crucial d'éviter de définir une précision de sortie supérieure aux chiffres disponibles pour le type numérique. Ceci peut être réalisé en utilisant la classe std::numeric_limits :

<code class="cpp">#include <iostream>
#include <limits>
int main()
{
        double a = 0.3;
        std::cout.precision(std::numeric_limits<double>::digits10);
        std::cout << a << std::endl;
        double b = 0;
        for (char i = 1; i <= 50; i++) {
                  b = b + a;
        };
        std::cout.precision(std::numeric_limits<double>::digits10);
        std::cout << b << std::endl;
}</code>

Ce code utilise la fonction membre digits10 pour définir la précision au maximum de chiffres disponibles pour un nombre à virgule flottante double précision, qui est 15. chiffres pour le double.

Limitations de l'arithmétique à virgule flottante

Bien que la solution fournie minimise l'erreur de précision, il est important de reconnaître que l'arithmétique à virgule flottante a des limites inhérentes . Si une boucle implique des milliers d'itérations, même avec une précision définie de manière appropriée, l'erreur accumulée peut devenir importante. Dans de tels scénarios, d'autres types de données, tels que des nombres à virgule fixe ou des nombres rationnels, peuvent être plus adaptés pour conserver des valeurs exactes.

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