web-dev-qa-db-fra.com

Double précision - décimales

D'après ce que j'ai lu, une valeur de type de données double a une précision approximative de 15 décimales. Cependant, lorsque j'utilise un nombre dont la représentation décimale se répète, telle que 1.0/7.0, je constate que la variable contient la valeur de 0.14285714285714285 - ce qui représente 17 places (via le débogueur).

Je voudrais savoir pourquoi il est représenté sous forme de 17 places en interne et pourquoi une précision de 15 est toujours écrite à environ 15?

36
nf313743

Un double IEEE a 53 bits significatifs (c'est la valeur de DBL_MANT_Dig Dans <cfloat>). Soit environ 15,95 chiffres décimaux (log10 (253)); l'implémentation fixe DBL_Dig à 15 et non 16, car elle doit être arrondie. Vous avez donc presque un chiffre décimal supplémentaire de précision (au-delà de ce que implique DBL_Dig==15) À cause de cela.

La fonction nextafter() calcule le nombre représentable le plus proche d'un nombre donné; il peut être utilisé pour montrer à quel point un nombre donné est précis.

Ce programme:

#include <cstdio>
#include <cfloat>
#include <cmath>

int main() {
    double x = 1.0/7.0;
    printf("FLT_RADIX = %d\n", FLT_RADIX);
    printf("DBL_Dig = %d\n", DBL_Dig);
    printf("DBL_MANT_Dig = %d\n", DBL_MANT_Dig);
    printf("%.17g\n%.17g\n%.17g\n", nextafter(x, 0.0), x, nextafter(x, 1.0));
}

me donne cette sortie sur mon système:

FLT_RADIX = 2
DBL_Dig = 15
DBL_MANT_Dig = 53
0.14285714285714282
0.14285714285714285
0.14285714285714288

(Vous pouvez remplacer %.17g Par, disons, %.64g Pour voir plus de chiffres, mais aucun d'entre eux n'est significatif.)

Comme vous pouvez le constater, le dernier chiffre décimal affiché change de 3 à chaque valeur consécutive. Le fait que le dernier chiffre affiché de 1.0/7.0 (5) Arrive à correspondre à la valeur mathématique est en grande partie une coïncidence; c'était une chance. Et le chiffre arrondi correct est 6, Pas 5. Remplacer 1.0/7.0 Par 1.0/3.0 Donne cette sortie:

FLT_RADIX = 2
DBL_Dig = 15
DBL_MANT_Dig = 53
0.33333333333333326
0.33333333333333331
0.33333333333333337

qui montre environ 16 chiffres décimaux de précision, comme on peut s'y attendre.

35
Keith Thompson

Il s’agit en fait de 53 places binaires, ce qui correspond à 15 décimales stables, ce qui signifie que si vous arrondissez un début avec un nombre à 15 décimales, convertissez-le en double, puis autour du double Retournez à 15 décimales pour obtenir le même nombre. Pour représenter uniquement un double, vous avez besoin de 17 décimales (ce qui signifie que pour chaque nombre comportant 17 décimales, il existe un unique plus proche double), raison pour laquelle 17 emplacements sont affichés, mais pas tous les 17. Les nombres décimaux correspondent à différentes valeurs de double (comme dans les exemples des autres réponses).

15
trutheality

La représentation décimale des nombres en virgule flottante est un peu étrange. Si vous avez un nombre avec 15 décimales et le convertissez en double, puis imprimez-le avec exactement 15 décimales, vous devriez obtenir le même nombre. Par contre, si vous imprimez un double arbitraire avec 15 décimales et que vous le reconvertissez en double, vous n'obtiendrez pas nécessairement la même valeur - vous avez besoin de 17 décimales pour cela. Et ni 15 ni 17 décimales ne suffisent pour afficher avec précision l'équivalent décimal exact d'un double arbitraire. En général, vous avez besoin de plus de 100 décimales pour le faire avec précision.

Voir la page Wikipedia pour la double précision et ceci article sur la précision en virgule flottante .

12
John Calsbeek

Un double contient exactement 53 chiffres binaires, ce qui correspond à environ 15,9545898 chiffres décimaux. Le débogueur peut afficher autant de chiffres qu'il le souhaite pour être plus précis que la valeur binaire . Ou cela pourrait prendre moins de chiffres et binaires, tels que 0.1 prend 1 chiffre en base 10, mais infini en base 2.

C'est étrange, je vais donc montrer un exemple extrême. Si nous créons une valeur en virgule flottante super simple qui ne contient que 3 chiffres binaires de précision, sans mantisse ni signe (la plage est donc 0-0,875), nous avons les options suivantes:

binary - decimal
000    - 0.000
001    - 0.125
010    - 0.250
011    - 0.375
100    - 0.500
101    - 0.625
110    - 0.750
111    - 0.875

Mais si vous faites les nombres, ce format n’est précis qu’à 0,903089987 chiffres décimaux. Pas même un chiffre n'est exact. Comme il est facile de voir, puisqu'il n'y a aucune valeur qui commence par 0.4?? ni 0.9??, et pourtant pour afficher la précision complète, nous avons besoin de 3 chiffres décimaux.

tl; dr: le débogueur vous indique la valeur de la variable à virgule flottante avec une précision arbitraire (19 chiffres dans votre cas), qui ne correspond pas nécessairement à la précision du format à virgule flottante (17 chiffres dans votre cas).

7
Mooing Duck

La virgule flottante IEEE 754 se fait en binaire. Il n'y a pas de conversion exacte d'un nombre donné de bits en un nombre donné de chiffres décimaux. 3 bits peuvent contenir des valeurs comprises entre 0 et 7, et 4 bits, des valeurs comprises entre 0 et 15. Une valeur comprise entre 0 et 9 prend approximativement 3,5 bits, mais ce n'est pas exact non plus.

Un nombre double précision IEEE 754 occupe 64 bits. De ce nombre, 52 bits sont dédiés au significande (le reste est un bit de signe et un exposant). Puisque le significande est (généralement) normalisé, il y a une impliciterd bit.

Maintenant, avec 53 bits et environ 3,5 bits par chiffre, une simple division nous donne 15,1429 chiffres de précision. Mais rappelez-vous que 3,5 bits par chiffre décimal n’est qu’une approximation, pas une réponse parfaitement précise.

Beaucoup de débogueurs (la plupart?) Regardent en réalité le contenu de tout le registre. Sur un x86, c'est en fait un nombre de 80 bits. L’unité de virgule flottante x86 est normalement ajustée pour effectuer des calculs avec une précision de 64 bits - mais en interne, elle utilise en réalité quelques "bits de garde", ce qui signifie qu’en interne, le calcul est effectué avec quelques bits de précision supplémentaires. il peut entourer le dernier correctement. Lorsque le débogueur examine l'intégralité du registre, il trouve généralement au moins un chiffre supplémentaire raisonnablement précis. Toutefois, étant donné que ce chiffre n'aura pas de bits de garde, il risque de ne pas être arrondi correctement.

4
Jerry Coffin

C'est parce qu'il est converti à partir d'une représentation binaire. Ce n’est pas parce qu’il a imprimé tous ces chiffres décimaux qu’il peut représenter toutes les valeurs décimales avec cette précision. Prenez, par exemple, ceci en Python:

>>> 0.14285714285714285
0.14285714285714285
>>> 0.14285714285714286
0.14285714285714285

Remarquez comment j'ai changé le dernier chiffre, mais il a quand même imprimé le même numéro.

3
spencercw

Dans la plupart des contextes où les valeurs double sont utilisées, les calculs comportent une certaine incertitude. La différence entre 1,33333333333333300 et 1,33333333333333399 peut être inférieure au montant de l'incertitude existant dans les calculs. Afficher la valeur de "2/3 + 2/3" en tant que "1.33333333333333" a plus de sens que de l’afficher en tant que "1.333333333333319", car ce dernier affichage implique un niveau de précision qui n'existe pas vraiment.

Dans le débogueur, cependant, il est important d’indiquer de manière unique la valeur détenue par une variable, y compris des bits de précision essentiellement sans signification. Il serait très déroutant qu'un débogueur affiche deux variables contenant la valeur "1.333333333333333" alors que l'une d'elles détenait réellement 1.333333333333319 et l'autre, 1.33333333333333294 (ce qui signifie que, même si elles semblaient identiques, elles n'étaient pas identiques). La précision supplémentaire affichée par le débogueur n’est pas susceptible de représenter un résultat de calcul correct, mais indique comment le code interprétera les valeurs détenues par les variables.

1
supercat