Représentation en virgule flottante

Dans la leçon précédente, nous avons identifié les erreurs d'arrondi comme une source fondamentale d'imprécision. Ces erreurs découlent directement de la façon dont les ordinateurs représentent les nombres. Comprendre cette représentation est essentiel pour anticiper et contrôler le comportement des algorithmes numériques.

Le problème fondamental

L'ensemble des nombres réels R\mathbb{R} possède deux propriétés qui le rendent impossible à représenter exactement dans un ordinateur : il est infini (il contient une infinité de nombres) et il est continu (entre deux nombres quelconques, il en existe toujours un autre).

Un ordinateur, en revanche, dispose d'une mémoire finie. Il ne peut stocker qu'un nombre fini de valeurs distinctes. Chaque nombre réel doit donc être approximé par l'un des nombres représentables dans la machine.

La question devient alors : comment choisir intelligemment quels nombres seront représentables ?

La notation en virgule flottante

La solution adoptée universellement est la notation en virgule flottante (ou notation flottante). Cette représentation s'inspire de la notation scientifique que vous connaissez déjà.

En notation scientifique, on écrit par exemple :

6,022×1023(nombre d’Avogadro)6{,}022 \times 10^{23} \quad \text{(nombre d'Avogadro)}
1,602×1019(charge de l’eˊlectron en coulombs)1{,}602 \times 10^{-19} \quad \text{(charge de l'électron en coulombs)}

Cette notation sépare deux informations : les chiffres significatifs (la mantisse) et l'ordre de grandeur (l'exposant).

Définition formelle

En notation flottante, un nombre XX est représenté sous la forme :

fl(X)=±0,d1d2d3ds×be\text{fl}(X) = \pm 0{,}d_1 d_2 d_3 \cdots d_s \times b^e

où :

  • bb est la base du système de numération
  • ss est le nombre de chiffres de la mantisse (la précision)
  • ee est l'exposant, avec meMm \leq e \leq M
  • did_i sont les chiffres de la mantisse, avec 0dib10 \leq d_i \leq b-1

La notation fl(X)\text{fl}(X) désigne la représentation flottante du nombre XX.

La contrainte de normalisation

Pour garantir l'unicité de la représentation, on impose une contrainte supplémentaire :

d10d_1 \neq 0

Cette condition s'appelle la normalisation. Elle assure que le premier chiffre de la mantisse est toujours significatif.

Sans cette contrainte, un même nombre pourrait avoir plusieurs représentations. Par exemple, en base 10 avec 3 chiffres :

0,123×102=0,0123×103=0,00123×1040{,}123 \times 10^2 = 0{,}0123 \times 10^3 = 0{,}00123 \times 10^4

Avec la normalisation, seule la première forme est valide.

💡

Le quadruplet caractéristique

Un système de numération en virgule flottante est entièrement défini par quatre paramètres : (b,s,m,M)(b, s, m, M), soit la base, le nombre de chiffres de la mantisse, l'exposant minimal et l'exposant maximal.

Exemple : Un système miniature

Pour bien comprendre, construisons un système flottant minimal avec les paramètres suivants :

b=2,s=2,m=2,M=3b = 2, \quad s = 2, \quad m = -2, \quad M = 3

Ce système utilise la base 2 (binaire), une mantisse de 2 chiffres, et des exposants allant de -2 à 3.

Quels nombres sont représentables ?

Les nombres normalisés dans ce système ont la forme :

±0,d1d2×2eavec d10 et 2e3\pm 0{,}d_1 d_2 \times 2^e \quad \text{avec } d_1 \neq 0 \text{ et } -2 \leq e \leq 3

En base 2, la seule valeur non nulle pour d1d_1 est 1. Pour d2d_2, nous avons le choix entre 0 et 1. Les mantisses possibles sont donc :

0,102=12et0,112=12+14=340{,}10_2 = \frac{1}{2} \quad \text{et} \quad 0{,}11_2 = \frac{1}{2} + \frac{1}{4} = \frac{3}{4}

Pour chaque mantisse, nous avons 6 exposants possibles (e{2,1,0,1,2,3}e \in \{-2, -1, 0, 1, 2, 3\}).

Voici la liste complète des nombres positifs représentables :

MantisseExposantCalculValeur décimale
0,1020{,}10_22-212×22\frac{1}{2} \times 2^{-2}18=0,125\frac{1}{8} = 0{,}125
0,1020{,}10_21-112×21\frac{1}{2} \times 2^{-1}14=0,25\frac{1}{4} = 0{,}25
0,1020{,}10_20012×20\frac{1}{2} \times 2^{0}12=0,5\frac{1}{2} = 0{,}5
0,1020{,}10_21112×21\frac{1}{2} \times 2^{1}11
0,1020{,}10_22212×22\frac{1}{2} \times 2^{2}22
0,1020{,}10_23312×23\frac{1}{2} \times 2^{3}44
0,1120{,}11_22-234×22\frac{3}{4} \times 2^{-2}316=0,1875\frac{3}{16} = 0{,}1875
0,1120{,}11_21-134×21\frac{3}{4} \times 2^{-1}38=0,375\frac{3}{8} = 0{,}375
0,1120{,}11_20034×20\frac{3}{4} \times 2^{0}34=0,75\frac{3}{4} = 0{,}75
0,1120{,}11_21134×21\frac{3}{4} \times 2^{1}32=1,5\frac{3}{2} = 1{,}5
0,1120{,}11_22234×22\frac{3}{4} \times 2^{2}33
0,1120{,}11_23334×23\frac{3}{4} \times 2^{3}66

Notre système miniature ne peut représenter que 12 nombres positifs distincts (plus leurs opposés négatifs et le zéro).

Visualisation sur la droite réelle

Si nous plaçons ces nombres sur une droite, nous observons un phénomène important :

text
Nombres positifs représentables :

0    0.125  0.25   0.5    1      2      4      6
|      |      |      |      |      |      |      |
+------+------+------+------+------+------+------+-->
     0.1875 0.375  0.75   1.5    3

Observation : les nombres sont plus serrés près de zéro
            et plus espacés pour les grandes valeurs.

Les nombres représentables ne sont pas uniformément distribués. Ils sont plus denses près de zéro et plus espacés pour les grandes valeurs. C'est une propriété fondamentale de la représentation en virgule flottante : la précision relative est à peu près constante, mais la précision absolue varie.

La droite des flottants

La représentation en virgule flottante divise la droite réelle en plusieurs zones distinctes.

Zone représentable

Les nombres dont la valeur absolue est comprise entre le plus petit nombre normalisé positif et le plus grand nombre représentable peuvent être approximés.

Dans notre système miniature :

  • Plus petit positif normalisé : 0,102×22=180{,}10_2 \times 2^{-2} = \frac{1}{8}
  • Plus grand positif : 0,112×23=60{,}11_2 \times 2^{3} = 6

Dépassement de capacité (overflow)

Lorsqu'un calcul produit un résultat dont la valeur absolue dépasse le plus grand nombre représentable, on parle de dépassement de capacité (en anglais, overflow).

Dans notre système, tout nombre supérieur à 6 (ou inférieur à -6) provoque un dépassement.

Soupassement de capacité (underflow)

Lorsqu'un résultat non nul est trop proche de zéro pour être représenté, on parle de soupassement de capacité (en anglais, underflow).

Dans notre système, tout nombre positif inférieur à 18\frac{1}{8} (mais non nul) provoque un soupassement.

⚠️

Conséquences pratiques

Le dépassement de capacité produit généralement une valeur spéciale notée « Inf » (infini). Le soupassement peut produire zéro ou une valeur dénormalisée, selon le système. Ces situations peuvent propager des erreurs catastrophiques dans un calcul.

Compter les nombres représentables

Combien de nombres distincts un système flottant peut-il représenter ?

Pour un système (b,s,m,M)(b, s, m, M) :

  • Nombre de mantisses distinctes : (b1)×bs1(b-1) \times b^{s-1} (le premier chiffre a b1b-1 choix, les autres en ont bb)
  • Nombre d'exposants : Mm+1M - m + 1
  • Avec les signes et le zéro : 2×(b1)×bs1×(Mm+1)+12 \times (b-1) \times b^{s-1} \times (M - m + 1) + 1

Pour notre système miniature (2,2,2,3)(2, 2, -2, 3) :

2×1×21×6+1=25 nombres2 \times 1 \times 2^1 \times 6 + 1 = 25 \text{ nombres}

(12 positifs + 12 négatifs + le zéro)

La norme IEEE 754

Les ordinateurs modernes utilisent la norme IEEE 754, qui définit deux formats principaux. Cette norme est le standard universel utilisé par pratiquement tous les processeurs.

Structure générale d'un nombre flottant

Un nombre flottant est stocké en trois parties distinctes :

signeexposantmantisse\boxed{\text{signe}} \quad \boxed{\text{exposant}} \quad \boxed{\text{mantisse}}

Prenons l'exemple de la simple précision (32 bits) pour tout expliquer :

PartieNombre de bitsRôle
Signe1 bit0 = positif, 1 = négatif
Exposant8 bitsDétermine l'ordre de grandeur
Mantisse23 bitsStocke les chiffres significatifs

Le problème des exposants négatifs

L'exposant doit pouvoir être positif ou négatif. Par exemple :

  • 1,5×2101{,}5 \times 2^{10} → exposant positif (grand nombre)
  • 1,5×2101{,}5 \times 2^{-10} → exposant négatif (petit nombre)

Plutôt que d'utiliser un bit de signe pour l'exposant, la norme IEEE 754 utilise une astuce appelée exposant biaisé.

L'idée : On stocke la valeur e=E+biaise = E + \text{biais} où :

  • EE est l'exposant réel (celui qu'on veut représenter)
  • ee est la valeur stockée dans les 8 bits (toujours positive)
  • Le biais vaut 127127 en simple précision

Pourquoi 127 ? Avec 8 bits, on peut stocker des valeurs de 0 à 255. En choisissant un biais de 127, on peut représenter des exposants réels allant de 126-126 à +127+127 :

Valeur stockée (e)Exposant réel (E = e − 127)Remarque
0Réservé (zéro et dénormalisés)
1126-126Plus petit exposant utilisable
12700Exposant nul
254+127+127Plus grand exposant utilisable
255Réservé (infini et NaN)

Les valeurs 0 et 255 sont réservées pour des cas spéciaux que nous verrons plus loin.

Le bit implicite : une astuce pour gagner de la précision

En notation scientifique normalisée en base 2, tout nombre s'écrit :

±1,xxxxx×2E\pm 1{,}xxxxx \times 2^E

Le premier chiffre avant la virgule est toujours 1 (c'est la définition de la normalisation en binaire). Puisqu'il est toujours égal à 1, pourquoi le stocker ?

L'astuce IEEE 754 : On ne stocke pas ce 1. Il est « implicite ». Les 23 bits de mantisse stockent uniquement la partie après la virgule (appelée partie fractionnaire ff).

Exemple concret : Représentons le nombre 5,755{,}75.

Étape 1 : Convertir en binaire.

5,75=4+1+0,5+0,25=22+20+21+22=101,1125{,}75 = 4 + 1 + 0{,}5 + 0{,}25 = 2^2 + 2^0 + 2^{-1} + 2^{-2} = 101{,}11_2

Étape 2 : Normaliser (décaler la virgule pour avoir 1,xxx).

101,112=1,01112×22101{,}11_2 = 1{,}0111_2 \times 2^2

Étape 3 : Identifier les composantes.

  • Signe : 0 (positif)
  • Exposant réel : E=2E = 2, donc valeur stockée : e=2+127=129=100000012e = 2 + 127 = 129 = 10000001_2
  • Partie fractionnaire : 01110111 (le 1 avant la virgule n'est pas stocké)

Représentation sur 32 bits :

0signe10000001exposant01110000000000000000000mantisse (23 bits)\underbrace{0}_{\text{signe}} \quad \underbrace{10000001}_{\text{exposant}} \quad \underbrace{01110000000000000000000}_{\text{mantisse (23 bits)}}

Formule de reconstruction d'un nombre

Pour reconstruire le nombre à partir de sa représentation, on utilise :

valeur=(1)signe×(1+f)×2e127\text{valeur} = (-1)^{\text{signe}} \times (1 + f) \times 2^{e - 127}

ff est la valeur de la partie fractionnaire (entre 0 et presque 1).

Vérifions avec notre exemple (5,755{,}75) :

(1)0×(1+0,01112)×2129127=1×1,4375×4=5,75(-1)^0 \times (1 + 0{,}0111_2) \times 2^{129-127} = 1 \times 1{,}4375 \times 4 = 5{,}75 \checkmark

(Car 0,01112=0,25+0,125+0,0625=0,43750{,}0111_2 = 0{,}25 + 0{,}125 + 0{,}0625 = 0{,}4375)

Calcul du plus grand nombre représentable

Maintenant que nous comprenons la structure, trouvons le plus grand nombre possible.

Pour maximiser un nombre, il faut :

  1. Un signe positif (0)
  2. L'exposant le plus grand possible
  3. La mantisse la plus grande possible

Quel est l'exposant maximum ?

La valeur stockée ee va de 0 à 255, mais :

  • e=0e = 0 est réservé pour le zéro et les nombres dénormalisés
  • e=255e = 255 est réservé pour l'infini (\infty) et NaN

Donc l'exposant maximum utilisable est e=254e = 254, ce qui donne :

Emax=254127=127E_{\max} = 254 - 127 = 127

Quelle est la mantisse maximum ?

La mantisse est maximale quand tous ses 23 bits sont à 1 :

fmax=0,11111...123 bits=i=1232if_{\max} = 0{,}\underbrace{11111...1}_{23 \text{ bits}} = \sum_{i=1}^{23} 2^{-i}

Cette somme est une série géométrique. Calculons-la :

i=1232i=12+14+18++1223\sum_{i=1}^{23} 2^{-i} = \frac{1}{2} + \frac{1}{4} + \frac{1}{8} + \cdots + \frac{1}{2^{23}}

C'est la somme d'une suite géométrique de raison 12\frac{1}{2} :

=12(1(12)23)112=11223=1223= \frac{\frac{1}{2}(1 - (\frac{1}{2})^{23})}{1 - \frac{1}{2}} = 1 - \frac{1}{2^{23}} = 1 - 2^{-23}

Avec le bit implicite (le 1 avant la virgule), la mantisse complète vaut :

mmax=1+fmax=1+(1223)=2223m_{\max} = 1 + f_{\max} = 1 + (1 - 2^{-23}) = 2 - 2^{-23}

Le plus grand nombre est donc :

floatmax=mmax×2Emax=(2223)×2127\text{float}_{\max} = m_{\max} \times 2^{E_{\max}} = (2 - 2^{-23}) \times 2^{127}

Calculons numériquement :

22231,999999882 - 2^{-23} \approx 1{,}99999988
21271,7×10382^{127} \approx 1{,}7 \times 10^{38}
floatmax3,4×1038\text{float}_{\max} \approx 3{,}4 \times 10^{38}

Calcul du plus petit nombre positif normalisé

Pour minimiser un nombre positif, il faut :

  1. L'exposant le plus petit possible
  2. La mantisse la plus petite possible

Quel est l'exposant minimum ?

La plus petite valeur utilisable est e=1e = 1 (car e=0e = 0 est réservé) :

Emin=1127=126E_{\min} = 1 - 127 = -126

Quelle est la mantisse minimum ?

La mantisse est minimale quand tous ses bits sont à 0 :

fmin=0,00000...023 bits=0f_{\min} = 0{,}\underbrace{00000...0}_{23 \text{ bits}} = 0

Avec le bit implicite :

mmin=1+0=1m_{\min} = 1 + 0 = 1

Le plus petit nombre positif normalisé est donc :

floatmin=1×21261,18×1038\text{float}_{\min} = 1 \times 2^{-126} \approx 1{,}18 \times 10^{-38}

Représentation du zéro

En IEEE 754, le zéro est représenté par un exposant et une mantisse tous deux nuls :

  • Exposant : e=0e = 0 (les 8 bits à 0)
  • Mantisse : f=0f = 0 (les 23 bits à 0)
±0:s    00000000e=0    00000000000000000000000f=0\pm 0 : \quad s \;|\; \underbrace{00000000}_{e=0} \;|\; \underbrace{00000000000000000000000}_{f=0}

Zéros signés : IEEE 754 distingue +0+0 et 0-0 selon le bit de signe. Arithmétiquement, ils sont égaux (+0=0+0 = -0 retourne vrai), mais leur représentation binaire diffère. Cette distinction peut être utile pour préserver le signe lors d'un underflow vers zéro.

Nombres dénormalisés (sous-normaux)

Quand l'exposant est nul (e=0e = 0) mais la mantisse est non nulle (f0f \neq 0), on obtient un nombre dénormalisé. Dans ce cas, le bit implicite est 0 (au lieu de 1) et l'exposant est fixé à E=126E = -126 :

(1)s×0,f×2126(-1)^s \times 0{,}f \times 2^{-126}

Ces nombres permettent un underflow graduel : ils comblent l'écart entre zéro et le plus petit nombre normalisé, évitant un saut brutal vers zéro.

💡

Plus petit nombre positif dénormalisé

Le plus petit nombre positif représentable (dénormalisé) est :

floatmindeˊnorm=223×2126=21491,4×1045\text{float}_{\min}^{\text{dénorm}} = 2^{-23} \times 2^{-126} = 2^{-149} \approx 1{,}4 \times 10^{-45}

Représentation de l'infini

L'infini est représenté avec un exposant maximal (tous les bits à 1) et une mantisse nulle :

  • Exposant : e=255e = 255 (les 8 bits à 1)
  • Mantisse : f=0f = 0
+:0    11111111e=255    00000000000000000000000f=0+\infty : \quad 0 \;|\; \underbrace{11111111}_{e=255} \;|\; \underbrace{00000000000000000000000}_{f=0}
:1    11111111e=255    00000000000000000000000f=0-\infty : \quad 1 \;|\; \underbrace{11111111}_{e=255} \;|\; \underbrace{00000000000000000000000}_{f=0}

Utilité : L'infini permet de représenter le résultat d'un overflow (dépassement de capacité) ou d'opérations comme 1/01/0. Les opérations arithmétiques avec l'infini sont bien définies : +1=\infty + 1 = \infty, ×2=\infty \times 2 = \infty, etc.

NaN (Not a Number)

NaN (Not a Number) représente le résultat d'opérations mathématiquement indéfinies. Il est encodé avec un exposant maximal et une mantisse non nulle :

  • Exposant : e=255e = 255
  • Mantisse : f0f \neq 0
NaN:s    11111111e=255    non nulf0\text{NaN} : \quad s \;|\; \underbrace{11111111}_{e=255} \;|\; \underbrace{\text{non nul}}_{f \neq 0}

Opérations produisant NaN :

  • 0/00/0
  • \infty - \infty
  • /\infty / \infty
  • 0×0 \times \infty
  • x\sqrt{x} pour x<0x < 0

Propriété importante : NaN n'est égal à aucune valeur, y compris lui-même. Le test xxx \neq x retourne vrai si et seulement si xx est NaN. C'est la méthode standard pour détecter un NaN.

⚠️

Propagation des NaN

Toute opération arithmétique impliquant un NaN produit un NaN. Cela permet de détecter qu'une erreur s'est produite quelque part dans un calcul.

Récapitulatif des valeurs spéciales

TypeExposant eMantisse fValeur
Zéro00±0\pm 0
Dénormalisé00\neq 0±0,f×2126\pm 0{,}f \times 2^{-126}
Normalisé1 à 254quelconque±1,f×2e127\pm 1{,}f \times 2^{e-127}
Infini2550±\pm \infty
NaN2550\neq 0Not a Number

Calcul de l'epsilon machine

L'epsilon machine ε\varepsilon (aussi appelé machine epsilon) caractérise la précision relative du système flottant. Sa définition exacte varie selon les auteurs, mais la définition la plus courante est :

💡

Définition de l'epsilon machine

L'epsilon machine ε\varepsilon est l'écart entre 1 et le plus petit nombre flottant strictement supérieur à 1.

Calcul pour IEEE 754 simple précision :

Le nombre 1 s'écrit en IEEE 754 avec une mantisse de 23 bits (plus le bit implicite) :

1=1,00000...023 zeˊros×201 = 1{,}\underbrace{00000...0}_{23 \text{ zéros}} \times 2^0

Le nombre flottant immédiatement supérieur à 1 est celui où le bit le moins significatif de la mantisse passe de 0 à 1 :

1+=1,00000...022 zeˊros1×201^+ = 1{,}\underbrace{00000...0}_{22 \text{ zéros}}1 \times 2^0

L'écart entre ces deux nombres est :

ε=1+1=2231,19×107\varepsilon = 1^+ - 1 = 2^{-23} \approx 1{,}19 \times 10^{-7}

Lien avec l'erreur d'arrondi :

Quand on arrondit un nombre réel xx au nombre flottant le plus proche, l'erreur maximale est la moitié de l'écart entre deux nombres flottants consécutifs. Autour de 1, cet écart est ε\varepsilon, donc l'erreur maximale est ε2\frac{\varepsilon}{2}.

Plus généralement, pour tout nombre réel xx dans la plage normale :

xfl(x)xε2=2245,96×108\left| \frac{x - \text{fl}(x)}{x} \right| \leq \frac{\varepsilon}{2} = 2^{-24} \approx 5{,}96 \times 10^{-8}

La quantité u=ε2u = \frac{\varepsilon}{2} est parfois appelée unit roundoff ou unité d'arrondi.

⚠️

Attention aux conventions

Certains auteurs définissent ε\varepsilon directement comme la borne d'erreur relative (ce que nous appelons u=ε2u = \frac{\varepsilon}{2}). Vérifiez toujours la convention utilisée dans vos références !

Interprétation pratique : En simple précision, on a environ 7 chiffres décimaux de précision (car log10(223)6,9\log_{10}(2^{23}) \approx 6{,}9).

Algorithme de calcul de l'epsilon machine :

L'algorithme suivant permet de calculer expérimentalement l'epsilon machine par recherche linéaire. Il retourne une valeur à un facteur 2 près de la valeur exacte :

calcul_epsilon.pypython
epsilon = 1.0

while (1.0 + 0.5 * epsilon) != 1.0:
  epsilon = 0.5 * epsilon

print(f"Epsilon machine ≈ {epsilon}")
# En double précision : ≈ 2.220446049250313e-16

Pourquoi cet algorithme fonctionne ?

À chaque itération, on divise ε\varepsilon par 2. La boucle s'arrête quand 1+ε21 + \frac{\varepsilon}{2} est arrondi à exactement 1, c'est-à-dire quand ε2\frac{\varepsilon}{2} est trop petit pour affecter la représentation de 1. À ce moment, ε\varepsilon est l'écart entre 1 et le nombre flottant suivant.

Récapitulatif : Simple précision (32 bits)

PropriétéFormuleValeur approximative
Plus grand nombre(2223)×2127(2 - 2^{-23}) \times 2^{127}3,4×10383{,}4 \times 10^{38}
Plus petit normalisé21262^{-126}1,2×10381{,}2 \times 10^{-38}
Epsilon machine ε\varepsilon2232^{-23}1,19×1071{,}19 \times 10^{-7}
Unité d'arrondi u=ε2u = \frac{\varepsilon}{2}2242^{-24}5,96×1085{,}96 \times 10^{-8}
Chiffres de précisionlog10(224)\lfloor \log_{10}(2^{24}) \rfloor≈ 7 chiffres décimaux

Double précision (64 bits)

Le raisonnement est identique, avec des paramètres différents :

ParamètreSimple précisionDouble précision
Bits pour l'exposant811
Bits pour la mantisse2352
Biais1271023
Exposant max utilisable254 → E = 1272046 → E = 1023
Exposant min utilisable1 → E = -1261 → E = -1022
PropriétéValeurApproximation
Plus grand nombre(2252)×21023(2 - 2^{-52}) \times 2^{1023}1,8×103081{,}8 \times 10^{308}
Plus petit normalisé210222^{-1022}2,2×103082{,}2 \times 10^{-308}
Epsilon machine ε\varepsilon2522^{-52}2,22×10162{,}22 \times 10^{-16}
Unité d'arrondi u=ε2u = \frac{\varepsilon}{2}2532^{-53}1,11×10161{,}11 \times 10^{-16}
Chiffres de précisionlog10(253)\lfloor \log_{10}(2^{53}) \rfloor≈ 15-16 chiffres décimaux
💡

Python utilise la double précision

En Python, le type float est toujours en double précision (64 bits). C'est pourquoi vous avez environ 15 chiffres décimaux de précision. Pour utiliser la simple précision, il faut passer par NumPy (numpy.float32).

Valeurs spéciales

La norme IEEE 754 définit également des valeurs spéciales pour représenter les situations exceptionnelles :

ValeurSignificationExemple de cause
++\infty et -\inftyDépassement de capacité10308×1010^{308} \times 10
NaN (Not a Number)Résultat indéfini0/00/0 ou 1\sqrt{-1}
Zéros signés (+0+0, 0-0)Soupassement avec signe10308/1020-10^{-308} / 10^{20}
valeurs_speciales.pypython
import math

# Démonstration des valeurs spéciales
print("=== Valeurs spéciales IEEE 754 ===")

# Infini
print(f"1e308 * 10 = {1e308 * 10}")        # inf
print(f"-1e308 * 10 = {-1e308 * 10}")      # -inf

# NaN
print(f"0.0 / 0.0 = {0.0 / 0.0}")          # nan (avec avertissement)
print(f"inf - inf = {float('inf') - float('inf')}")  # nan

# Propriété étrange de NaN
nan = float('nan')
print(f"nan == nan : {nan == nan}")         # False (!)
⚠️

Attention

NaN possède une propriété unique : il n'est égal à rien, pas même à lui-même. Le test nan==nan\text{nan} == \text{nan} retourne toujours False\text{False}. Utilisez la fonction math.isnan()\text{math.isnan()} pour détecter les NaN.

Démonstrations en Python

Observer les limites du système

limites_flottants.pypython
import sys

# Informations sur les flottants en Python (double précision)
print("=== Caractéristiques des flottants ===")
print(f"Plus grand flottant    : {sys.float_info.max:.6e}")
print(f"Plus petit positif     : {sys.float_info.min:.6e}")
print(f"Epsilon machine        : {sys.float_info.epsilon:.6e}")
print(f"Chiffres de précision  : {sys.float_info.dig}")

# Démonstration du dépassement de capacité
print("\n=== Dépassement de capacité ===")
grand = 1e308
print(f"1e308        = {grand}")
print(f"1e308 * 10   = {grand * 10}")  # Produit 'inf'

# Démonstration du soupassement
print("\n=== Soupassement de capacité ===")
petit = 1e-308
print(f"1e-308       = {petit}")
print(f"1e-308 / 1e20 = {petit / 1e20}")  # Approche de zéro

Calcul expérimental de l'epsilon

epsilon_machine.pypython
# Méthode 1 : Calcul itératif
eps = 1.0
while 1.0 + eps != 1.0:
  eps_precedent = eps
  eps = eps / 2.0

print(f"Epsilon calculé : {eps_precedent}")

# Méthode 2 : Valeur système
import sys
print(f"Epsilon système : {sys.float_info.epsilon}")

# Méthode 3 : Avec NumPy
import numpy as np
print(f"Epsilon float32 : {np.finfo(np.float32).eps}")
print(f"Epsilon float64 : {np.finfo(np.float64).eps}")

Ce qu'il faut retenir

La représentation en virgule flottante est un compromis entre la plage de valeurs représentables et la précision. Le système (b,s,m,M)(b, s, m, M) définit complètement les nombres représentables dans une machine.

Les points essentiels sont :

  • Les nombres flottants forment un ensemble fini et discret
  • Ils ne sont pas uniformément distribués : plus denses près de zéro
  • Le dépassement et le soupassement de capacité sont des situations à surveiller
  • La normalisation garantit l'unicité de la représentation
  • L'epsilon machine quantifie la précision relative du système
  • La norme IEEE 754 définit les formats standard (32 et 64 bits)

Dans la prochaine leçon, nous étudierons ce qui se passe lorsqu'on effectue des opérations arithmétiques sur ces nombres : comment les erreurs d'arrondi apparaissent concrètement lors des additions, soustractions, multiplications et divisions.

Exercices de réflexion

Exercice 1 : Construire un système flottant

Considérons un système flottant en base 10 avec les paramètres (b,s,m,M)=(10,2,1,2)(b, s, m, M) = (10, 2, -1, 2).

  1. Listez toutes les mantisses normalisées possibles.
  2. Combien de nombres positifs distincts ce système peut-il représenter ?
  3. Quel est le plus petit nombre positif représentable ? Le plus grand ?
  4. Le nombre 0,50{,}5 est-il représentable exactement dans ce système ?
💡

Indice

En base 10 avec normalisation, le premier chiffre d1d_1 peut prendre les valeurs 1, 2, 3, ..., 9. Le second chiffre d2d_2 peut prendre les valeurs 0, 1, 2, ..., 9.

Exercice 2 : Identifier les zones problématiques

Dans le système miniature (2,2,2,3)(2, 2, -2, 3) étudié dans cette leçon :

  1. Que se passe-t-il si on tente de représenter le nombre 0,050{,}05 ?
  2. Que se passe-t-il si on tente de représenter le nombre 1010 ?
  3. Entre quels nombres représentables consécutifs se trouve π\pi ?
  4. Quelle serait l'erreur d'arrondi si on approximait 2,72{,}7 par le nombre représentable le plus proche ?

Exercice 3 : Réflexion sur la densité

Observez la distribution des nombres représentables dans notre système miniature :

text
0.125, 0.1875, 0.25, 0.375, 0.5, 0.75, 1, 1.5, 2, 3, 4, 6
  1. Calculez l'écart entre deux nombres consécutifs pour l'intervalle [0,5,1][0{,}5, 1].
  2. Calculez l'écart entre deux nombres consécutifs pour l'intervalle [4,6][4, 6].
  3. Comment l'écart entre nombres consécutifs évolue-t-il lorsque les nombres grandissent ?
  4. Expliquez pourquoi cette propriété est une conséquence directe de la représentation en virgule flottante.
⚠️

Point clé à retenir

Cette variation de la densité explique pourquoi l'erreur absolue d'arrondi augmente avec la magnitude des nombres, tandis que l'erreur relative reste à peu près constante. C'est une caractéristique fondamentale de l'arithmétique flottante.

Exercice 4 : Explorer les limites en Python

Écrivez un programme Python qui :

  1. Affiche les valeurs de sys.float_info.max, sys.float_info.min et sys.float_info.epsilon.
  2. Vérifie expérimentalement que 1.0 + epsilon/2 == 1.0 est vrai mais 1.0 + epsilon == 1.0 est faux.
  3. Trouve le plus petit entier nn tel que 1,0+10n=1,01{,}0 + 10^{-n} = 1{,}0 en double précision.