par , 01/02/2022 à 08h50 (3313 Affichages)
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 Python, les opérateurs d'addition, de multiplication et de puissance pour les nombres complexes.
I. Nombres complexes
I-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.
I-B. Représentation
I-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.
I-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 est noté |z|.
Le réel θ est appelé un argument du complexe z et est noté arg(z).
I-C. Opérations sur les nombres complexes
I-C-1. Addition
L'addition de 2 nombres complexes z1 = a + ib et z2 = c + id écrits sous forme algébrique, est définie de la manière suivante :
(a + ib) + (c + id) = (a+b) + i(b+d)
I-C-2. Multiplication
La multiplication de 2 nombres complexes z1 = a + ib et z2 = c + id, 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 complexe.
II. 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 classe Complexe.
Notre classe comportera un constructeur, 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 :
1 2 3 4 5 6 7 8
| 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 :
1 2
| z = Complexe(1, 2) # création de l'objet Complexe : 1 + 2i
print(z) # affiche le nombre complexe |
Le code affiche :
1 + 2i
II-A. Surcharge de l'opérateur d'addition
Pour surcharger l'opérateur « + » et pouvoir ainsi réaliser l'addition de 2 nombres complexes, nous devons ajouter une méthode __add __ () à la classe :
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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 :
1 2 3 4
| z1 = Complexe(1, 2) # création du 1er objet de la classe Complexe : 1 + 2i
z2 = Complexe(2, 3) # création de 2e objet Complexe : 2 + 3i
print(z1+z2) # affiche le résultat de l'addition |
Le code affiche :
3 + 5i
II.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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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 :
1 2 3 4
| 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
II-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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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 :
1 2
| 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 ** n |
z1.__pow__(n) |
Division |
z1 / z2 |
z1.__truediv__(z2) |
Division entière |
z1 // z2 |
z1.__floordiv__(z2) |
Modulo |
z1 % z2 |
z1.__mod__(z2) |
... |
... |
... |
II-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 :
1 2 3 4 5 6 7 8 9 10
| 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 :
1 2 3 4
| 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 page .
A noter qu'il existe également un module cmath pour Python contenant des fonctions mathématiques pour les nombres complexes.
III. 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.
Sources :
https://fr.wikipedia.org/wiki/Nombre_complexe
https://python.developpez.com/tutori...s/?page=classe
https://allen-downey.developpez.com/...methodes#L17-7
https://www.programiz.com/python-pro...or-overloading
https://fr.acervolima.com/surcharge-...urs-en-python/