Le thème de la semaine des mathématiques 2025 est égalités. Ce concept, très présent en mathématiques, l’est aussi dans la programmation objet, et plus généralement en informatique où il existe plusieurs définitions de l’égalité.
Les différents sens de l’égalité en maths
Le premier mathématicien à parler d’égalité est Euclide. Il évoque des propriétés de l’égalité qui en font une relation d’équivalence :
- a=a
- si a=b alors b=a
- si a=c et b=c alors a=b
Mais l’égalité n’est pas une relation d’équivalence comme les autres, en plus de a = a il faut aussi a ≠ n’importe quoi d’autre que a. Par exemple une droite est toujours parallèle à elle-même mais n’est pas pour autant égale à toutes les droites qui lui sont parallèles. L’idée sous-jacente est de considérer comme égaux des objets mathématiques indistinguables l’un de l’autre.
égalité comme résultat d’un calcul
Lorsque j’écris 2+2=4, je ne dis pas seulement que le nombre 2+2 est le même nombre que 4, je sous-entends que si on effectue le calcul 2+2, le résultat est 4. D’ailleurs sur certaines calculatrices 4 opérations, le bouton permettant d’obtenir le résultat de l’évaluation d’une expression porte le signe =. Cela perturbe des élèves à partir du cycle 2, car ils finissent par se fixer sur cette interprétation de l’égalité, et ne comprennent pas qu’on puisse écrire 4=2+2 ou 2+2=3+1.
cas d’égalité des triangles
Chez Euclide, lorsqu’on dit que les triangles ABC et DEF sont égaux, on sous-entend qu’ils sont isométriques, et si par exemple AB = DE, on compare des distances et pas des points : que AB = DE ne signifie ni que A=D ni que B=E mais seulement que la distance entre A et B est la même que la distance entre D et E.
égalité approchée
En cycle 3, beaucoup d’élèves apprennent que π=3,14 et ont beaucoup de mal par la suite à se défaire de cette idée, qui donne à la fois une fausse image de π, et une fausse image de l’égalité.
Un problème similaire apparaît insidieusement lorsqu’on enseigne les fractions, notamment lorsqu’on dit que si on partage équitablement le contenu d’une bouteille en trois parties (égales !), chaque verre contient le tiers du contenu de la bouteille : en fait on ne peut pas forcément partager équitablement une quantité (par exemple si le nombre de molécules d’eau n’est pas divisible par 3, on sait grâce à la division euclidienne -encore Euclide- que le partage équitable est impossible) même si cette quantité est continue, du moins dans la pratique : les fractions obtenues en coupant des pizzas ou des segments ne peuvent être qu’approchées.
équations
L’énoncé d’une équation s’écrit avec le signe égal. Par exemple lorsqu’on écrit que x+1=4, on pose implicitement la question de savoir non pas si x+1=4 mais quand x+1=4 : quelles sont les valeurs de x pour lesquelles x+1=4 ? Une équation est donc un problème, et résoudre ce problème c’est donner l’ensemble des x pour lesquels l’égalité est vérifiée.
Un problème nouveau apparaît lorsqu’on parle d’équation d’une courbe algébrique : on ne peut pas lister toutes les solutions d’une équation de droite comme 2x+5y=3 parce qu’en caractéristique nulle il y a une infinité de solutions de l’équation.
fonctions
Dans l’écriture d’une relation, en particulier d’une fonction, on utilise aussi le signe d’égalité comme dans y = sin(x). Cela sous-entend que pour toute valeur de la variable x, la valeur correspondante de y est le sinus de la valeur correspondante de x. Une notion mathématique qui précède celle de fonction est celle de variable. Lorsque je dis que x=3, je ne dis pas que la variable x est égale à 3 (sinon ce ne serait pas une variable) mais que sa valeur est égale à 3. Une variable est en fait une donnée formée de deux choses : son nom (quoiqu’il existe, en logique et en informatique, des variables anonymes) et sa valeur, et l’écriture x=3 est un abus de langage pour dire que x a pour valeur 3.
L’égalité en informatique
Pour savoir si x=3, je dois donc récupérer la valeur de la variable x (cela s’appelle évaluer x, et suppose donc que la variable x est une expression) et la comparer avec 3. Le résultat de la comparaison est un booléen (False ou True).
Affectation
Python hérite d’un choix malheureux datant de Fortran, un des premiers langages informatiques compilés. Dans ces langages, lorsque je modifie une variable, par exemple en injectant la valeur 5 dans la variable x, je n’écris pas 5→x pour suggérer cette affectation (ne serait-ce que parce que le caractère → n’existe pas sur un clavier azerty…) mais x=5, qui montre non pas un constat d’égalité, mais une volonté (que x soit égal à 5). Il y a eu des langages de programmation utilisant une suite non symétrique de symboles pour désigner l’affectation (:= dans les langages issus d’Algol, <- pour R…) et dans ces langages (y compris les langages purement fonctionnels -dépourvus de variables- comme Lisp, OCaml ou Haskell, et SQL qui n’est pas à proprement parler un langage de programmation) il est possible d’utiliser le signe d’égalité pour une comparaison, mais pour Python on ne peut pas, ce signe étant déjà réservé à l’affectation. Comment faire alors ?
Comparaison en Python
Pour savoir si deux objets sont égaux, en Python, on utilise un signe d’égalité dédoublé comme dans 2+2==4. Ou pas ! On peut aussi écrire 2+2 is 4, avec le même résultat (évaluation à True). Il y a donc deux égalités en Python, ce qui inscrit Python pleinement dans le thème de la semaine des maths 2025 (égalités, au pluriel) ! En quoi ces deux égalités diffèrent-elles ? En rien, avec des objets immuables : la première évalue les deux membres de l’égalité et compare les résultats des deux évaluations, la seconde compare les adresses mémoire des deux objets. Les réponses sont les mêmes, mais avec des objets mutables comme des listes, les égalités diffèrent :
>>> tab1 = [3,1,4]
>>> tab2 = [3,1,4]
>>> tab1 is tab2
False
>>> tab1 == tab2
True
égalité approchée
Pour comparer deux entiers, on sait depuis le cycle 2 comment faire avec leur écriture décimale. Pour les réels c’est plus compliqué, parce que les réels sont modélisés par des flottants, et que des flottants, il n’y en a que 18446744073709551616 (et encore, certains flottants, comme NaN et l’infini, ne sont pas des réels). A priori, si on veut comparer avec , il ne devrait pas y avoir de souci puisque les deux nombres ne sont présents en mémoire que sous forme approchée, et devraient être approchés par le même flottant :
>>> a =8**0.5
>>> b = 2*2**0.5
>>> a == b
True
>>> a
2.8284271247461903
>>> b
2.8284271247461903
Mais les flottants sont des fractions dyadiques, ensemble strictement inclus dans celui des décimaux, et même les nombres décimaux ne peuvent être comparés exactement :
>>> a = 0.1 + 0.2
>>> b = 0.3
>>> a == b
False
>>> a
0.30000000000000004
>>> b
0.3
>>> a-b
5.551115123125783e-17
Cela pose un problème en géométrie, où un déterminant censé être nul peut ne pas valoir exactement 0. On y reviendra plus tard, parce qu’une solution possible utilise la POO. En attendant, on constate que l’entier 3 et le réel 3 ne sont pas considérés comme égaux par Python :
>>> 3 == 3.0
True
>>> 3 is 3.0
False
C’est donc bien le double égal qui est le plus pratique pour la comparaison de réels, et pas le is.
POO et égalités
Comment comparer deux réels ? On essaye
print(dir(3.0))
et on obtient (sous SofusPy974 en l’occurrence) quelque chose comme
['__eq__', '__ge__', '__gt__', '__le__', '__lt__', '__ne__', 'clone', 'numberCompare', 'toFixed']
montrant qu’il est possible de savoir, respectivement, si un flottant est égal, supérieur ou égal, supérieur, inférieur ou égal, inférieur, ou différent d’un autre flottant, et qu’il est possible de faire ces comparaisons algorithmiquement (pour les nombres décimaux, ces algorithmes sont abordés en cycle 3).
Pour faire de la programmation objet, on a parfois besoin de redéfinir l’égalité, et donc de se poser la question qui entame cet article : quand doit-on considérer comme indistinguables deux objets ? Par exemple dans un annuaire téléphonique, lorsqu’une personne change de numéro de téléphone, elle est quand même toujours la même personne. Si on veut mettre à jour un abonné dans un annuaire, il est prudent de commencer par vérifier si l’abonné est déjà dans l’annuaire. Or en testant ('Dupont','Jean','1/1/1970',01234567) in annuaire on risque de ne pas trouver cet abonné parce que dans l’annuaire il y a bien ('Dupont','Jean','1/1/1970',01222233) mais il ne sera considéré comme égal à l’abonné recherché, que s’il a aussi le même numéro de téléphone, ce qui n’est pas le cas. Ainsi, même pour une recherche dans une liste, il peut s’avérer nécessaire de redéfinir l’égalité.
En SQL, il est obligatoire de choisir des champs qui, à eux tous, constituent une clé primaire, c’est-à-dire qu’il n’y a par exemple pas deux abonnés ayant le même prénom, le même nom et la même date de naissance. En SQL, typiquement, on crée une clé entière déclarée explicitement comme clé primaire.
En Python, la méthode d’égalité est appelée __eq__ (on prononce dundereq) et on peut la surcharger, par exemple au sein d’une classe Reel modélisant les nombres réels :
class Reel(float):
def __init__(self,valeur):
self.v = valeur
def __eq__(self,other):
return abs(self.v-other.v) < 1e-12
def __add__(self,other):
return Reel(self.v+other.v)
def __sub__(self,other):
return Reel(self.v-other.v)
def __mul__(self,other):
return Reel(self.v*other.v)
Le float entre parenthèses évite d’avoir à redéfinir les opérations : a priori, un réel se comporte comme un flottant, sauf mention contraire. La mention contraire porte sur l’égalité, qui est redéfinie comme une égalité à 10-12 près. La première méthode, __init__, permet de donner une valeur à un réel. Cette valeur est un flottant. Les réels fonctionnent mieux que les flottants, concernant l’égalité :
>>> x = Reel(0.3)
>>> y = Reel(0.1) + Reel(0.2)
>>> x == y
True
>>> x
0.3
>>> y
0.30000000000000004
Python possède un module decimal qui peut aussi faire le job :
>>> from decimal import *
>>> x = Decimal('0.3')
>>> y = Decimal('0.1') + Decimal('0.2')
>>> x == y
True
>>> x
Decimal('0.3')
>>> y
Decimal('0.3')
Mais si on veut comparer des hypoténuses calculées par Pythagore, on ne peut pas utiliser ce module, parce que les racines carrées ne sont pas nécessairement des décimaux. On utilisera donc des égalités approchées pour aborder les vecteurs.
Vecteurs et égalité
Dans le projet de programme pour la rentrée 2026, en Seconde, il est prévu, comme exemple d’algorithme, le suivant :
Étudier l’alignement de trois points dans le plan.
Comme, en géométrie, il est également précisé ceci :
Déterminant de deux vecteurs dans une base orthonormée, critère de colinéarité. Application à l’alignement, au parallélisme.
Caractériser alignement et parallélisme par la colinéarité de vecteurs.
Caractérisations de la colinéarité de deux vecteurs non nuls : nullité du déterminant ; proportionnalité des coordonnées.
on voit qu’il va être nécessaire, à un moment ou à un autre, de définir une fonction determinant en Python, et de comparer deux réels (en fait, comparer un réel avec 0).
Vecteurs en Python
Comme le programme précise que le déterminant est une fonction qui, à deux vecteurs, associe un réel, il est nécessaire de voir comment on peut modéliser un vecteur en Python. Le plus simple est de prendre un couple de flottants, mais alors on a ce phénomène :
def déterminant(u,v):
(xu,yu)=u
(xv,yv)=v
return xu*yv-xv*yu
>>> u = (2,3)
>>> v = (0.2,0.3)
>>> déterminant(u,v)
-1.1102230246251565e-16
La nullité (c’est-à-dire l’égalité avec 0) du déterminant est un critère de colinéarité. Or, bien que v soit le dixième de u, il n’est pas considéré comme colinéaire à u.
Colinéarité de deux vecteurs
Deux vecteurs ayant des coordonnées réelles, leur déterminant doit être un réel :
def sont_colinéaires(u,v):
return déterminant(u,v) == 0
>>> sont_colinéaires(u,v)
False
Pour résoudre ce problème on va renoncer à l’égalité stricte et lui préférer une presqu’égalité (à 10-9 près) :
from math import isclose
def sont_colinéaires(u,v):
return isclose(déterminant(u,v),0.0,abs_tol=1e-9)
>>> sont_colinéaires(u,v)
True
Mais cela est peu satisfaisant : si le déterminant de u et v est approximativement nul, u et v sont approximativement colinéaires. Pour faire les choses avec plus de précision, on peut utiliser le calcul formel.
Calcul formel
En Python le calcul formel se fait avec
from sympy import *
Ensuite, on peut redéfinir le vecteur v comme vecteur de fractions :
>>> v = (Integer(2)/10,Integer(3)/10)
>>> v
(1/5, 3/10)
>>> déterminant(u,v)
0
>>> sont_colinéaires(u,v)
True
La précision du calcul formel est infinie :
>>> w = (sqrt(8),sqrt(18))
>>> w
(2*sqrt(2), 3*sqrt(2))
>>> sont_colinéaires(v,w)
True
>>> sont_colinéaires(u,w)
True
Cela peut servir à une découverte des équations de droites, en prenant par exemple un vecteur (x,y) et en charchant s’il est colinéaire avec u :
>>> x,y = symbols('x y')
>>> x
x
>>> y
y
>>> sont_colinéaires(u,(x,y))
False
>>> déterminant(u,(x,y))
-3*x + 2*y
Ils ne sont pas colinéaires, mais le calcul de leur déterminant montre que l’équation de la droite passant par l’origine et de vecteur directeur u, a pour équation
Et pour l’équation de la droite passant par le point de coordonnées (5,4), et dirigée par le vecteur u, on peut tenter :
>>> déterminant(u,(5-x,4-y))
3*x - 2*y - 7
qui donne l’équation .
Cependant, avec le calcul formel, il convient de se demander ce que signifie l’égalité :
>>> (x-2)*(x+2) == x**2-4
False
>>> (x-2)*(x+2)
(x - 2)*(x + 2)
>>> simplify((x-2)*(x+2))
x**2 - 4
Des expressions ne doivent être considérées comme égales, que si leurs versions simplifiées (ici, développées) le sont. Il est donc parfois nécessaire de simplifier des expressions avant de les comparer.



Laisser un commentaire