Aller au contenu

Des calculs déroutants☘

Au problème du nombre fini de chiffres s'ajoute le problème de la représentation des nombres décimaux en base 2. Cela donne des résultats dont il faut apprendre à se méfier...

Exemple

  1. Tout d'abord, calculons 0.1 + 0.1 :

    >>> 0.1 + 0.1
    0.2
    
    >>> 0.1 + 0.1 == 0.2
    True
    
    En demandant à Python, si, pour lui, 0.1 + 0.1 est bien égal à 0.2, tout semble bien se passer.

  2. A présent, calculons 0.1 + 0.1 + 0.1 :

    >>> 0.1 + 0.1 + 0.1
    0.30000000000000004
    
    Étonnant, il semble que le résultat ne soit pas 0.3 !

  3. Demandons alors à Python si 0.1 + 0.1 + 0.1 est bien égal à 0.3 :

    >>> 0.1 + 0.1 + 0.1 == 0.3
    False
    
    Étonnant n'est-ce pas ?

  4. De même :

    >>> 0.1 + 0.2 == 0.3
    False
    
    Python répond FAUX !

Important

Cela n'est pas lié au langage Python. On retrouvera ce problème dans tous les langages de programmation.
Ce problème est dû à la façon dont les nombres à virgule sont codés en machine.

A retenir

On ne doit jamais tester l'égalité de deux flottants avec le comparateur « == ».
Il faudra se rappeler de l'exemple du calcul de 0.1 + 0.1 + 0.1 ci-dessus.

Si l'on cherche à tester l'égalité de flottants en machine, on ne teste que leur proximité (avec risques d'erreur donc).
Le module math de Python propose une fonction spécifique pour ce type de test : isclose().

>>> from math import isclose
>>> isclose(0.1 + 0.2, 0.3)
True

Exemple☘

La fonction fractions_egales() a pour paramètres les entiers a, b, c et d. Cette fonction renvoie True si la fraction \frac{a}{b} est égale à la fraction \frac{c}{d} et False sinon.

  1. Quelle précondition sur les paramètres semble-t-il raisonnable d'imposer ?

    Une réponse

    Les paramètres b et d, qui représentent les dénominateurs, doivent être non nuls.

  2. Complétez le code de la fonction en ajoutant une assertion pour traduire la précondition précédente.

    1
    2
    3
    4
    5
    6
    def fractions_egales(a, b, c, d):
        """
        a, b, c, d – int, entiers avec b et d non nuls
        Sortie: bool – True lorsque la fraction a/b est égale à c/d,
                       False sinon
        """
    
    Attention

    Le test if a/b == c/d serait une bien mauvaise idée.
    Rappelez-vous : on ne peut pas vérifier l'égalité de deux flottants avec « == » !

    Une solution
    1
    2
    3
    4
    5
    6
    7
    8
    def fractions_egales(a, b, c, d):
        """
        a, b, c, d – int, entiers avec b et d non nuls
        Sortie: bool – True lorsque  est égale à ,
                       False sinon
        """
        assert (b!= 0) and (d!= 0), "dénominateur nul !"
        return a*d == b*c
    

Des règles de calcul étonnantes☘

Info

Soient a, b et 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).

En machine, l'addition des flottants n'est pas associative :

>>> (0.3 + 0.9) + 0.2
1.4

>>> 0.3 + (0.9 + 0.2)
1.4000000000000001

>>> (0.3 + 0.9) + 0.2 == 0.3 + (0.9 + 0.2)
False

L'essentiel des calculs en machine sur les flottants ne sont donc que des calculs de valeurs approchées.

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.