Introduction à l’arithmétique flottante

Comprendre et limiter les erreurs inhérentes au calcul numérique

a marqué ce sujet comme résolu.

Bonjour à tous,

J’ai commencé (il y a 1 jour, 19 heures) la rédaction d’un tutoriel dont l’intitulé est Effectuer des calculs numériques précis.

J’aimerais obtenir un maximum de retour sur celui-ci, sur le fond ainsi que sur la forme, afin de proposer en validation un texte de qualité.

Si vous êtes intéressé, cliquez ci-dessous

Merci d’avance pour votre aide


Je continue dans ma lancée avec un tutoriel sur les erreurs de calcul causées par la représentation machine des réels. L’idée est d’apprendre à mes lecteurs les limitations du calcul avec les flottants, savoir quand on peut y être confronté, et connaître quelques parades.

Le public visé est à peu près tout ceux qui auraient à faire des simulations numériques, et qui sont intéressés par la précision des résultats. Dans l’esprit, ce serait une extension de mon tutoriel sur la méthode d’Euler.

Ce que je recherche actuellement :

  • un avis sur le positionnement du tuto (est-ce que c’est un créneau avec un réel public ?). Ce n’est pas un cours sur IEEE 754, mais vraiment un cours sur les écueils du calcul avec les flottants).
  • un avis sur la première partie, car j’ai l’impression que je n’explique pas assez pour quelqu’un qui ne connaît pas, et en même temps, je n’ai pas envie de mettre tous les détails (ce n’est pas un cours sur IEEE 754)
  • éventuellement un retour sur les notes que j’ai inscrites dans les deux autres parties, pour voir si ce n’est pas trop ambitieux pour un mini-tuto.
  • et bien sûr, un retour sur des erreurs factuelles ou des explications absconses. :)

Au plaisir de vous lire,

Aabu

+1 -0

Merci pour le tutoriel ! Un début de remarques :

Introduction

Pourtant, votre ordinateur vous dira le contraire.

Ici, c'est plus précisément Python. Il me semble intéressant de l'indiquer, vu qu'on pourrait avoir d'autres interpréteurs qui fourniraient la bonne réponse. Autrement dit, tu pourrais illustrer tes propos avec Python, puis dire que ça se généralise à tout programme.

Pour suivre au mieux ce tutoriel, il est conseillé :

Il n'y a pas de pré-requis ? ^^

+0 -0

Lu'!

Je te conseille de parler de cet exemple, c'est une illustration qui a le don de choquer.

Voici un petit algorithme proposé par Kahan et Muller :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <iostream>

typedef float discret;

int main(){
  discret x0 = 11/2.0;
  discret x1 = 61/11.0;

  for (int i = 0 ; i < 100 ; i++){
    discret x2 = 111 - (1130 - 3000/x0) / x1;
    x0 = x1;
    x1 = x2;
    std::cout << x2 << std::endl; 
  }
}

Cet algorithme est assez amusant. En effet, si l'on calcule la valeur vers laquelle elle converge avec des réels, on obtient 6. Avec float ou double sur une machine, cela converge vers 100.

Représentation des réels en machine

Développements binaires finis et infinis

Cette forme mathématiquement exacte

Qu'entends-tu par là ? Qu'on ne fait pas d'approximation, contrairement aux représentations utilisées en machine ?

que nous aborderons dans la section suivante.

Le terme "section" n'est pas très clair, d'autant plus qu'avec la ZEP-12, il désignera ce qu'on appelle actuellement un extrait. J'imagine que tu désignes la partie sur la représentation des réels par les nombres à virgule flottante ?

En base 2, les (en) et les (fn) sont des bits et valent 0 ou 1.

Je chipote, mais vu que tu parles du développement binaire, on est déjà en base 2.

les (en) et les (fn) sont des bits

Nop, ce sont des suites. :P

Par exemple, le nombre 3,5 en décimal s'écrit en binaire

Il me semble intéressant de donner un (second ?) exemple avec une partie fractionnaire n'étant pas sous la forme d'une puissance de 2.

Par exemple, la fraction $\frac 13$ à un développement binaire infini.

Pourrais-tu expliquer pourquoi ?

Le choix de la base 2 n'est pas anodin, parce que certains nombres avec un nombre fini de décimales en base 10, en ont un nombre infini en base 2.

Un nombre au développement décimal infini en base 10 en aura-t-il nécessairement un infini en base 2 ?

