Outils pour utilisateurs

Outils du site


nsi:premiere:flottants

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Nombres flottants

Problématique

On souhaite pouvoir représenter un nombre à virgule, positif ou négatif. Pour une raison qui apparaîtra plus loin, on qualifie les nombres à virgule de flottants.

Dans le cas des nombres négatifs, on adoptait une astuce, le complément à 2, qui nous permettait de ne rien changer aux circuits électroniques utilisés pour les calculs. Les cas des nombres à virgule est plus complexe et est complètement différent. En conséquence, un ordinateur possède des circuits électroniques différents selon qu'il fait des calculs avec des entiers ou des flottants.

Binaire naturel

Comme on le sait, on peut écrire n'importe quel nombre entier en binaire, que ce nombre soit positif ou négatif :

  • $13 = 2^3 + 2^2 + 2^0$ donc on peut écrire $13 = 1101_b$
  • $-13 = - 1101_b$

Il est également possible d'écrire des nombres à virgule :

$$13,625 = 2^3 + 2^2 + 2^0 + 2^{-1} + 2^{-3} \Rightarrow 13,75 = 1101,101_b$$

Voici une technique permettant d'être un peu plus efficace, surtout pour la partie à droite de la virgule.

$13,625 = 13 + 0,625$. La partie entière ne pose pas de difficulté, on procède comme avant. $13 = 1101_b$.

Pour $0,625$ on procède en multipliant par 2 la partie après la virgule et en retenant le chiffre à gauche.

  • $0,625 \times 2 = \textbf{1},25$
  • $0,25 \times 2 = \textbf{0},5$
  • $0,5 \times 2 = \textbf{1},0$ et inutile d'aller plus loin.

On lit de haut en bas : $101$ c'est la partie décimale, c'est à dire $,101_b$.

Donc $13,625 = 1101,101_b$.

Exercice 1

Convertir en binaire les nombres suivants :

  • 21,5
  • –17,75
  • 1,90625
  • 46,625
  • 0,3

Comme vous pouvez le voir avec le dernier nombre, il est possible qu'un nombre dont l'écriture se termine en décimal, ne se termine pas en binaire : L'écriture de 0,3 en binaire est infinie. Nous verrons que cela crée une difficulté. En effet, il ne sera pas possible de stocker une écriture binaire infinie dans la machine ce qui nous amènera à tronquer l'écriture et donc à approximer. Aussi étonnant que cela paraisse, quand on écrit en Python x = 0.3, x ne contient pas vraiment 0.3 mais une approximation !

Représentation machine

mantisse et exposant

Prenons $x = 55,40625$.

  1. Procéder comme précédemment.
    On obtient : $x = 11 0111,01101_b$
  2. Décaler la virgule pour la placer juste après le premier $1$.
    $x = 1,1011101101_b \times 10_b^{5}$
    Je rappelle que $10_b = 2$ donc $\times 10_b^5 = \times 2^5$

Le nombre $1,1011101101_b$ est appelé mantisse et le 5 est l'exposant.

On parle de virgule flottante car comme en notation scientifique, c'est l'exposant qui détermine la position de la virgule. C'est de la que vient le nom de flottant.

Exercice 2

Donnez la mantisse et l'exposant pour les nombres suivants :

  • 0,3515625
  • 45,625

type float - IEEE754

Je vous donne ci-dessous la version longue des flottants qui utilise 64 bits. Il en existe une version courte en 32 bits mais pas sur Python. Faites attention si vous consultez une aide sur internet de ne pas confondre les deux. Pour plus de détails...

Exemple : Le nombre 0b 0100 0000 0100 1011101101000 ... 0000

  • bit de signe 0 donc +
  • exposant + 1023 = 0b100 0000 0100 = 1028 donc exposant = 5
  • mantisse : On lit 1011101101000 ... 0000, il faut comprendre
    mantisse = 1.10111011010...00

Donc le nombre est $2^5 \times 1,1011101101_b = 110111,01101_b = 55,40625$

Exercice 3

Donner les nombres correspondant aux codages suivants :

  • 1011 1111 1101 0101 1010 ... 0000
  • 0100 0001 0011 1010 1111 1101 0100 0101 1100 ... 0000
  • 0011 1111 1111 0000 0000 ... 0001

Le dernier cas donne une mesure de la précision relative du dernier bit.

En virgule flottante cette précision relative est à peu près constante : 0,000 000 000 000 01 % près !

Exercice 4

