Soya/Python déformation
Soya/Python plein écran
Mathématiques/Arithmétique flottante
Principe.
Toute donnée contenue ou utilisée par un ordinateur est représentée par un nombre "fini" de "bits". Chaque bit pouvant prendre deux valeurs, une donnée sur N bits pourra prendre 2N valeurs. Par ailleurs, suivant les processeurs et les langages utilisés, les types de données disponibles ont couramment une taille "fixe", par exemple 32 bits, 64 bits ou plus, ce qui fait qu'ils peuvent prendre 232 valeurs, 264, etc. De ce fait, lorsqu'on essaye de travailler sur un ordinateur pour effectuer des calculs sur des nombres réels, on est limité par le fait qu'il n'est possible de représenter qu'une partie finie de formula_1. Cette discrétisation de formula_1 fait que le calcul numérique sur ordinateur est très différent du calcul mathématique qu'il est censé représenter.
Ainsi, les concepteurs de machines, comme de langages informatiques, doivent faire des choix dans la manière dont les nombres réels seront représentés et dans la manière dont ils seront manipulables. Ce livre montrera les problèmes qui se posent, par exemple pour gérer les situations où le résultat d'un calcul ne tombe pas exactement sur une des 2N valeurs, les problèmes liés aux infinis, aux opérations incorrectes (par ex. les divisions par zéro)... Les réponses à ces problèmes que trouvent les concepteurs de machines et de langages informatiques ont des impacts sur la manière dont un développeur pourra les utiliser pour créer des applications.
L'arithmétique des nombres réels sur ordinateur, dite "en virgule flottante", est un domaine souvent peu maîtrisé, deux attitudes courantes étant soit de faire des calculs sans se soucier de ces questions, soit (après avoir buté sur une de ces questions sans savoir pourquoi) de se méfier des calculs numériques et de les éviter autant que possible. En effet, tout calcul peut comporter des erreurs d'arrondi ; et ces erreurs peuvent se propager et induire des résultats très largement inexacts. L'objectif de ce livre est de montrer au lecteur que les calculs en virgule flottante ne sont en rien mystérieux, et que les résultats de calcul qui peuvent sembler étranges ou aléatoires au premier abord sont en fait déterministes.
Nombres flottants.
Tout nombre réel peut s'écrire sous la forme formula_3. Par exemple :
Cependant, chaque nombre peut s'écrire sous cette forme avec une infinité de couples formula_6. Cette notation ne devient unique que si le premier chiffre "significatif" (non zéro) est placé avant la virgule, les autres étant placés après. Cette notation est alors dite "scientifique". Par exemple :
Le principe n'est pas limité à la base 10, et peut se généraliser pour toute base. La base 2 est la plus utilisée en informatique, mais ce paragraphe sera valable pour toute base formula_9. Cette notation permet de représenter tout nombre réel non nul par un ensemble de trois valeurs :
Le cas du nombre zéro est particulier, car il peut être représenté par une mantisse nulle et un exposant quelconque. Pour l'instant, nous considèrerons qu'on peut choisir arbitrairement pour la valeur zéro une des représentations possibles dans le format considéré. La représentation précise sera étudiée plus tard, nous étudierons d'abord le cas général des nombres non nuls.
Comme précisé en introduction, la représentation des nombres flottants que l'on étudie ici a une taille fixe. On peut choisir pour le signe une représentation de taille fixe, par exemple avec un chiffre qui sera à 0 pour les nombres positifs et à 1 pour les nombres négatifs. Il ne reste donc plus qu'à choisir le nombre de chiffres à attribuer à la mantisse (la "précision", notée "p") et à l'exposant (noté "e"). Si on suppose que l'on travaille en base 10, avec une précision de formula_11 chiffres et un exposant pouvant varier entre formula_12 et formula_13, nous pouvons représenter par exemple les nombres suivants :
On remarque que le plus petit nombre positif représentable dans ce format est 0,01, et le plus grand 999,9. On voit déjà une limite de l'arithmétique flottante : on ne peut représenter que des nombres dont la valeur absolue est entre formula_17 et formula_18, où formula_19 est le plus grand chiffre (9 en décimal, 1 en binaire). Par ailleurs, si on manipule ces chiffres pour essayer de mieux « voir » comment ils sont (le lecteur est par ailleurs vivement encouragé à faire ou refaire ces manipulations lui-même), on peut remarquer qu'ils ne sont pas uniformément répartis entre ces deux bornes :
Ainsi, entre formula_17 et formula_27, les nombres représentés de cette manière sont espacés régulièrement de formula_28, soit formula_29 dans cet exemple, puis, entre formula_27 et formula_31, l'écart vaut formula_32, soit formula_33, pour aller jusqu'à formula_34 entre formula_35 et formula_18. Ainsi, avoir une mantisse de taille fixe fait que les nombres flottants ne peuvent être répartis uniformément.
En notation binaire, qui est la plus utilisée par les ordinateurs, la mantisse commence toujours par le chiffre 1, sauf pour zéro. Ce chiffre peut donc être omis de la représentation en machine, ce qui permet de gagner un bit (mais ce qui laisse toujours en suspend le choix de la représentation du nombre zéro). 
Premiers calculs... et premières questions.
Pour mieux comprendre l'effet de ces deux limitations (bornes et répartition des nombres flottants), on peut essayer de faire des calculs simples, comme des additions. Si on essaye d'additionner les deux plus petits nombres flottants représentables dans le format que nous avons choisi précédemment, on obtiendra :
formula_37
Le résultat est représentable exactement dans le format considéré. Essayons maintenant d'additionner ce nombre et 50,75 :
formula_38
On constate que ce résultat ne peut être représenté exactement avec la précision fixée à 4 chiffres... Ainsi, même une simple addition peut ne pas être si évidente ! En pratique, le résultat devant être dans une précision à 4 chiffres, il faut l'arrondir. Ici, la valeur formula_39 est la plus proche, et pourraît être celle utilisée. Cependant, dans le cas suivant, le choix est moins simple: 
formula_40
Ici, comment arrondir ? Doit-on choisir formula_41 ou formula_42 ? Et si le résultat avait été négatif ? Et dans le cas suivant :
formula_43
Doit-on choisir formula_44, ou... ou quelle valeur, d'ailleurs ?
La question de l'arrondi a de multiples réponses. L'arrondi au plus proche laisse le choix pour le cas « 0,5 », qui peut être arrondi au supérieur ou à l'inférieur. Mais des arrondis « vers 0 » ou « vers l'infini » sont aussi parfois utilisés. Comme nous venons de le voir dans le dernier exemple, le choix de l'arrondi peut, dans les cas limites, faire qu'un résultat soit représentable ou non dans le format considéré.
Considérons maintenant la soustraction suivante :
formula_45
Là encore, le résultat tombe juste. Mais ce n'est pas toujours le cas...
formula_46
Cette fois-ci, le résultat tombe entre 0 et formula_17, on ne peut donc le représenter de manière normalisée. On peut alors soit arrondir à formula_17, et l'erreur relative serait assez grande (formula_49 au lieu de formula_50, l'erreur est d'un facteur 1000 !), soit à zéro. Mais, dans ce dernier cas, la différence de deux nombres exactement représentables dans ce format numérique serait nulle, et l'équivalence formula_51 serait fausse !
Nous venons de voir qu'une représentation en virgule flottante des nombres réels posait un certain nombre de problèmes, notamment en terme d'arrondi des résultats et pour les valeurs trop grandes ou trop petites, et ce même sur des opérations simples. Nous avons pris l'addition et la soustraction comme premiers exemples, mais la multiplication, la division... sont soumises aux mêmes problèmes. Les chapitres suivants montreront comment chacun de ces problèmes peut trouver une solution, et comment un développeur peut les utiliser pour concevoir une application robuste.