Introduction
Les ordinateurs ne peuvent pas représenter avec exactitude tous les nombres réels, car ils stockent les informations dans un nombre limité de bits. Pour cela, ils utilisent une approximation appelée représentation en virgule flottante, qui permet d’exprimer une grande variété de valeurs à l’aide d’un format normalisé. Cette méthode repose sur la base 2 et suit le standard IEEE 754, ce qui permet d’assurer un comportement cohérent des calculs sur toutes les machines. Toutefois, cette représentation introduit des erreurs inévitables qu’il est essentiel de comprendre pour éviter des bugs subtils en programmation.
Définir un nombre flottant
La représentation en virgule flottante s’inspire de la notation scientifique. Un nombre réel est codé sous la forme suivante :
signe × mantisse × 2^exposant
Le signe est un bit indiquant si le nombre est positif ou négatif.
La mantisse (ou partie significative) contient les chiffres utiles du nombre, codés en binaire.
L’exposant permet de décaler la virgule pour représenter de très grands ou très petits nombres.
En Python, un nombre flottant suit le format IEEE 754 double précision (64 bits) :
1 bit pour le signe.
11 bits pour l’exposant, codé avec un biais de +1023.
52 bits pour la mantisse (avec un bit implicite égal à 1 dans les cas normaux).
Exemple : représenter 0,625
Convertissons 0,625 en binaire :
0,625 = 0,5 + 0,125 → 0,101
On l’écrit sous forme normalisée :
0,101 = 1,01 × 2⁻¹
Cela donne :
Signe : 0
Exposant : -1 + 1023 = 1022 → 01111111110
Mantisse : bits après le 1 initial → 010000... (sur 52 bits)
À retenir
Un nombre flottant est représenté selon le modèle « signe × mantisse × 2^exposant », en respectant la norme IEEE 754. Cela permet de coder un grand ensemble de réels avec un format commun aux langages de programmation.
Sources d’erreurs : codage et accumulation
La représentation flottante ne permet pas de coder toutes les valeurs exactement. Deux grandes sources d’imprécision sont à distinguer : l’erreur de codage d’un nombre isolé et l’erreur due à l’accumulation dans les calculs.
Erreurs de codage : certains décimaux sont intraduisibles
Certains nombres simples en base 10 ont une écriture infinie en binaire. C’est le cas de 0,1 :
>>> 0.1
0.10000000000000000555...0,1 s’écrit 0,000110011001100... (répétition de 0011). Cette suite étant infinie, elle est tronquée, ce qui provoque une approximation.
Erreurs d’accumulation : des écarts qui s’ajoutent
Lors de calculs répétés, ces petites erreurs s’additionnent. Exemple :
x = 0.0
for i in range(10):
x += 0.1
print(x)On attend 1.0, mais on obtient 0.9999999999999999.
Comparaisons à éviter
Il faut éviter de tester l’égalité directe entre deux flottants :
>>> 0.1 + 0.2 == 0.3
FalseÀ la place, on utilise une marge d’erreur :
abs((0.1 + 0.2) - 0.3) < 1e-9À retenir
Les erreurs sur les flottants peuvent venir soit de leur codage binaire, soit de l’accumulation lors de calculs successifs. Pour éviter les pièges, il faut comparer les résultats avec une tolérance, jamais avec égalité stricte.
Cas extrêmes : infinis, NaN, sous-normaux
Le standard IEEE 754 définit aussi des cas particuliers pour gérer les situations limites sans provoquer d’erreurs fatales.
Infinis et NaN
+∞ ou −∞ : apparaissent lors d’un dépassement de capacité ou d’une division par zéro flottant.
>>> 1.0 / 0.0
infNaN (Not a Number) : résultat d’une opération non mathématique, comme la racine d’un nombre négatif (en flottant).
>>> float('nan') == float('nan')
FalseUne valeur NaN n’est jamais égale à elle-même.
Sous-normalisation : préserver les très petites valeurs
Quand les nombres deviennent trop proches de zéro, l’exposant minimum (−1022) est insuffisant. Pour continuer à représenter de petites valeurs positives, on autorise une mantisse non normalisée (le bit 1 implicite devient 0).
Exemple : sous-normalisation
Prenons le plus petit exposant normalisé (−1022). Si l’on veut représenter 1 × 2⁻¹⁰²³, on utilise une mantisse de 1 (bit implicite) avec cet exposant. Mais pour coder un nombre encore plus petit, on supprime le bit implicite et décale encore la mantisse :
ex : 0,000...1 × 2⁻¹⁰²²
Cela permet d’approcher zéro sans « trou », même si la précision chute fortement.
À retenir
Pour gérer les situations extrêmes, la norme IEEE 754 prévoit des codages spéciaux : infini, NaN et sous-normaux. Ces formats assurent une continuité des calculs, même en cas de dépassement ou de très faible valeur.
Bonnes pratiques pour éviter les erreurs
Certaines stratégies permettent de contourner les problèmes liés aux flottants.
Utiliser des entiers quand c’est possible
Dans les applications sensibles (ex : calculs financiers), il vaut mieux éviter les flottants et raisonner en entiers :
# Représenter 10,25 € comme 1025 centimesUtiliser decimal ou fractions en Python
Ces modules gèrent les valeurs avec une précision arbitraire :
from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2'))Comparer avec tolérance
Il est recommandé de ne jamais tester a == b pour des flottants, mais de faire :
abs(a - b) < epsilonoù epsilon est une valeur comme 1e-9.
À retenir
Pour éviter les erreurs, on privilégie les entiers, les bibliothèques spécialisées (
decimal,fractions) et les comparaisons à marge d’erreur. Ces pratiques assurent des résultats plus fiables et plus compréhensibles.
Conclusion
La représentation flottante permet aux ordinateurs de manipuler efficacement des nombres réels, mais elle repose sur une approximation contrôlée. Certains décimaux ne peuvent être codés exactement, des erreurs d’arrondi se produisent, et des cas limites doivent être gérés avec rigueur. En comprenant ces mécanismes — codage, sous-normalisation, cas extrêmes —, les élèves acquièrent les bons réflexes pour écrire des programmes plus précis et plus robustes.
