Nombres flottants et approximation

icône de pdf
Signaler
Dans cette leçon, tu vas comprendre comment les ordinateurs représentent les nombres réels grâce à la norme IEEE 754 en virgule flottante. Tu verras pourquoi certaines valeurs décimales ne peuvent pas être codées exactement, comment apparaissent les erreurs d’arrondi et quels cas particuliers (infini, NaN, sous-normaux) existent. Tu apprendras aussi les bonnes pratiques pour limiter ces imprécisions en programmation. Mots-clés : virgule flottante, IEEE 754, mantisse, exposant, erreurs d’arrondi, NaN.

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
inf
  • NaN (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')
False

Une 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 centimes

Utiliser 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) < epsilon

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.