Représentation des réels par les nombres à virgule flottante

ainsi qu'un nombre constant de chiffres significatifs

En quoi est-ce un avantage ? :)

La mantisse à une partie entière qui vaut 1

Veux-tu dire par là que la mantisse est de la forme $1.abcde...$ ? Je ne sais pas pourquoi, mais je m'attendais à un nombre entier.

L'exposant est un entier compris entre entre −1023 et +1024.

Comment sont codés les nombres négatifs ?

Dans ce cas, la partie entière est toujours 1

Il est bien question ici de la partie entière de la mantisse ? Le cas échéant, il faudrait peut-être revoir "La mantisse à une partie entière qui vaut 1, car sinon ce n'est plus une véritable notation scientifique.", qui laisse entendre que c'est toujours le cas.

1 10000000000 0000000000000000000000000000000000000000000000000000

Peut-être pourrais-tu utiliser la commande \underbrace présentée ici pour décrire un peu chaque partie ? Notamment, pour l'exposant, je m'attendais à $00000000010$, soit $2$ en binaire.

D'ailleurs, je ne comprends pas non plus la suite que tu donnes plus bas.

C'est une forme qui permet de représenter des nombres plus petit, mais avec moins de bits significatifs.

Je n'avais pas compris cette phrase avant de voir l'exemple. Mais je ne vois pas trop comment la reformuler.

Si l'exposant -1023 suppose que la partie entière est nulle, comme je représente $3 \times 2^{-1023}$ ?

Merci ! :)

+0 -0

Cette forme mathématiquement exacte

Qu'entends-tu par là ? Qu'on ne fait pas d'approximation, contrairement aux représentations utilisées en machine ?

Oui. Les développements décimaux, c'est exact. Mais la suite est éventuellement infinie, et c'est ce qui empêche de la stocker en entier.

que nous aborderons dans la section suivante.

Le terme "section" n'est pas très clair, d'autant plus qu'avec la ZEP-12, il désignera ce qu'on appelle actuellement un extrait. J'imagine que tu désignes la partie sur la représentation des réels par les nombres à virgule flottante ?

En fait, le mot "extrait" n'est pas très bien choisi, parce que personne ne désigne par extrait une division d'un texte. Tu peux dire partie, chapitre, section, sous-section, paragraphe etc, mais extrait ça ne veut rien dire en vérité. Et j'essaie de m'y prendre comme je peux.

Par exemple, le nombre 3,5 en décimal s'écrit en binaire

Il me semble intéressant de donner un (second ?) exemple avec une partie fractionnaire n'étant pas sous la forme d'une puissance de 2.

Tu crois vraiment que ça apporte quelque chose ? Parce que le but du début, c'est de dire "Les réels n'ont pas tous un développement binaire fini, et en particulier il peut être infini même si le développement décimal l'est.".

Par exemple, la fraction $\frac 13$ à un développement binaire infini.

Pourrais-tu expliquer pourquoi ?

Voir ci-dessous.

Le choix de la base 2 n'est pas anodin, parce que certains nombres avec un nombre fini de décimales en base 10, en ont un nombre infini en base 2.

Un nombre au développement décimal infini en base 10 en aura-t-il nécessairement un infini en base 2 ?

Oui, des élements de réponse ici et . En résumé, comme 2x5 = 10, fini en binaire => fini en décimal, et infini en décimal => infini en binaire. On a vu que que fini en décimal => éventuellement infini en binaire, et infini en binaire => éventuellement fini en décimal.

Représentation des réels par les nombres à virgule flottante

ainsi qu'un nombre constant de chiffres significatifs

En quoi est-ce un avantage ? :)

L'avantage c'est de ne pas avoir une précision relative qui dépend trop de la magnitude, bien que la magnitude ait une grande amplitude. Par exemple, avec les nombres à virgule fixe, plus ton nombre est petit, plus sa précision relative est faible (tu perds des chiffres après le premier chiffre non nul).

L'exposant est un entier compris entre entre −1023 et +1024.

Comment sont codés les nombres négatifs ?

C'est codé comme des entiers non signés avec un décalage. pour J'ai pas vraiment envie de rentrer dans ce détail… Je pense que je vais simplifier la présentation technique. Ce n'est pas vraiment l'objectif que de présenter en détail la norme.

Du coup, il y a du travail sur cette partie. :D

