Flottants et précision

Objectifs

  • Comprendre le mode de stockage des nombres flottants en informatique ;

  • Comprendre la notion de précision.

Mise en situation

En informatique on sait que toutes les données sont stockées en binaire. Pour les nombres décimaux, donc avec une virgule, on peut se demander comment stocker correctement la valeur sachant que la virgule n'est pas un nombre que l'on peut stocker : c'est un caractère. Une première approche pourrait être de simplement stocker la partie entière et la partie décimale séparément, mais ce n'est pas comme cela que ça fonctionne. C'est en réalité un peu plus complexe que cela, et en informatique on parle de nombres flottants, ou nombres à virgule flottante.

L'encodage des flottants

Les nombres flottants sont stockés sur 64 bits de façon à ce que le premier bit en partant de la gauche (on parle de bit de poids fort) détermine le signe : si ce bit vaut 0 le nombre est positif, si ce bit vaut 1 le nombre est négatif. Les onze bits suivants permettent d'encoder l'exposant et les cinquante deux bits restants permettent d'encoder la mantisse.

Les nombres sont dits flottants parce que la place de la virgule n'est pas fixe. Contrairement à ce que pourrait dicter l'intuition, il ne s'agit pas d'écrire les nombres avec un bit de signe, onze bits pour la partie entière et les cinquante deux bits restants pour la partie décimale.

Format de représentation des flottants en double précisionInformations[1]

Définition

Les nombres flottants sont calculés ainsi, en binaire :

nbFlottant = signe * 2exposant * mantisse

La place de la virgule dans un nombre flottant dépend donc de son exposant.

ExempleEn décimal

Il est plus simple d'utiliser le système décimal pour comprendre. Le nombre -1.2345 sera représenté avec les données suivantes :

  • Signe : négatif

  • Exposant : -4

  • Mantisse : 12345

Le calcul donnera 10-4, soit 0.0001, multiplié par 12345, soit 1.2345, puis passé en négatif.

On constate que le changement de l'exposant, par -5 par exemple, donnera le nombre 0.12345. La place de la virgule est donc flottante, et dépend de la valeur de l'exposant.

ExempleDéclarer un flottant et l'utiliser

1
"""Pyhton."""
2
nb_float = 0.1
3
print(nb_float)
4
nb_float *= 0.1
5
print(nb_float)
6
nb_float += 1
7
print(nb_float)
1
/** JavaScript */
2
let nbFloat = 0.1
3
console.log(nbFloat)
4
nbFloat *= 0.1
5
console.log(nbFloat)
6
nbFloat += 1
7
console.log(nbFloat)

En Python comme en JavaScript on déclare et on manipule les nombres flottants comme les autres nombres.

AttentionImprécisions

Tous les nombres ne sont pas parfaitement encodables avec cette méthode. Les nombres qui correspondent à une somme de puissance de deux sont écrits de façon exacte, les autres le sont de façon approchées, ce qui dans certains cas peut poser des problèmes de calcul.

ExempleProblèmes d'approximation

En mathématiques, 0.1 + 0.2 = 0.3. La réponse à la question « est ce que 0.2 ajouté à 0.1 vaut 0.3 ? » est « oui ».

De même, 0.25 + 0.25 = 0.5, donc la réponse à la question « est ce que 0.25 ajouté à 0.25 vaut 0.5 ? » est « oui ».

Cependant, à cause des problèmes d'approximation des nombres flottants, ce n'est pas le cas en informatique.

1
"""Python."""
2
print(0.1 + 0.2 == 0.3)
3
print(0.25 + 0.25 == 0.5)
1
/** JavaScript */
2
console.log(0.1 + 0.2 === 0.3)
3
console.log(0.25 + 0.25 === 0.5)

Ces deux programmes affichent false puis true, parce que 0.1 ne peut pas être encodé correctement. Ainsi, quand les programmes additionnent 0.1 et 0.2, ils additionnent en réalité un nombre très proche de 0.1 et 0.2, donc le résultat obtenu n'est pas égal à 0.3 et le test est faux.

En revanche, 0.25 est encodé correctement donc la deuxième addition donne un résultat exact et le test est vrai.

ConseilEviter les problèmes d'approximation

Pour éviter les problèmes d'approximation lors de calculs ou de comparaisons avec des flottants il faut travailler avec mathjs, une bibliothèque conçue pour gérer les problèmes d'approximations des nombres flottants en JavaScript.

ComplémenttoPrecision()

Soit x = 0.3333 :

  • x.toPrecision(2) renvoie 0.33.

  • x.toPrecision(2) est de type chaîne de caractère, x.toPrecision(2).substr(2) renvoie 33.

À retenir

Les nombres flottants sont stockés sur 64 bits, ils sont dits flottants parce que la place de la virgule dépend de l'exposant.