Convertir les nombres suivants :

  • 497,625
  • 1000
  • –1240
  • 3.2e5

Le dernier cas correspond à la notation pour $3,2 \cdot 10^5$.

Simple et double précision

Dans d'autres langages (C, C++, …) le flottant ordinaire est codé en 32 bits. On peut demander des flottants plus longs (64 bits), donc plus précis. On parle de réels en double précision, ce sont des double.

float approxime

Des nombres comme $\pi$ ou $\sqrt{2}$ ne peuvent pas être écrits avec une écriture décimale finie. On n'est donc pas surpris que le type float ne permette pas non plus de les écrire exactement.

Il est plus surprenant de voir que le nombre 0,1 ne peut pas, lui non plus, être écrit en float sans approximation.

Appliquons la méthode vue plus haut pour 0,1 :

  • $0,1 \times 2 = \textbf{0},2$
  • $0,2 \times 2 = \textbf{0},4$
  • $0,4 \times 2 = \textbf{0},8$
  • $0,8 \times 2 = \textbf{1},6$
  • $0,6 \times 2 = \textbf{1},2$
  • $0,2 \times 2 = \textbf{0},4$
  • $0,4 \times 2 = \textbf{0},8$
  • $0,8 \times 2 = \textbf{1},6$

On en déduit que $0,1 = 0,00011001100110011..._b$. Cette écriture est infinie et il faudra la tronquer pour l'écrire en float. On approximera donc.

Quand en Python – et aussi dans la plupart des langages – on écrit x = 0.1, la variable n'est pas exactement égale à 0,1.

Si on écrit print(x) on ne s'en rend pas compte que x != 0.1 car l'affichage est limité aux 16 premières décimales.

>>> x = 0.1
>>> print(x)
0.1

Mais on peut forcer l'affichage de 60 décimales :

>>> x = 0.1
>>> print(f"{x:0.60f}")
0.100000000000000005551115123125782702118158340454101562500000

Il est possible d'imaginer des codages qui évitent ce genre de problème. Mais cela ferait perdre la grande efficacité des float pour pas grand chose car pour les calculs scientifiques, cette approximation ne pose pas de problème. Il existe néanmoins des outils de calcul exact qui utilisent une autre façon de stocker les nombres à virgule.

 Cas extrêmes

exposant + 1023 est codé sur 11 bits, il pourrait donc aller de 0 à 2047. Mais on interdit ces valeurs, on se limite à la plage 1 à 2046.

Exercice 5

  • Quel est le plus grand nombre que l'on peut représenter ?
  • Quel est le nombre le plus proche de 0 que l'on peut représenter ?

Valeurs spéciales

Ces cas spéciaux ne sont pas à connaître.

exposant + 1023 correspond aux bits 1 à 12 de la représentation (le bit 0 étant le signe).

Les valeurs 0 et 2047 sont gardées pour des nombres spéciaux.

  • Pour 0 on dit que le nombre est dénormalisé.// Dans ce cas, mantisse = 0,[52 bits de la mantisse] et sur les 11 bits précédent on code exposant + 1022.// Cette technique permet d'atteindre 0 ce qui serait impossible autrement.
  • 2047 sert pour des cas spéciaux comme $\infty$ ou NaN : not a number.

Exercice 6

Quelle valeur correspond aux deux flottants dénormalisés :

  • 0000 0000 0000 0000 … 0000
  • 0000 0000 0000 0000 … 0001

Remarque : 1e-324 renvoie 0.0

Les calculs

Les nombres flottants ne sont généralement pas des représentations exactes des nombres. Ils supposent une approximation qui peut avoir des effets surprenants.

Par exemple : 0.1 + 0.2 != 0.3

N'hésitez pas à tester en console les exemples proposés.

Exercice 7

Expliquer ce cas surprenant :

>>> 0.1 + 0.1 + 0.1
0.30000000000000004

Exercice 8

Expliquer la différence :

>>> 1e16 + 1 - 1e16
0.0
>>> 1e16 - 1e16 + 1
1.0

Exercice 9

Expliquer la différence :

>>> 2**1024
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
>>> 2.0**1024
OverflowError: (34, 'Numerical result out of range')

Exercice 10

  • Quel est le problème avec le code à droite ?
  • Comment modifier le programme pour qu'il produise le résultat attendu ?
x = 10
while x != 0:
  x -= 0.1
print("fini")
nsi/premiere/flottants.txt · Dernière modification : de goupillwiki