(Terminer) Didacticiel pour comprendre les erreurs en virgule flottante IEEE

Exclusion de responsabilité du contenu obsolète de la base de connaissances

Cet article a été rédigé sur les produits pour lesquels Microsoft n’offre plus aucune prise en charge. Par conséquent, cet article est proposé « en l’état » et ne sera plus mis à jour.

Résumé

Les mathématiques à virgule flottante sont un sujet complexe qui déroute les nombreux programmeurs. Le didacticiel ci-dessous doit vous aider à reconnaître les situations de programmation dans lequel les erreurs en virgule flottante sont susceptibles de se produire et comment les éviter. Il doit vous permettent également de reconnaître les cas qui sont dues aux limitations intrinsèques mathématiques à virgule flottante au lieu des bogues du compilateur réel.

Plus d'informations

Systèmes de numération décimale et binaire

En règle générale, nous vous présenterons des choses en base 10. La base est complètement arbitraire. La seule raison que les personnes utilisent généralement 10 base veut que 10 doigts, qui ont fait les outils d’inventaire pratiques.


Le nombre de 532.25 au format décimal (base 10), les produits suivants :

   (5 * 10^2) + (3 * 10^1) + (2 * 10^0) + (2 * 10^-1) + (5 * 10^-2)
500 + 30 + 2 + 2/10 + 5/100
_________
= 532.25


Dans le système de numération binaire (base 2), chaque colonne représente une puissance de 2 au lieu de 10. Par exemple, le nombre 101.01 signifie ce qui suit :

   (1 * 2^2) + (0 * 2^1) + (1 * 2^0) + (0 * 2^-1) + (1 * 2^-2)
4 + 0 + 1 + 0 + 1/4
_________
= 5.25 Decimal


Comment les entiers sont représentés dans les PC

Dans la mesure où il n’existe pas de partie fractionnaire d’un nombre entier, sa représentation sous forme de machine est beaucoup plus simple qu’il l’est pour les valeurs à virgule flottante. Les entiers normales sur des ordinateurs personnels (PC) sont 2 octets (16 bits) long avec le bit le plus significatif qui indique le signe. Entiers longs sont de 4 octets. Les valeurs positives sont des nombres binaires simples. Par exemple :

    1 Decimal = 1 Binary
2 Decimal = 10 Binary
22 Decimal = 10110 Binary, etc.


Toutefois, les entiers négatifs sont représentés à l’aide du modèle de complément de deux. Pour obtenir la représentation des deux complément pour un nombre négatif, prendre la représentation binaire de la valeur absolue de retourner tous les bits et ajouter 1. Par exemple :

   4 Decimal = 0000 0000 0000 0100
1111 1111 1111 1011 Flip the Bits
-4 = 1111 1111 1111 1100 Add 1


Remarque -1 décimal = 1111 1111 1111 1111 en binaire, ce qui explique pourquoi Basic traite -1 comme une véritable logique (tous les bits = 1). Il s’agit d’une conséquence de n’ayant ne pas les opérateurs distincts pour les comparaisons logiques et au niveau du bit. En Basic, il est souvent pratique d’utiliser le fragment de code ci-dessous lorsque votre programme effectue beaucoup de comparaisons logiques. Cela facilite grandement la lisibilité.

   CONST TRUE = -1
CONST FALSE = NOT TRUE


Notez que l’ajout de n’importe quelle combinaison de deux complètent les nombres à l’aide d’ordinaire arithmétique binaire produit le résultat correct.

Complications à virgule flottante

Chaque nombre entier décimal peut être représentée exactement en un entier binaire ; Toutefois, cela n’est pas vrai pour les nombres fractionnaires. En fait, chaque numéro est en base 10 stratégies irrationnelles de réduction sera également stratégie irrationnelle de réduction dans un système dont la base est inférieure à 10.


Binaire, en particulier, des nombres fractionnaires seulement pouvant être représentée dans le formulaire p/q, où q est une puissance entière de 2, peuvent être exprimés exactement, avec un nombre limité de bits.


Les fractions décimales même courantes, comme le nombre décimal 0,0001, ne peut pas être représentées exactement en format binaire. (0,0001 est une fraction répétitive binaire avec une période de 104 bits !)


Ceci explique pourquoi un exemple simple, semblable à la suivante

   SUM = 0
FOR I% = 1 TO 10000
SUM = SUM + 0.0001
NEXT I%
PRINT SUM ' Theoretically = 1.0.


se 1.000054 d’impression en tant que sortie. La petite erreur de représentation de 0,0001 en base binaire est propagée dans la somme.


Pour la même raison, soyez très prudent lorsque vous effectuez des comparaisons sur des nombres réels. L’exemple suivant illustre une erreur de programmation courante :

   item1# = 69.82#
item2# = 69.20# + 0.62#
IF item1# = item2# then print "Equality!"


