I. Introduction▲
La surcharge d’opérateur permet de redéfinir un opérateur dans une classe.
Par exemple, en Python l’opérateur « + » est surchargé par la classe int et la classe str :
- on peut ainsi réaliser une addition classique entre deux entiers : print(1+2) affiche 3 ;
- ou concaténer deux chaînes de caractères : print("bon"+"jour") renvoie "bonjour".
Notre objectif est de redéfinir dans une classe Pythonune classe Python les opérateurs d'addition, de multiplication et de puissance pour les nombres complexesnombres complexes.
II. Nombres complexes▲
II-A. Définition▲
En mathématiques, l'ensemble des nombres complexes est créé comme extension de l'ensemble des nombres réels, contenant en particulier un nombre imaginaire noté i, tel que i2 = −1. Le carré de (−i) est aussi égal à −1 : (−i)2 = −1.
Tout nombre complexe peut s'écrire sous la forme a + ib où a et b sont des nombres réels.
II-B. Représentation▲
II-B-1. Forme algébrique▲
Un nombre complexe z se présente en général sous forme algébrique comme une somme a + ib,
où a et b sont des nombres réels quelconques
et où i (l’unité imaginaire) est un nombre particulier tel que i2 = –1.
II-B-2. Forme trigonométrique▲
Pour tout couple de réels (a, b) différent du couple (0,0), il existe un réel positif r et une famille d'angles θ déterminés à un multiple de 2π près tels que a = r cos(θ) et b = r sin(θ).
Tout nombre complexe non nul peut donc s'écrire sous une forme trigonométrique :
z = r (cos(θ) + i sin(θ)) avec r > 0.
Le réel positif r est appelé le module du complexe z et il est noté |z|. Le réel θ est appelé un argument du complexe z et il est noté arg(z).
II-B-3. Opérations sur les nombres complexes▲
II-B-3-a. Addition▲
L'addition de 2 nombres complexes z1 = a + ib et z2 = c + id écrits sous forme algébrique, est définie par :
(a + ib) + (c + id) = (a+b) + i(b+d)
II-B-3-b. Multiplication▲
La multiplication de 2 nombres complexes z1 = a + ib et z2 = c + id écrits sous forme algébrique, est définie par :
(a + ib) × (c + id) = (ac - bd) + i(ad + bc)
Pour avoir plus d'informations sur le sujet, je vous invite à consulter la page de Wikipedia Nombre complexeNombre complexe.
III. Création de la classe Complexe▲
Pour définir ces nombres complexes en Python et pouvoir réaliser des opérations entre eux, il nous faut créer une classeclasse Complexe.
Notre classe comportera un constructeurconstructeur, c'est-à-dire une méthode particulière __init__() dont le code est exécuté quand la classe est instanciée.
Elle va nous permettre de définir les parties réelle et imaginaire du nombre complexe au moment de la création de l'objet :
class
Complexe:
def
__init__
(
self, part_reel=
0
, part_imag=
0
): # méthode constructeur de la classe
self.reel =
part_reel # on définit la partie réelle du nombre complexe
self.imag =
part_imag # on définit la partie imaginaire du nombre complexe
def
__str__
(
self): # permet d'afficher le nombre complexe sous la forme algébrique a + bi
return
"{0} + {1}i"
.format
(
self.reel, self.imag) if
self.imag>=
0
else
"{0} - {1}i"
.format
(
self.reel, abs(
self.imag))
La méthode __str__() permet d'afficher un nombre complexe sous la forme a + bi.
Pour tester ces méthodes, nous ajoutons simplement deux lignes au module :
z =
Complexe
(
1
, 2
) # création de l'objet Complexe : 1 + 2i
print
(
z) # affiche le nombre complexe
Le code affiche :
1 + 2i
III-A. Surcharge de l'opérateur d'addition▲
Pour surcharger l'opérateursurcharger l'opérateur « + » et pouvoir ainsi réaliser l'addition de 2 nombres complexes, nous devons ajouter une méthode __add __ () à la classe :
class
Complexe:
def
__init__
(
self, part_reel=
0
, part_imag=
0
): # méthode constructeur de la classe
self.reel =
part_reel # on définit la partie réelle du nombre complexe
self.imag =
part_imag # on définit la partie imaginaire du nombre complexe
def
__str__
(
self): # permet d'afficher le nombre complexe sous la forme algébrique a + bi
return
"{0} + {1}i"
.format
(
self.reel, self.imag) if
self.imag>=
0
else
"{0} - {1}i"
.format
(
self.reel, abs(
self.imag))
def
__add__
(
self, other): # méthode permettant de redéfinir l'opérateur « + » pour 2 nombres complexes : z1 + z2 = (a + bi) + (c + di) = (a+c) + (b+d)i
part_reel =
self.reel +
other.reel # on évalue la partie réelle du nombre complexe résultat de l'addition
part_imag =
self.imag +
other.imag # on évalue la partie imaginaire du nombre complexe résultat de l'addition
return
Complexe
(
part_reel, part_imag) # renvoie le nombre complexe résultat de l'addition
Cette méthode permet donc de redéfinir l'opération « + » pour les nombres complexes en utilisant l'égalité :
(a + bi) + (c + di) = (a+c) + (b+d)i
Pour tester l'opérateur d'addition portant sur 2 objets de la classe Complexe, nous ajoutons simplement ces lignes de code :
z1 =
Complexe
(
1
, 2
) # création du 1er objet de la classe Complexe : 1 + 2i
z2 =
Complexe
(
2
, 3
) # création du 2e objet Complexe : 2 + 3i
print
(
z1+
z2) # affiche le résultat de l'addition
Le code affiche :
3 + 5i
III-B. Surcharge de l'opérateur de multiplication▲
Pour surcharger l'opérateur « * » et l'appliquer à 2 nombres complexes, nous devons également ajouter une méthode __mul __ () à la classe :
class
Complexe:
def
__init__
(
self, part_reel=
0
, part_imag=
0
): # méthode constructeur de la classe
self.reel =
part_reel # on définit la partie réelle du nombre complexe
self.imag =
part_imag # on définit la partie imaginaire du nombre complexe
def
__str__
(
self): # permet d'afficher le nombre complexe sous la forme algébrique a + bi
return
"{0} + {1}i"
.format
(
self.reel, self.imag) if
self.imag>=
0
else
"{0} - {1}i"
.format
(
self.reel, abs(
self.imag))
def
__add__
(
self, other): # méthode permettant de redéfinir l'opérateur « + » pour 2 nombres complexes : z1 + z2 = (a + bi) + (c + di) = (a+c) + (b+d)i
part_reel =
self.reel +
other.reel # on évalue la partie réelle du nombre complexe résultat de l'addition
part_imag =
self.imag +
other.imag # on évalue la partie imaginaire du nombre complexe résultat de l'addition
return
Complexe
(
part_reel, part_imag) # renvoie le nombre complexe résultat de l'addition
def
__mul__
(
self, other): # méthode permettant de redéfinir l'opérateur « * » pour 2 nombres complexes : z1 * z2 = (ac - bd) + (ad + bc)*i
part_reel =
self.reel *
other.reel -
self.imag *
other.imag # part_reel = (ac - bd)
part_imag =
self.reel *
other.imag +
self.imag *
other.reel # part_imag = (ad + bc)
return
Complexe
(
part_reel, part_imag) # renvoie le nombre complexe résultat de la multiplication
Cette méthode offre donc la possibilité de redéfinir l'opération de multiplication pour 2 nombres complexes en utilisant l'égalité :
(a + bi) x (c + di) = (ac - bd) + (ad + bc)i
Pour tester l'opérateur de multiplication portant sur 2 objets de la classe Complexe, nous ajoutons simplement ces lignes :
z1 =
Complexe
(
1
, 2
) # création du 1er objet de la classe Complexe : 1 + 2i
z2 =
Complexe
(
2
, 3
) # création du 2e objet de la classe Complexe : 2 + 3i
print
(
z1*
z2) # affiche le résultat du produit
Le code affiche :
-4 + 7i
III-C. Surcharge de l'opérateur de puissance▲
Maintenant que nous avons redéfini les opérateurs d'addition et de multiplication dans notre classe Complexe, nous pouvons ajouter une méthode __pow__() qui va permettre d'évaluer un nombre complexe z élevé à la puissance n.
class
Complexe:
def
__init__
(
self, part_reel=
0
, part_imag=
0
): # méthode constructeur de la classe
self.reel =
part_reel # on définit la partie réelle du nombre complexe
self.imag =
part_imag # on définit la partie imaginaire du nombre complexe
def
__str__
(
self): # permet d'afficher le nombre complexe sous la forme algébrique a + bi
return
"{0} + {1}i"
.format
(
self.reel, self.imag) if
self.imag>=
0
else
"{0} - {1}i"
.format
(
self.reel, abs(
self.imag))
def
__add__
(
self, other): # méthode permettant de redéfinir l'opérateur « + » pour 2 nombres complexes : z1 + z2 = (a + bi) + (c + di) = (a+c) + (b+d)i
part_reel =
self.reel +
other.reel # on évalue la partie réelle du nombre complexe résultat de l'addition
part_imag =
self.imag +
other.imag # on évalue la partie imaginaire du nombre complexe résultat de l'addition
return
Complexe
(
part_reel, part_imag) # renvoie le nombre complexe résultat de l'addition
def
__mul__
(
self, other): # méthode permettant de redéfinir l'opérateur « * » pour 2 nombres complexes : z1 * z2 = (ac - bd) + (ad + bc)*i
part_reel =
self.reel *
other.reel -
self.imag *
other.imag # part_reel = (ac - bd)
part_imag =
self.reel *
other.imag +
self.imag *
other.reel # part_imag = (ad + bc)
return
Complexe
(
part_reel, part_imag) # renvoie le nombre complexe résultat de la multiplication
def
__pow__
(
self, n): # méthode permettant de redéfinir l'opérateur de puissance : self ** n
z =
Complexe
(
1
,0
) # on initialise la variable objet z avec la valeur 1 élément neutre pour la multiplication de nombres complexes
for
i in
range(
n): # nous multiplions n fois z par self à l'aide de l'opérateur *
z =
z*
self # équivalent à : z = z.__mul__(self)
return
z # renvoie le nombre complexe résultat de l'opération (self ** n)
Nous testons maintenant l'opérateur pour (1 + i) ** 3 :
z =
Complexe
(
1
, 1
)
print
(
z**
3
)
Le code renvoie :
-2 + 2i
Vérification
z3 = (1 + i)3
z3 = (1 + i) × (1 + i) × (1 + i)
En développant et en réduisant le produit des 2 premiers facteurs, on obtient :
z3 = (0 + 2i) × (1 + i)
Enfin, en développant et en réduisant une seconde fois, on a bien :
z3 =-2 + 2i
Tableau de quelques opérateurs et de leur méthode correspondante en Python :
Opérateur |
Expression |
Interprétation Python |
---|---|---|
Addition |
z1 + z2 |
z1.__add__(z2) |
Soustraction |
z1 - z2 |
z1.__sub__(z2) |
Multiplication |
z1 * z2 |
z1.__mul__(z2) |
Puissance |
z1 ** z2 |
z1.__pow__(z2) |
Division |
z1 / z2 |
z1.__truediv__(z2) |
Division entière |
z1 // z2 |
z1.__floordiv__(z2) |
Modulo |
z1 % z2 |
z1.__mod__(z2) |
... |
... |
... |
III-D. Surcharge de l'opérateur de comparaison « == »▲
Pour surcharger l'opérateur « == » et pouvoir ainsi tester si 2 nombres complexes sont égaux, nous ajoutons finalement une méthode __eq__ () à notre classe :
class
Complexe:
def
__init__
(
self, part_reel=
0
, part_imag=
0
): # méthode constructeur de la classe
self.reel =
part_reel # on définit la partie réelle du nombre complexe
self.imag =
part_imag # on définit la partie imaginaire du nombre complexe
#------------------------------------------------------
def
__eq__
(
self, other): # méthode permettant de redéfinir l'opérateur « == » pour 2 nombres complexes
return
(
self.reel==
other.reel) and
(
self.imag==
other.imag) # renvoie True si les parties réelles et imaginaires des 2 nombres complexes sont égales
Cette méthode permet donc de redéfinir l'opérateur de comparaison « == » pour deux nombres complexes en testant si leurs parties réelles et imaginaires sont égales :
z1 =
Complexe
(
1
, 2
) # création du 1er objet de la classe Complexe : 1 + 2i
z2 =
Complexe
(
1
, 2
) # création de 2e objet Complexe : 1 + 2i
print
(
z1==
z2) # affiche le résultat de la comparaison
Le code affiche :
True
Tableau de quelques opérateurs de comparaison et de leur méthode correspondante en Python :
Opérateur |
Expression |
Interprétation Python |
---|---|---|
Inférieur à |
z1 < z2 |
z1.__lt__(z2) |
Inférieur ou égal à |
z1 <= z2 |
z1.__le__(z2) |
Egal |
z1 == z2 |
z1.__eq__(z2) |
... |
... |
... |
Si vous souhaitez avoir une liste plus complète des opérateurs, je vous invite à consulter cette pagepage.
À noter qu'il existe également un module cmathcmath pour Python contenant des fonctions mathématiques pour les nombres complexes.
IV. Conclusion▲
Après avoir défini les opérations d'addition et de multiplication pour les nombres complexes, nous avons pu redéfinir les opérateurs « + », « * » et « ** » dans une classe Python à l'aide de la surcharge d'opérateurs.
Chacun pourra ensuite librement ajouter d'autres opérateurs à la classe Complexe ou bien en créer une autre, basée par exemple sur la représentation trigonométrique des nombres complexes.
V. Module Python▲
Il contient le code complet de la classe Complexe :
VI. Remerciements▲
Je tiens à remercier Malick pour le suivi de cet article, ainsi que escartefigue pour sa relecture.