Précision dans les flotteurs

En général, on dit qu’un flottant a une précision de 6 chiffres après le point décimal. Mais si nous stockons un grand nombre de l’ordre de 10 ^ 30, nous n’aurons pas 6 chiffres après le point décimal. Alors, est-il exact de dire que les flotteurs ont une précision de 6 chiffres après le point décimal?

“6 chiffres après la virgule décimale” n’a pas valeur, et votre exemple en est une bonne démonstration.

Ceci est une spécification exacte du type de données float .

La précision du float est de 24 bits. Il y a 23 bits désignant la fraction après le point binary, plus un “bit de début implicite”, selon la source en ligne. Cela donne 24 bits significatifs au total.

Par conséquent, en chiffres décimaux, cela correspond approximativement à:

24 * log (2) / log (10) = 7,22

On dirait que vous vous posez des questions sur la précision des décimales (chiffres après le séparateur), alors que les chiffres significatifs (nombre total de chiffres sans les zéros au début et à la fin) constituent une meilleure façon de décrire la précision des nombres.

Vous avez raison de dire que le nombre de chiffres après la virgule décimale changera lorsque le nombre est grand – mais si nous parlons de précision, le nombre de chiffres significatifs ne changera pas lorsque le nombre sera plus grand. Cependant, la réponse n’est pas simple pour les nombres décimaux:


De nos jours, la plupart des systèmes utilisent le format de virgule flottante IEE pour représenter les nombres en C. Toutefois, si vous utilisez une fonction inhabituelle, cela vaut la peine de la vérifier. Les numéros de float IEE simple précision sont composés de trois parties:

  • Le bit de signe (ce nombre est-il positif ou négatif)
  • L’exposant (généralement aussi signé)
  • La fraction (le nombre avant l’exposant est appliqué)

Comme on pouvait s’y attendre, tout cela est stocké en binary.


Combien de chiffres significatifs?

Si vous utilisez des nombres IEE-754, “combien de chiffres significatifs” n’est probablement pas un moyen facile d’y penser, car la précision est mesurée en chiffres significatifs binarys plutôt qu’en nombres décimaux . float s ne possède que 23 bits d’exactitude pour la partie fraction, mais comme il existe un premier bit implicite (à moins que la partie fraction ne soit composée de zéros, ce qui indique une valeur finale de 1), la précision est de 24 bits.

Cela signifie qu’il y a 24 chiffres binarys significatifs , ce qui ne se traduit pas par un nombre exact de chiffres significatifs décimaux. Vous pouvez utiliser la formule 24 * log (2) / log (10) pour déterminer s’il existe 7,225 chiffres de précision décimale, ce qui n’est pas une très bonne réponse à votre question, car il existe 24 chiffres binarys significatifs dont avoir 6 chiffres décimaux significatifs.

Ainsi, les nombres à virgule flottante simple précision ont 6 à 9 chiffres décimaux significatifs de précision , en fonction du nombre.

Il est intéressant de noter que vous pouvez également utiliser cette précision pour calculer le plus grand entier consécutif (à partir de zéro) que vous pouvez représenter avec succès dans un flottant simple précision. Il est 2 ^ 24, ou 16 777 216. Vous pouvez stocker exactement des entiers plus grands, mais uniquement s’ils peuvent être représentés sous 24 chiffres binarys significatifs.


Autre astuce: La taille limitée du composant fraction est la même chose qui cause ceci en Javascript:

 > console.log(9999999999999999); 10000000000000000 

Les nombres Javascript sont toujours représentés par des flottants à double précision, qui ont une précision de 53 bits. Cela signifie entre 2 ^ 53 et 2 ^ 54, seuls les nombres pairs peuvent être représentés, car le dernier bit d’un nombre impair est perdu.

La précision des nombres en virgule flottante doit être mesurée en chiffres binarys et non en chiffres décimaux . En effet, les ordinateurs fonctionnent sur des nombres binarys et une fraction binary ne peut se rapprocher que d’une fraction décimale.

Les juristes spécialistes des langues diront que la largeur exacte d’un float n’est pas spécifiée par la norme C et dépend donc de la mise en œuvre, mais sur toute plate-forme, vous rencontrerez probablement un float C signifiant un nombre simple précision IEEE754 .

IEEE754 spécifie qu’un nombre à virgule flottante est en notation scientifique : (-1) s × 2 e × m
s est large d’un bit, e large de huit bits et m large de vingt-trois bits. Mathématiquement, m a une largeur de 24 bits car il est toujours supposé que le bit le plus haut est 1.

Ainsi, le nombre maximal de chiffres décimaux pouvant être approximés avec cette représentation est le suivant: log 10 (2 24 ) = 7,22 . Cela correspond approximativement à sept chiffres décimaux significatifs et à un exposant compris entre 2 126 et 2 127 .

Notez que l’exposant est mesuré séparément. C’est exactement comme si vous utilisiez une notation scientifique ordinaire, comme par exemple “Une personne pèse 72,3 kg = 7,23 × 10 4 grammes”. Notez qu’il y a trois chiffres significatifs ici, ce qui signifie que le nombre n’est précis qu’à 100 grammes près. Mais il y a aussi un exposant qui est un nombre totalement différent. Vous pouvez avoir un très grand exposant avec très peu de chiffres significatifs, comme “le soleil pèse 1,99 × 10 33 grammes”. Grand nombre, peu de chiffres.

En bref, un flotteur peut stocker environ 7 à 8 chiffres décimaux significatifs . Laissez-moi illustrer ceci avec un exemple:

 1234567001.00 ^ +---------------- this information is lost .01234567001 ^ +-------------- this information is lost 

Fondamentalement, le flotteur stocke deux valeurs: 1234567 et la position du point décimal.

Maintenant, ceci est un exemple simplifié. Les flotteurs stockent des valeurs binarys au lieu de valeurs décimales. Un float IEEE 754 32 bits peut contenir 23 “bits significatifs” (plus le premier, toujours considéré comme 1), ce qui correspond à environ 7 à 8 chiffres décimaux.

  1234567001.00 (dec) = 1001001100101011111111101011001.00 (bin) gets rounded to 1001001100101011111111110000000.00 = | 23 bits | 1234567040.00 (dec) 

Et c’est exactement ce que C produit:

 void main() { float a = 1234567001; printf("%f", a); // outputs 1234567040 }