Aller au contenu

Présentation des flottants⚓︎

Les flottants

Les flottants1 (floating point numbers) s'utilisent comme les nombres décimaux, mais il y aura des précautions à prendre. Les mêmes qu'avec presque tout langage de programmation.

Les choses simples avec les flottants⚓︎

À savoir

  • Le point . est le séparateur décimal.
  • Ces nombres sont stockés en binaire (et non en décimal)
    • avec une précision un peu meilleure qu'avec une calculatrice,
    • mais pas arbitraire non plus.
  • On peut entrer directement un nombre en écriture scientifique en utilisant la notation2 e
    • exemple : -1.602e-19 pour \(-1,602 \times 10^{-19}\), la charge en coulomb d'un électron.

Le nombre stocké est souvent différent du nombre entré

Le nombre stocké sera l'approximation binaire du nombre décimal entré et sera souvent différent !

Exemples simples expliqués

In [1]: from math import pi, sqrt

In [2]: pi / 2
Out[2]: 1.5707963267948966

In [3]: 1.2**1000
Out[3]: 1.5179100891722457e+79

In [4]: 7.3 + 2
Out[4]: 9.3

In [5]: 21 / 3
Out[5]: 7.0

In [6]: 18 / 6.02e23
Out[6]: 2.990033222591362e-23

In [7]: sqrt(12.3)
Out[7]: 3.5071355833500366
  1. Depuis (from) le module math, on importe :
    • une bonne approximation de \(\pi\) par un flottant,
    • une fonction racine carrée (square root) qui renvoie un flottant.
  2. Une approximation de \(\frac \pi 2\) donnée avec une quinzaine de chiffres décimaux significatifs.
    • La division3 entre flottants s'obtient avec l'opérateur /
  3. Un calcul d'une puissance d'un flottant.
    • Le résultat est donné en écriture scientifique \(\approx 1,\!5179\times10^{79}\)
  4. On peut mélanger un entier et un flottant dans une opération.
    • Détail important : l'entier sera d'abord converti automatiquement en flottant avant le calcul.
  5. Si on utilise l'opérateur /,
    • les opérandes entiers sont automatiquement convertis en flottant avant le calcul ;
    • le résultat sera un flottant, même si la division entière a un reste nul.
  6. L'avant-dernier exemple calcule le volume moyen d'une molécule d'eau4 en ml, soit environ 30 Å3.
  7. On calcule la racine carrée d'un flottant.

Les opérateurs

On retrouve les opérateurs déjà vus avec les entiers, et on ajoute / pour la division non abrégée5.

+ - * ** < <= == != >= > fonctionnent aussi avec les flottants.

Note : Python permet aussi de travailler avec des fractions, (module fractions) et on retrouvera ces mêmes opérateurs. Nous le reverrons.

>>> from fractions import Fraction
>>> Fraction(3, 7) + Fraction(-1, 7) / Fraction(2, 3)
Fraction(3, 14)
>>>
Maths expertes

Pour ceux qui savent ce qu'est un nombre complexe, les mêmes opérateurs fonctionnent avec les nombres complexes. Si un opérande est complexe, alors l'autre est automatiquement converti avant calcul en complexe. Nous le reverrons.

>>> (1 + 2j) / (1 - 2j)
(-0.6+0.8j)
>>>

Points délicats⚓︎

Attention

On retrouve comme sur de nombreuses calculatrices (et c'est normal) les points suivants :

  • Il existe des limites aux nombres flottants, avec
    • un plus petit flottant strictement positif,
    • un plus grand flottant positif,
    • et de même avec les négatifs.
  • Le nombre affiché ou entré n'est souvent pas égal au nombre représenté en machine.
  • Pour simplifier :
    • une quinzaine de chiffres significatifs, et
    • des exposants de la puissance de 10 entre -300 et +300, environ.

Exemples expliqués

In [1]: 0.5**1000
Out[1]: 9.332636185032189e-302

In [2]: 0.5**1100
Out[2]: 0.0

In [3]: 2.0**1000
Out[3]: 1.0715086071862673e+301

In [4]: 2.0**1100
Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

OverflowError: (34, 'Numerical result out of range')
  1. La première opération donne un résultat très petit, qui ressemble au plus petit flottant strictement positif.
  2. La deuxième, tellement petit, qu'il est arrondi à exactement zéro.
  3. La troisième donne un résultat très grand, écrit en écriture scientifique.
  4. La quatrième provoque une erreur, le résultat étant trop grand.
    • Notons que 2**1100 ne provoquerait pas d'erreur ; c'est un entier qui pourrait être bien plus grand encore sans perdre de précision, tant qu'il y a de la mémoire disponible.

Stockage interne, souvent une approximation⚓︎

Exemple à méditer

In [1]: 0.1 + 0.2 == 0.3
Out[1]: False
  • \(0.1\) est approché en machine par un nombre qui n'est pas exactement égal à \(0.1\)6, mais par un nombre écrit en binaire, au plus proche. De même pour \(0.2\) et \(0.3\).
  • Le test d'égalité est réalisé sur les nombres binaires, pas sur les nombres affichés en décimal !
  • Une calculatrice a normalement le même comportement, sauf bug.

Conclusion, à retenir

  1. On ne doit jamais faire de test d'égalité entre flottants !
    • Par exemple, pour savoir si un triangle à côtés flottants \((a < b < c)\) est rectangle, on ne fera pas le test a*a + b*b == c*c.
  2. Il faut apprendre à faire des arrondis à la précision que l'on souhaite.
    • Nous allons donc découvrir, entre autres, les fonctions natives round et abs.

  1. Les flottants ; la norme IEEE_754 

  2. La notation e (en) 

  3. La division 

  4. La constante d'Avogadro 

  5. La division non abrégée 

  6. L'approximation de \(0.1\) est stockée avec la valeur \(\dfrac{3602879701896397}{2^{55}} =\dfrac{3602879701896397}{36028797018963968} = 0,\!1000000000000000055511151231257827021181583404541015625\) qui est lui aussi un décimal, mais surtout un quotient d'entier par une puissance de deux.