Si l'exposant -1023 suppose que la partie entière est nulle, comme je représente $3 \times 2^{-1023}$ ?

Vayel

Le truc, c'est que ça ne marche pas dans les deux sens. C'est quand ton nombre est petit que le flottant correspondant aura implicitement une partie entière nulle. Quand ton nombre à un exposant de -1023, ça ne veut pas dire que ça partie entière est nulle. Là, ton nombre, c'est $11_2 \times 2^{-1023} = 1.1_2 \times 2^{-1022}$, du coup, il est normalisé.

ainsi qu'un nombre constant de chiffres significatifs

En quoi est-ce un avantage ? :)

C'est surtout faux. Que la precision maximale d'un flottant soit de 1015 a 1016 ne veut pas dire que la valeur est significative a 1015 ou 1016.

Höd

Tu fais allusion au sens physique de significatif ? J'avais envie de dire "on a un nombre maximal constant (sauf dénormalisation) de chiffres non nuls stockables". Ça correspond à la précision… mais j'avais envie de donner un sens plus physique à la chose, à tort si je comprends bien. :D

+0 -0

En fait, le mot "extrait" n'est pas très bien choisi, parce que personne ne désigne par extrait une division d'un texte. Tu peux dire partie, chapitre, section, sous-section, paragraphe etc, mais extrait ça ne veut rien dire en vérité. Et j'essaie de m'y prendre comme je peux.

On est d'accord que "section suivante" désigne le passage "Représentation des réels par les nombres à virgule flottante", et non le second extrait ?

Tu crois vraiment que ça apporte quelque chose ?

Je n'ai pas réfléchi très longtemps à la question, mais là, je ne vois pas comment écrire $3.8$ en binaire.

Là, ton nombre, c'est $11_2×2{−1023}=1.1_2×2{−1022}$, du coup, il est normalisé.

Ah oui, je n'avais pas pensé qu'il fallait convertir en base 2 avant d'écrire sous forme scientifique. Mais du coup, comme est représenté $1_{10} \times 2^{-1023} = 1_{2} \times 2^{-1023}$ ? On ne peut pas dire que c'est $0.1 \times 2^{-1023}$.

+0 -0

Tu fais allusion au sens physique de significatif ? J'avais envie de dire "on a un nombre maximal constant (sauf dénormalisation) de chiffres non nuls stockables". Ça correspond à la précision… mais j'avais envie de donner un sens plus physique à la chose, à tort si je comprends bien. :D

Aabu

C'est pas du tout physique mais bien numérique. L'opération d'affectation fait perdre nécessairement de la précision au delà de $10^{-15}$, on est d'accord. Si tu te contentes de cela, pas de soucis pour dire qu'effectivement le nombre de chiffre significatif est également la précision de la représentation.

