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.
- exemple :
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
- 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.
- 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
/
- La division3 entre flottants s'obtient avec l'opérateur
- Un calcul d'une puissance d'un flottant.
- Le résultat est donné en écriture scientifique \(\approx 1,\!5179\times10^{79}\)
- 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.
- 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.
- L'avant-dernier exemple calcule le volume moyen d'une molécule d'eau4 en ml, soit environ 30 Å3.
- 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')
- La première opération donne un résultat très petit, qui ressemble au plus petit flottant strictement positif.
- La deuxième, tellement petit, qu'il est arrondi à exactement zéro.
- La troisième donne un résultat très grand, écrit en écriture scientifique.
- 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.
- Notons que
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
- 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
.
- Par exemple, pour savoir si un triangle à côtés flottants \((a < b < c)\) est rectangle, on ne fera pas le test
- Il faut apprendre à faire des arrondis à la précision que l'on souhaite.
- Nous allons donc découvrir, entre autres, les fonctions natives
round
etabs
.
- Nous allons donc découvrir, entre autres, les fonctions natives
-
La notation e (en) ↩
-
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. ↩