float étrange erreur d’imprécision dans c

Il m’est arrivé aujourd’hui une chose étrange. J’essaie de comstackr et d’exécuter la sortie de ce code. Voici le code qui ajoute simplement des valeurs flottantes à un tableau de float, puis l’affiche. Le code simple:

int main(){ float r[10]; int z; int i=34; for(z=0;z<10;z++){ i=z*z*z; r[z]=i; r[z]=r[z]+0.634; printf("%f\n",r[z]); } } 

le résultat:

 0.634000 1.634000 8.634000 27.634001 64.634003 125.634003 216.634003 343.634003 512.633972 729.633972 

notez que parmi les 27, apparaissent les chiffres après le 0,634 qui ne devraient pas être là. Quelqu’un sait pourquoi c’est arrivé? C’est un événement causé par une approximation en virgule flottante? ..

PS j’ai un système Linux Linux, 64 bits

Merci a tous

Un nombre peut être représenté sous la forme suivante:

[signe] [mantisse] * 2 [exposant]

Il y aura donc des erreurs d’arrondis ou des erreurs relatives lorsque l’espace est moins en mémoire.

De wiki :

Le format à virgule flottante simple précision est un format de numéro d’ordinateur qui occupe 4 octets (32 bits) dans la mémoire de l’ordinateur et représente une large plage dynamic de valeurs à l’aide d’un point flottant.

entrez la description de l'image ici

La norme IEEE 754 spécifie un binary32 comme ayant:

 Sign bit: 1 bit Exponent width: 8 bits Significand precision: 24 bits (23 explicitly stored) 

Cela donne une précision de 6 à 9 chiffres décimaux significatifs (si une chaîne décimale comportant au plus 6 décimales significatives est convertie en précision simple IEEE 754 puis reconvertie en le même nombre de décimales significatives, la chaîne finale doit correspondre à l’original; et si une simple précision IEEE 754 est convertie en chaîne décimale avec au moins 9 décimales significatives, puis reconvertie en simple, le nombre final doit correspondre à l’original [4]).

Edit (le commentaire d’Edward): Des représentations en virgule flottante plus grandes (plus de bits) permettent une plus grande précision .

Oui, il s’agit d’une erreur d’approximation en virgule flottante ou d’erreur d’ arrondi . La représentation des nombres en virgule flottante utilise la quantification pour représenter un grand nombre de nombres. Elle ne représente donc que des étapes et arrondit tous les nombres intermédiaires au pas le plus proche. Cette erreur de cause si le numéro désiré n’est pas une de ces étapes.

Outre les autres réponses utiles, il peut être intéressant d’imprimer plus de chiffres que le nombre par défaut:

 int main(){ float r[10]; int z; int i=34; for(z=0;z<10;z++){ i=z*z*z; r[z]=i; r[z]=r[z]+0.634; printf("%.30f\n",r[z]); } } 

donne

 0.634000003337860107421875000000 1.633999943733215332031250000000 8.633999824523925781250000000000 27.634000778198242187500000000000 64.634002685546875000000000000000 125.634002685546875000000000000000 216.634002685546875000000000000000 343.634002685546875000000000000000 512.633972167968750000000000000000 729.633972167968750000000000000000 

En particulier, notez que 0.634 n'est pas réellement "0.634", mais plutôt le nombre le plus proche pouvant être représenté par un float .

“float” n’a qu’une précision d’environ six chiffres, il n’est donc pas surprenant que vous obteniez des erreurs d’une telle taille.

Si vous utilisiez “double”, vous auriez une précision d’environ 15 chiffres. Vous auriez une erreur, mais vous obtiendriez par exemple 125.634000000000003 et non 125.634003.

Ainsi, vous obtiendrez toujours des erreurs d’arrondi et vos résultats ne seront pas tout à fait ce que vous attendez, mais en utilisant le double, l’effet sera minime. Avertissement: Si vous effectuez des opérations telles que l’ajout de 125 + 0,634, puis de la soustraction 125, le résultat ne sera (probablement) pas 0,634. Peu importe si vous utilisez float ou double. Mais avec un double, le résultat sera très très proche de 0,634.

En principe, étant donné le choix entre float et double, vous ne devriez jamais utiliser float, sauf si vous avez une très, très bonne raison.