Sauf que, et tu en parles (ou a prévu d'en parler), les erreurs se propagent, que ce soit par la multiplication de flottants ou l'addition de flottants.

Au final, après une succession de $n$ opérations, le nombre de chiffres significatifs du résultat obtenu est nécessairement égal ou inférieur à cette précision. Parfois très inférieur. C'est justement le jeu de du calcul numérique que de limiter la propagation de ces erreurs pour obtenir un résultat qui ait le nombre de chiffres significatifs le plus proche de la précision autorisée par le représentation choisie.

Par exemple, si tu prends l'exemple donné plus haut par Ksass`Peuk, même si il est possible de représenter 100 en flottant avec une précision de $10^{-15}$, le nombre de chiffres significatifs de ce résultat est 0, le résultat attendu étant 6 !

A ma connaissance, la seule méthode capable de déterminer efficacement le nombre de chiffres significatifs d'un résultat numérique est CESTAC (Contrôle et Estimation STochastique des Arrondis de Calculs), qui comme son nom l'indique est une méthode probabiliste. Je compte écrire un article dessus, comme dit dans mon premier message. Rapidemment, pour l'idée, la méthode consiste pour chaque opération à calculer l'opération un certain nombre de fois (en pratique, pour des raisons probabiliste on utilise 3 répétitions) avec un mode d'arrondi sélectionné selon une distribution de probabilité uniforme. On peut ensuite appliquer un test de Student et obtenir un intervalle de confiance pour le nombre de chiffres significatifs de l'opération.

L'implémentation la plus connue est celle de CADNA en Fortran. La méthode a été développée en France, au LIP6, et est utilisé pour la simulation de systèmes critiques, notamment dans l'aéronautique (à ma connaissance massivement utilisée par Dassault).

+0 -0

@ Höd : ok, c'est clair maintenant.

Mais du coup, comme est représenté $1_{10} \times 2^{-1023} = 1_{2} \times 2^{-1023}$ ? On ne peut pas dire que c'est $0.1 \times 2^{-1023}$.

Vayel

Arf, tu m'as fait prendre conscience de quelque chose que j'avais mal compris. Pour qu'il y ait continuité entre normalisés et dénormalisés, les normalisés sont de la forme $0.abcde... \times 2^{-1022}$, le -1023 n'apparaît pas dans le calcul. Si j'ai bien compris, ton exemple $1 \times 2^{-1023} = 0.1 \times 2^{-1022}$, est donc représenté par le dénormalisé avec une mantisse "1000…0".

Du coup, la version actuelle raconte des conneries. J'ai mal à mon ego. :D

Bonjour à tous !

La beta du tutoriel a été mise à jour.

Merci pour vos relectures


Refontes en cours.

J'ai mis à jour "Développements binaires finis et infinis", qui n'a presque plus rien en commun avec avant. Qu'en pensez-vous ? Il y des incohérences dans quelques phrases à cause de la réécriture, ne faits pas trop attention. Par contre, critiquez vertement la progression logique du bouzin !

+0 -0

C'est beaucoup mieux. :)

Si vous êtes à l'aise avec la numération en base 2, vous savez que tout entier N peut s'écrire sous la forme d'une suite de bits finie anan−1…a0. Pour obtenir la valeur en décimal, il suffit alors d'effectuer le calcul suivant.

Pourquoi parles-tu de cela, sachant que tu indiques la maîtrise du binaire dans les pré-requis ?

On démontre aussi qu'un développement binaire fini implique un développement décimal fini

Ouep, c'est la contraposée de la proposition précédente. :-°

Par exemple la fraction 1/3 n'est pas représentable exactement par une suite finie de bits […] Un des exemples les plus simples est 1/10.

Comment trouve-t-on ces deux développements binaires ?

en conséquence, on ne peut pas représenter tous les réels de manière exacte.

En machine. ^^

+0 -0

Représentation des réels en machine

Représentation des réels par les nombres à virgule flottante

permettre la représentation de très petits et très grands nombres avec une précision relative constante

Sans avoir lu la suite, je ne comprends pas ce que tu entends pas "précision relative".

La notation scientifique d'un nombre binaire est de la forme suivante.

Peut-être serait-il intéressant de rappeler ce que fait la multiplication par $2^k$ (décalage de $k$ bits vers la gauche) ? Mais je comprendrais aussi que tu inclues cela dans les pré-requis.

et qui vaut donc entre 1 et 2

Peut-être pourrais-tu utiliser un intervalle ? Ca permettrait d'exclure 2 facilement (et d'éviter la répétition de "vaut" :P).

Le bit de signe peut prendre deux valeurs, ce qui est suffisant pour les deux signes possibles, et rend la représentation symétrique par rapport à zéro.

Là, je me suis demandé : mais au fait, comment représente-t-on 0 ?

ce qui signifie qu'on pourra stocker toujours le même nombre de décimales, quelque soit la valeur du nombre !

Je ne comprends pas cela.

Pour avoir plus petit encore, il vaut considérer une partie entière nulle, et c'est ce qu'indique la valeur spéciale -1023. Dans ce cas, le nombre est dit dénormalisé, et s'écrit sous la forme :

Il me semble intéressant de donner un exemple. De prime abord, je me suis dit que c'était bêtement $1.bc\ldots \times 2^{-1023}$, avant de me rendre compte que $a$ (et les autres) pouvait être nul.

pour autoriser des nombres plus petits encore, on fait appel aux nombres dénormalisés, au détriment de la précision.

Pourquoi au détriment de la précision ?

Nous allons maintenant nous intéresser plus en détails aux limitations des flottants, que nous avons déjà effleuré (valeur extrêmes des exposants, taille de la mantisse, etc.).

Je ne comprends pas trop le "valeur extrêmes des exposants". Désignes-tu par là les cas spéciaux 1024 et -1023, ou le fait qu'on est limité au niveau de l'ordre de grandeur ?


