Les flottants☘
Nombre décimal☘
On utilise les flottants pour représenter les nombres réels.
Le nombre de chiffres utilisé en machine est nécessairement limité: une machine ne connaît donc pas tous les décimaux (elle ne connaît pas les décimaux ayant "trop" de chiffres).
Comme une infinité de nombres réels n'ont même pas un nombre fini de chiffres, il est clair qu'aucun de ces réels n'est représenté par un flottant.
Les nombres \sqrt{2}, \pi sont par exemple impossible à manipuler dans un langage de programmation (que ce soit python, java, javascript, C, ...). Seules des approximations de ces nombres sont connues.
Il existe donc une infinité de nombres non représentés en machine. L'essentiel des calculs en machine ne sont donc que des calculs de valeurs approchées.
Des approximations parfois étonnantes☘
Au problème du nombre fini de chiffres s'ajoute le problème de la représentation des nombres en base 2 (nous y reviendrons en détail).
Cela donne des résultats dont il faut apprendre à se méfier.
Demandons à Python si 0.1 + 0.1 est égal à 0.2 (on utilise pour cela == )
>>> 0.1 + 0.1 == 0.2
True
Tout semble bien se passer.
Et demandons lui maintenant si 0.1 + 0.1 + 0.1 est égal à 0.3:
>>> 0.1 + 0.1 + 0.1 == 0.3
False
De même:
>>> 0.1 + 0.2 == 0.3
False
Python répond FAUX!
Attention, cela n'est pas lié au langage python. On retrouvera ce problème dans tous les langages. Le problème est dû à la façon dont les nombres sont codés en machine.
Info
On retiendra qu'on ne doit jamais utiliser == entre deux flottants. On retiendra l'exemple ci-dessus de 0.1 + 0.1 + 0.1.
Info
Pour comparer des flottants en machine, on ne teste
en fait que leur proximité.
Python propose une fonction spécifique pour ce type de test:
isclose.
Des règles de calcul distinctes de celles des réels☘
Info
Soient a, b, c des nombres réels. On a: (a+b)+c = a+(b+c). C'est ce que l'on appelle associativité de l'addition de nombres réels (le mot associativité est utilisé pour rappeler que l'on peut, pour additionner, "associer" les deux premiers ou "associer" les deux derniers).
L'addition des flottants n'est pas associative:
>>> (0.3 + 0.9) + 0.2 == 0.3 + (0.9 + 0.2)
False
On insiste donc, une fois de plus, sur la non-utilisation de ==
entre flottants: l'information obtenue avec
un test a == b
(où a et b sont de type float)
ne concerne que les flottants et donne rarement une information sur
les nombres mathématiques qu'ils sont censés représenter.
Note
On peut heureusement obtenir
des conclusions fiables en terme de "proximité",
c'est à dire d'approximation dans de nombreux cas. Mais même en sachant se limiter à des tests
de proximité, on peut très vite sortir des conclusions fiables.
La discipline informatique qui se préoccupe de la maîtrise de ces problèmes est nommée arithmétique
des ordinateurs.
En mathématiques, l'analyse numérique est une discipline qui se préoccupe également
de ces problèmes.
Opérations sur les flottants☘
>>> type(2.1 + 3.2) # addition
<class 'float'>
>>> type(2.0 * 3.0) # multiplication
<class 'float'>
>>> type(2.0 ** 3.0) # exposant
<class 'float'>
>>> type(3.0 / 5.1) # division
<class 'float'>
>>> type(3.1 - 5.7) # soustraction
<class 'float'>
Erreur en programmation☘
En apprenant à programmer, on passe beaucoup de temps à débuguer. Il faut apprendre à repérer les erreurs, notamment les plus fréquentes.
En voici une:
>>> 3.0 / 0.0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero
L'erreur est ici évidente puisqu'on a directement divisé par 0. Dans un programme complexe, cette division par 0 peut être cachée sous la forme d'une division par une variable qui prend la valeur 0 à un moment dans le programme, sans que le programmeur n'ait a priori prévu cette situation.
Opération mixte☘
On a vu que les flottants et les entiers ne sont pas codés de la même façon. Une conséquence est qu'on ne devrait pas pouvoir faire d'opérations entre un entier et un flottant.
Essayons:
>>> 3.1 + 2
5.1
>>> type(3.0 + 2)
<class 'float'>
En fait, dans une situation comme celle-ci, python transforme l'entier en flottant (2 devient 2.0) puis effectue l'addition.
Info
Dans certains langages de programmation, une tentative d'opération comme la précédente entre un flottant et un entier ménerait à une erreur.
Voici par exemple une copie d'une console interactive OCaml (OCaml est, comme Python, un
langage de programmation).
- En ligne 1, on ajoute deux entiers. On utilise pour cela l'opérateur
+
. - En dernière ligne, on ajoute deux flottants. On utiliser pour cela
l'opérateur
+.
. - Dans les deux autres lignes, on a essayé d'ajouter un entier et un flottant en
utilisant
+
ou+.
: l'opération est refusée dans les deux cas.
# 2+3 ;;
- : int = 5
# 2.0 + 3 ;;
Line 1, characters 0-3:
Error: This expression has type float but an expression was expected of type int
# 2.0 +. 3 ;;
Line 1, characters 7-8:
Error: This expression has type int but an expression was expected of type float
Hint: Did you mean `3.'?
# 2.0 +. 3.0 ;;
- : float = 5.
Vous pouvez tester OCaml en ligne sur cette page par exemple.