Recherche…


Les nombres à virgule flottante sont étranges

La première erreur que presque tous les programmeurs font est de présumer que ce code fonctionnera comme prévu:

float total = 0;
for(float a = 0; a != 2; a += 0.01f) {
    total += a;
}

Le programmeur novice suppose que cela résume chaque nombre compris entre 0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99 , pour donner le résultat 199 , la réponse mathématiquement correcte.

Deux choses se produisent qui rendent cela inexact:

  1. Le programme tel qu'il est écrit ne se termine jamais. a ne devient jamais égal à 2 et la boucle ne se termine jamais.
  2. Si nous réécrivons la logique de boucle pour vérifier a < 2 place, la boucle se termine, mais le total finit par être différent de 199 . Sur les machines conformes à la norme IEEE754, la somme est généralement d'environ 201 place.

La raison en est que les nombres à virgule flottante représentent des approximations de leurs valeurs attribuées .

L'exemple classique est le calcul suivant:

double a = 0.1;
double b = 0.2;
double c = 0.3;
if(a + b == c)
    //This never prints on IEEE754-compliant machines
    std::cout << "This Computer is Magic!" << std::endl; 
else
    std::cout << "This Computer is pretty normal, all things considered." << std::endl;

Bien que ce que le programmeur voit, ce sont trois nombres écrits en base10, ce que le compilateur (et le matériel sous-jacent) voient sont des nombres binaires. Parce que 0.1 , 0.2 et 0.3 exigent une division parfaite par 10 - ce qui est assez facile dans un système de base 10, mais impossible dans un système de base 2 - ces nombres doivent être stockés dans des formats imprécis, similaires au nombre 1/3 doit être stocké dans la forme imprécise 0.333333333333333... en base-10.

//64-bit floats have 53 digits of precision, including the whole-number-part.
double a =     0011111110111001100110011001100110011001100110011001100110011010; //imperfect representation of 0.1
double b =     0011111111001001100110011001100110011001100110011001100110011010; //imperfect representation of 0.2
double c =     0011111111010011001100110011001100110011001100110011001100110011; //imperfect representation of 0.3
double a + b = 0011111111010011001100110011001100110011001100110011001100110100; //Note that this is not quite equal to the "canonical" 0.3!


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow