Choisir comment représenter un nombre à virgule
Tu additionnes 0.1 et 0.2 dans Python, puis tu compares le résultat à
0.3 :
0.1 + 0.2 == 0.3Avant d'exécuter, prédis True ou False. Affiche ensuite le résultat du
calcul avec print(0.1 + 0.2).
Cette fiche fait travailler le contrôle d'un calcul numérique, une compétence du bloc BC02.
| Ton besoin | Où travailler |
|---|---|
| Comprendre le résultat de Python | Sections 1 et 3 |
| Choisir une représentation pour un usage | Section 2 |
| Contrôler l'effet des arrondis | Section 4 |
| Découvrir l'histoire de la norme | Section 5 |
Si tu lis depuis plus de vingt minutes sans avoir exécuté ou modifié un calcul, ferme la fiche et reprends ton exercice. Tu pourras revenir au point précis qui te bloque.
1. Observer l'approximation
Python affiche 0.30000000000000004 et la comparaison donne False. Ce
résultat ne vient pas d'une règle particulière à Python. Il vient de la façon
dont la plupart des ordinateurs représentent les nombres à virgule.
Affiche davantage de décimales pour comparer les valeurs réellement conservées :
print(f"{0.1:.20f}")
print(f"{0.2:.20f}")
print(f"{0.3:.20f}")Repère les chiffres qui apparaissent après le premier 1, le premier 2 et le
premier 3. La mémoire de l'ordinateur est finie : elle conserve ici des
valeurs très proches des trois nombres demandés, sans pouvoir les écrire
exactement.
2. Partir de l'usage
Avant de lire les explications, associe chaque situation à une représentation :
- le solde d'un compte affiché au centime ;
- la température relevée par un capteur ;
- une très grande distance et une très petite masse dans une simulation ;
- le nombre de commandes dans une table.
Choisis parmi : entier, centimes stockés comme entiers, type décimalUn type de donnée qui conserve des chiffres en base 10, utile quand une règle comme le centime doit rester exacte., nombre
flottant. Un type décimal stocke les chiffres en base 10 ; dans Python, écrire
simplement 0.1 crée au contraire un nombre flottantUne façon de stocker un nombre avec quelques chiffres utiles et une échelle mobile, pour couvrir des valeurs très petites comme très grandes dans un espace limité.. Écris aussi ce que tu veux
préserver : une valeur exacte, une grande plage de valeurs ou la précision de la
mesure.
Repères pour contrôler ton choix
- Une quantité comptée, comme un nombre de commandes, s'écrit naturellement avec un entier.
- Un montant exige une règle stable en base 10, le système qui utilise les dix chiffres de 0 à 9. Des centimes entiers ou un type décimal préservent cette règle.
- Une mesure de capteur est déjà une approximation du phénomène physique. Un nombre flottant peut convenir si sa précision dépasse celle du capteur.
- Une simulation qui combine des échelles très éloignées bénéficie de la grande plage des nombres flottants, mais doit contrôler la propagation des erreurs.
Un phénomène continu, comme une température, ne devient pas exact parce que
l'écran affiche 21,4 °C. Le capteur prélève et arrondit une mesure. Distingue
donc le phénomène, la mesure enregistrée et son affichage.
3. Comprendre le choix binaire
Imagine un espace mémoire limité. Tu dois pouvoir y placer aussi bien la taille d'une bactérie qu'une distance astronomique. Où places-tu la virgule ?
Avec une virgule fixeUne façon de stocker les nombres où l’unité est choisie à l’avance, par exemple compter des centimes avec des nombres entiers., tu décides de l'unité à l'avance. 1999 peut par
exemple représenter exactement 19,99 € si l'unité est le centime. Mais réserver
plus de place aux petites fractions réduit la plus grande valeur disponible.
Un nombre flottant reprend la notation scientifique, comme
1,25 × 10³ pour écrire 1250. Il conserve un nombre limité de chiffres utiles
et une échelle qui déplace la virgule. Cela permet de couvrir des valeurs très
petites et très grandes avec le même espace mémoire.
Les nombres flottants courants utilisent la base 2Un système d’écriture des nombres qui utilise seulement les chiffres 0 et 1, adapté aux deux états des circuits électroniques., c'est-à-dire une écriture
construite avec 0 et 1. Certaines fractions décimales n'ont pas d'écriture
binaire finie. 0,1 doit être approché, comme 1/3 doit être approché quand tu
l'écris 0,333... avec un nombre limité de chiffres.
Teste maintenant trois façons de contrôler le même calcul :
print(0.1 + 0.2 == 0.3)
print(round(0.1 + 0.2, 10) == round(0.3, 10))
import math
print(math.isclose(0.1 + 0.2, 0.3))La première demande une égalité exacte. La deuxième compare après un arrondi
choisi. math.isclose accepte un petit écart, appelé toléranceLe plus grand écart accepté entre deux valeurs pour les considérer comme assez proches dans un usage précis.. Le contrôle
dépend de la question : une mesure physique accepte souvent une tolérance,
alors qu'un identifiant doit rester exactement égal.
Modifie le premier calcul avec 0.25 + 0.5 == 0.75. Les quarts et les demis
ont une écriture finie en base 2. Compare le résultat avec celui de 0.1 + 0.2.
4. Arrondir au moment décidé
Trois parts valent 33.333, 33.333 et 33.334. Elles totalisent 100 dans cet
exemple. Si tu arrondis chaque valeur avant de les additionner, les petits écarts
retirés de l'affichage s'accumulent.
Prédis les deux résultats, puis exécute :
parts = [33.333, 33.333, 33.334]
print(sum(round(part, 2) for part in parts))
print(round(sum(parts), 2))Comparer les deux calculs
Le premier arrondit chaque part puis les additionne : il affiche 99.99. Le
second additionne les valeurs non arrondies puis arrondit le total : il affiche
100.0.
Les deux lignes ne répondent pas exactement à la même question. Pour un rapport, conserve les valeurs non arrondies pendant les calculs et arrondis l'affichage final. Si tu affiches plusieurs parts arrondies, précise que leur somme peut s'écarter légèrement de 100 %.
Retrouve un calcul de ton TP ou de ton rapport qui affiche des décimales. Écris à côté la valeur avant affichage, le moment où l'arrondi intervient, l'écart acceptable et le contrôle choisi.
Pour pratiquer le même piège dans une requête SQL, ouvre la section sur les parts arrondies de Ajouter un comptage à chaque ligne avec OVER.
5. Les personnes derrière la norme
Pourquoi des concurrents ont fini par adopter les mêmes règles
Le Z3 de Konrad Zuse utilisait déjà une virgule flottante en 1941 avec des relais électromécaniques. Les machines suivantes ont employé plusieurs bases, dont 2, 8, 10 et 16. Aucun de ces choix ne permet de stocker tous les nombres exactement dans une mémoire finie.
À la fin des années 1970, les constructeurs utilisaient leurs propres formats et règles. Un même programme scientifique pouvait donc changer de comportement en passant d'une machine à une autre.
William Kahan, mathématicien à Berkeley, avait travaillé sur l'arithmétique de la calculatrice HP-35. John Palmer l'a ensuite sollicité chez Intel pour les futures puces de calcul. En 1978, Kahan prépare une proposition avec Harold Stone et Jerome Coonen. Universitaires et industriels discutent la précision, les arrondis, le coût des circuits et la compatibilité.
Intel commercialise le coprocesseur 8087 en 1980. La norme IEEE 754, dont les travaux commencent en 1977, est approuvée en 1985. Une grande partie de ses choix existait donc déjà dans du matériel avant l'adoption finale.
La norme ne rend pas tous les calculs exacts. Elle fixe les formats et le comportement des opérations afin que les erreurs soient prévisibles et que les programmes puissent être transportés entre machines.
Si chaque fabricant décidait encore seul comment arrondir, comment vérifierais-tu qu'une simulation donne le même résultat sur deux machines ?
Pour lire cette histoire en français : Virgule flottante : la lente convergence vers la rigueur, Jean-Michel Muller, CNRS, notamment les pages 6 à 12.