Menu sources

Le format IEEE

Le but de cette page n'est pas d'expliquer en profondeur le format IEEE mais de comprendre "l'erreur" qui se produit dans le source suivant :

Dim sng As Single 'Nombre réel simple précision
Dim dbl As Double 'Nombre réel double précision

Private Sub Form_Load()
    'on affecte 1.9 a la variable sng
    sng = 1.9
    'on affecte la valeur de sng a dbl
    dbl = sng
    'on Affiche dbl
    MsgBox dbl
End Sub

D'après vous quel nombre va apparaitre ?

1.9 ?

Si vous avez VB faites donc le test (il faut le voir pour le croire) avant de lire la suite plus bas





































Voici ce qui apparait a l'écran :

Incroyable non ?
Les sceptiques pourront ajouter une fonction de convertion :

dbl = CDbl(sng)

Cela ne change rien l'erreur est toujours là !

Paradoxe : en passant un nombre réel simple précision dans un nombre réel double précision une erreur de précision apparait ?!

Cette erreur est dans cet exemple tres visible, elle pourrait tout aussi bien se cacher lors d'une requête dans une base de donnée

Pour commencer plongeons nous dans MSDN :

Single, type de données

Les variables de type Single (à virgule flottante en simple précision) sont stockées sous la forme de nombres à virgule flottante de 32 bits (4 octets) IEEE dont la valeur est comprise entre -3,402823E38 et -1,401298E-45 pour les nombres négatifs et entre 1,401298E-45 et 3,402823E38 pour les positifs.
Le caractère de déclaration de type Single est le point d'exclamation (!).

Double, type de données

Les variables de type Double (à virgule flottante en double précision) sont stockées sous la forme de nombres à virgule flottante de 64 bits (8 octets) IEEE dont la valeur est comprise entre -1,79769313486232E308 et -4,94065645841247E-324 pour les nombres négatifs et entre 4,94065645841247E-324 et 1,79769313486232E308 pour les positifs.
Le caractère de déclaration de type Double est le signe #.

 

Cela ne nous avance pas trop, on nous confirme que le double est plus précis que le simple mais c'est tout.

Pour comprendre il faut aller plus loin à l'interieur même du format de stockage des nombres réels sur PC: le format IEEE.

Bref rappel sur la notation binaire

Les nombres entiers sont convertis en binaires pour etre stockés dans un ordinateur

Avec la calculatrice Windows (en affichage Scientifique) il est possible de faire des convertions rapidement
5 s'écrit en binaire 101 c'est a dire :
5
=1x2^2+0x2^1+1x2^0
5=1x4+0x2+1x1
5 =4+1

Pour les nombres entiers c'est très facile mais plus le nombre est grand et plus il faut de bits pour l'écrire
c'est pour ça que les nombres entiers sont limités à une plage de valeurs dans tous les ordinateurs.
Extrait de MSDN :
Les variables de type Long (entier long) sont stockées sous la forme de nombres signés de 32 bits (4 octets)
dont la valeur est comprise entre -2 147 483 648 et 2 147 483 647.

Pour aller plus loin sans utiliser trop de mémoire on utilise des nombres réels simple et double


Notation binaire pour les nombres réels

Pour stocker un nombre à "nombres à virgule flottante" x en binaire la maniere simple serait de codé deux entiers a et b
en écrivant x=a * 10^b
exemple 1.9=19* 10^-1

avec cette écriture pas d'erreur possible en simple ou en double précision.

En notation IEEE x n'est pas écrit a * 10^b
mais x = -1 ^ S x 2 ^ E x 1. F
S E et F etant trois nombres entiers
( F représente les decimales de 1.F )
( S vaut 0 ou 1 )
( E peut être négatif )

Le calcul pour obtenir S,E et F n'est pas détaillé ici (voir le programme)
Exemple:
6,5 n'est pas écrit 65 x 10^-1
Mais
-1^0 x 2^2 x 1.625

 

Le nombre stocké est donc SEF
La taille en bit de S, E et F et variable :

Pour les simples:
S : 1 bit
E : 8 bits
F : 23 bits
Au total 1+8+23=32 bits
On retrouve bien les 4 octets de précision

Pour les doubles:
S : 1 bit
E : 11 bits
F : 52 bits
Au total 1+11+52=64 bits
On retrouve les 8 octets de précison

Cette notation ne permet pas d'écrire précisement tout les nombres
F etant limité on obtient souvent une approximation de x !

L'ordinateur doit calculer cette approximation dès que l'on affecter une valeur dans un single ou dans un double

L'ordinateur doit recalculer le nombre (a chaque fois que l'on y accède) à partir de la notation stokée,
le calcul est plus précis lorsque le nombre se trouve dans un double.

Mais lorsque l'on affecte un single dans un double le calcul ne se refait pas, la notation single et placée directement dans le double
L'approximation etant moins bonne (et surtout inférieur a la précisions du double) l'erreur devient visible lorsque l'on recalcule la valeur

Exemple (cf les sources du programme joint)

Le nombre 1.9 est stocké :

dans un SINGLE sous la forme binaire : 0 01111111 11100110011001100110011

dans un DOUBLE sous la forme binaire : 0 00001111111 1110011001100110011001100110011001100110011001100110

dans un DOUBLE provenant d'un SINGLE : 0 00001111111 11100110011001100110011 00000000000000000000000000000

la difference est visible à la fin, le recalcul de la valeur du dernier DOUBLE ne donnera pas 1.9 mais 1,89999997615814

pour éviter cette erreur on peut passer par un STRING intermédiare cela impose le recalcul de la notation dans le double.
(Voir la fonction Cdouble du programme d'exemple)