Cela ne s’IMPRIMERONT pas « D’égalité ! », car 69.82 ne peut pas être représentée exactement en format binaire, ce qui provoque la valeur qui résulte de l’assignation soit légèrement différent (en binaire) à la valeur qui est générée à partir de l’expression. Dans la pratique, vous devez toujours coder ces comparaisons de manière à permettre une tolérance de. Par exemple :

   IF (item1# < 69.83#) AND (item1# > 69.81#) then print "Equal"


Cela IMPRIMERA « Égal à ».

Nombres au Format IEEE

QuickBasic pour MS-DOS, version 3.0 a été livré avec une version MBF (Microsoft Binary Floating Point) et une version de l’IEEE (Institute of Electrical and Electronics Engineers) pour les ordinateurs disposant d’un coprocesseur. QuickBasic pour MS-DOS, versions 4.0 et ultérieures uniquement utilisent IEEE. Microsoft a choisi la norme IEEE pour représenter des valeurs à virgule flottante dans les versions actuelles de base pour les trois raisons principales suivantes :

  1. Pour permettre à Basic à utiliser les processeurs Intel mathématique, qui utilisent le format IEEE. Les processeurs 80 x 87 série Intel ne fonctionnent pas avec les numéros au Format binaire de Microsoft.
  2. Pour faire appel entre Basic, C, Pascal, FORTRAN et MASM beaucoup plus facile d’interlanguage. Dans le cas contraire, les routines de conversion devrait être utilisé pour envoyer les valeurs numériques d’une langue à l’autre.
  3. Pour garantir la cohérence. IEEE est la norme acceptée pour les compilateurs C et FORTRAN.
Voici une comparaison rapide des représentations IEEE et MBF pour un nombre de double précision :

               Sign Bits   Exponent Bits   Mantissa Bits
--------- ------------- -------------
IEEE 1 11 52 + 1 (Implied)
MBF 1 8 56


Pour plus d’informations sur les différences entre la représentation de virgule flottante IEEE et MBF, requête sur les mots suivants dans la Base de connaissances Microsoft :

   IEEE and floating and point and appnote


Notez que IEEE a plus de bits dédiés à l’exposant, qui permet de représenter un plus grand nombre de valeurs. MBF a plus de bits mantisse, ce qui lui permet d’être plus précis dans sa portée plus étroite.

Concepts généraux à virgule flottante

Il est très important de réaliser que n’importe quel système de virgule flottante binaire peut représenter uniquement un nombre fini de valeurs à virgule flottante dans la forme exacte. Toutes les autres valeurs doivent être estimées par la valeur représentable la plus proche. La norme IEEE spécifie la méthode d’arrondi des valeurs à la valeur représentable « plus proche ». QuickBasic pour MS-DOS prend en charge la norme et arrondit selon les règles de l’IEEE.


Gardez à l’esprit que les numéros qui peuvent être représentées dans IEEE sont répartis sur une plage très large. Vous pouvez vous imaginer sur un numéro de ligne. Il existe une haute densité de nombres représentable près 1.0 et -1.0 mais moins et moins, comme vous allez vers 0 ou un nombre infini.


L’objectif de la norme IEEE, qui est conçue pour les calculs d’ingénierie, est d’optimiser la précision (pour obtenir aussi près que possible au véritable numéro). Précision indique le nombre de chiffres que vous pouvez représenter. La norme IEEE essaie d’équilibrer le nombre de bits dédiés à l’exposant avec le nombre de bits utilisés pour la partie décimale du nombre, de conserver l’exactitude et la précision dans des limites acceptables.

Détails de l’IEEE

Les nombres à virgule flottante sont représentés sous la forme suivante, où [exposant] est l’exposant binaire :

   X =  Fraction * 2^(exponent - bias)


[Fraction] est la partie fractionnelle normalisée du nombre, normalisée car l’exposant est ajusté afin que le premier bit est toujours 1. De cette façon, il n’a pas à être stockés, et vous obtenez un bit de plus de précision. C’est pourquoi il existe un bit implicite. Vous pouvez considérer cela comme notation scientifique, dans laquelle vous manipulez l’exposant d’avoir un chiffre à gauche de la virgule décimale, sauf en binaire, vous pouvez toujours manipuler l’exposant afin que le premier bit soit un 1, dans la mesure où il n’y a seulement 1 et0.


[décalage] est la valeur de compensation utilisée pour éviter d’avoir à stocker les exposants négatifs.


L’écart pour les nombres en simple précision est 127 et 1023 (décimal) pour les nombres à double précision.


Les valeurs égales à tous des 0 et tous les 1 (binaire) sont réservés pour la représentation des cas spéciaux. Il existe autres cas spéciaux, qui indiquent les différentes conditions d’erreur.

Exemples de simple précision

2 = 1 * 2 ^ 1 = 0100 0000 0000 0000... hex de 0000 0000 0000 = 4000
Notez le bit de signe est zéro et l’exposant stocké est 128, ou 100 0000 0 en notation binaire, soit 127 plus 1. La mantisse stockée est (1.) 000 0000... 0000 0000, qui a un implicite 1 et binaire point principal, afin que la mantisse réelle est de 1.

-2 = -1 * 2 ^ 1 = 1100 0000 0000 0000... 0000 0000 = hex de 0000 C000
Identique à l’option + 2 sauf que le bit de signe est défini. Cela est vrai pour tous les nombres de virgule flottante au standard IEEE.

4 = 1 * 2 ^ 2 = 0100 0000 1000 0000... hex de 0000 0000 0000 = 4080
Même mantisse, exposant est incrémenté (valeur biaisée est 129, soit 100 0000 1 en notation binaire.

6 = 1,5 * 2 ^ 2 = 0100 0000 1100 0000... 0000 0000 = 40C 0 0000 hex.
Même exposant, la mantisse est supérieure de moitié--il est (1.) 100 0000... 0000 0000, c'est-à-dire, dans la mesure où il s’agit d’une fraction binaire, 1-1/2 (les valeurs de nombres fractionnaires sont 1/2, 1/4, 1/8, etc..).

1 = 1 * 2 ^ 0 = 0011 1111 1000 0000... Hex de 0000 0000 0000 = 3F80
Même exposant que d’autres puissances de 2, la mantisse est un de moins que 2 à 127, soit 011 1111 1 en binaire.

.75 = 1,5 * 2 ^ -1 = 0011 1111 0100 0000... Hex de 0000 0000 0000 = 3F40
L’exposant tronqué équivaut à 126, 011 1111 0 en représentation binaire et la mantisse correspond à (1.) 100 0000... 0000 0000, qui correspond à 1-1/2.

2,5 = 1,25 * 2 ^ 1 = 0100 0000 0010 0000... hex de 0000 0000 0000 = 4020
Exactement la même que 2 sauf que le bit qui représente 1/4 est défini dans la mantisse.

0,1 = 1,6 * 2 ^ -4 = 0011 1101 1100 1100... Hex de 1100 1101 = 3DCC CCCD
1/10 est une fraction itérative en binaire. La mantisse est juste en deçà de 1.6, et l’exposant tronqué indique que 1.6 doit être divisée par 16 (il s’agit de 011 1101 1 en binaire, soit 123 en décimal). L’exposant réel est 123-127 = - 4, ce qui signifie que le facteur par lequel multiplier est 2 ** -4 = 1/16. Notez que la mantisse stockée est arrondie dans le dernier bit. Il s’agit d’une tentative pour représenter le nombre non représentable aussi précisément que possible. (La raison pour laquelle ce 1/10 et 1/100 ne peuvent pas exactement représentable dans le fichier binaire est similaire à celle que 1/3 n’est pas exactement qui peut être représenté sous forme décimale.)

0 = 1,0 * 2 ^ -128 = tous les zéros--un cas spécial.

Autres erreurs en virgule flottante

Les erreurs courantes en virgule flottante sont les suivantes :

  1. Erreur d’arrondi


    Cette erreur se produit lorsque tous les octets dans un nombre binaire ne peut pas être utilisées dans un calcul.


    Exemple : Ajout de 0,0001 à 0.9900 (simple précision)


    Nombre décimal 0,0001 seront représentés en tant que :
    (1.) 10100011011011100010111 * 2^(-14+Bias) (13 0 s les meilleures binaire !)
    0.9900 sera représenté sous la forme :
    (1.)11111010111000010100011 * 2^(-1+Bias)
    Maintenant pour ajouter ces nombres, le décimal (binaire) doit être alignées. Pour cela, elles doivent être Unnormalized. Voici l’addition qui en résulte :
           .000000000000011010001101 * 2^0  <- Only 11 of 23 Bits retained
    +.111111010111000010100011 * 2^0
    ________________________________
    .111111010111011100110000 * 2^0


    Il s’agit une erreur d’arrondi, car certains ordinateurs arrondir lors du déplacement de l’addition. D’autres simplement à tronquer. Erreurs d’arrondi sont importants à prendre en compte chaque fois que vous ajoutez ou multiplication de deux valeurs très différentes.
  2. Deux en soustrayant les valeurs presque identiques
           .1235
    -.1234
    _____
    .0001


    Cela sera normalisée. Notez que bien que les numéros d’origine chaque avaient quatre chiffres significatifs, le résultat a un seul chiffre significatif.
  3. Dépassement de capacité et de dépassement de capacité négatif


    Cela se produit lorsque le résultat est trop grande ou trop petite pour être représentée par le type de données.
  4. Erreur de quantification


    Cela se produit avec les nombres qui ne peut pas être représentés dans la forme exacte par le standard en virgule flottante.
  5. Division par un très petit nombre


    Cela peut déclencher une erreur « division par zéro » ou peut produire des résultats incorrects, comme dans l’exemple suivant :
          A = 112000000
    B = 100000
    C = 0.0009
    X = A - B / C


    Dans QuickBasic pour MS-DOS, X maintenant a la valeur 888887, au lieu de la réponse correcte, 900000.
  6. Erreur de sortie


    Ce type d’erreur se produit lorsque les fonctions de sortie modifient les valeurs avec lequel ils travaillent.
Propriétés

ID d'article : 42980 - Dernière mise à jour : 27 janv. 2017 - Révision : 1

Commentaires