C'est bien plus clair. Un point me chifonne toutefois : tu parles de réels, mais j'imagine que tu exclus les entiers (i.e. qu'on ne va pas représenter 3, 4, etc. sous forme de flottants) ?

Merci.

+0 -0

Ah d'accord. Merci. ^^

Mais pourquoi 4,0000000000000001 et pas 4,0000000000000000 ? 4 peut bien s'écrire $1.00000\ldots \times 2^2$ et donc avoir une mantisse nulle, non ?

@Aabu : il pourrait être intéressant de proposer des exercices. ^^

+0 -0

Bonjour à tous !

La beta du tutoriel a été mise à jour.

Merci pour vos relectures


Encore une refonte de la deuxième moitié de la première partie… J'ai pris en compte quelques remarques. Mon processus de rédaction est un peu laborieux, mais je ne perd pas espoir !

Merci beaucoup à ceux qui relisent (en particulier Vayel, avec de bonnes remarques qui font réfléchir :) ).

+0 -0

L'organisation des propos me parait bien mieux. Quelques remarques :

Représentation des réels en machine

De la nécessité des approximations

On peut voir qu'une approximation est faite en affichant suffisamment de décimales avec Python :

Il me semble intéressant d'insister sur cette notion d'approximation. Dans cette vidéo, le cheminement suivant est clairement expliqué :

  • On a un nombre au développement binaire infini (tu le dis)
  • Mais on ne peut stocker un tel développement (tu le dis)
  • Donc on ne garde qu'un nombre fini de bits (tu le dis)
  • Et cette suite obtenue désigne un autre nombre (tu pourrais donner un exemple, en fixant abitrairement un nombre de bits puis appliquant cette limitation au développement de 1/10)
  • Autre nombre qu'on considère égal à notre nombre de départ (donc 1/10 considéré comme égal à TODO)

Représentation des réels par les nombres à virgule flottante

Les flottants sont des nombres écrits sous la forme suivante :

Pourquoi ne plus mentionner l'expression "notation scientifique en base 2" ?

la mantisse m, un nombre tel que 0≤x<2

Pourquoi $x$ ? :P

Avec la valeur que prend ce champs, il est possible de déterminer la valeur de la partie entière de la mantisse, ainsi que la valeur de l'exposant e.

Je chipote, mais j'aurais dit l'inverse : la première information à laquelle on s'attend, c'est la valeur de $e$, mais on déduit également la valeur de la partie entière de la mantisse.

Si le champs vaut -1023, alors la partie entière vaut 0, et e vaut -1022. On a donc un nombre sous la forme suivante, dite dénormalisée :

Pourquoi n'expliques-tu plus l'intérêt de cela ? :)

Tu pourrais par exemple parler du cas où e est entre -1022 et +1023, puis dire que du coup on ne peut représenter de nombre inférieur à $2^{-1022}$ et que pour pallier cela, on introduit une convention pour $e = -1023$.

Après, peut-être est-il préférable d'aborder cela dans le second extrait, lorsque tu parles du plus petit nombre positif (à préciser dans le tuto) non nul représentable.

Mantisse (valeur)

Ce serait plutôt "Partie fractionnaire de la mantisse (valeur de la mantisse)". A titre personnel, il me semble plus lisible de faire deux colonnes plutôt que mettre des informations entre parenthèses.


Le tutoriel en l'état est de bonne qualité, mais tu pourrais peut-être encore l'améliorer en parlant des pourquoi :

  • Pourquoi la représentation à virgule flottante est-elle la plus utilisée ?
  • Pourquoi passer par la notation scientifique ?

Ca demanderait par contre pas mal de travail supplémentaire. A toi de voir quels sont les objectifs du tutoriel. :)

Merci. ^^

+0 -0

Le tutoriel en l'état est de bonne qualité, mais tu pourrais peut-être encore l'améliorer en parlant des pourquoi :

  • Pourquoi la représentation à virgule flottante est-elle la plus utilisée ?
  • Pourquoi passer par la notation scientifique ?

Vayel

Je pense que je vais en parler un peu dans la partie "limitations". On peut y parler de précision, gamme de valeurs, etc. Je vais pas détailler à fond les avantages et les inconvénients par rapport à d'autres représentations, parce que ça m'obligerait à les introduire. J'ai pas envie de faire un cours sur les réels en machine. Juste un cours sur les flottants en machine et les erreurs de calcul rigolotes qui vont avec. Cependant la dernière partie ouvrira un peu sur quadruple précision, BCD et autre.

Ce sujet est verrouillé.