La création d'une calculatrice est un exercice classique pour mettre en pratique les concepts fondamentaux de la programmation, tels que les structures de contrôle et la logique. Ce projet a été réalisé en plusieurs étapes pour en enrichir progressivement les fonctionnalités.
Phase initiale : Opérations de base avec interaction utilisateur
La première version consistait en un script permettant d'effectuer des opérations simples (addition, soustraction, multiplication, division, logarithme) sur deux nombres. Le choix entre nombres réels et complexes était proposé à l'utilisateur. Une boucle permettait de répéter l'opération.
import math
def effectuer_addition(a, b):
return a + b
def effectuer_soustraction(a, b):
return a - b
def effectuer_multiplication(a, b):
return a * b
def effectuer_division(a, b):
if b == 0:
print("Division par zéro impossible.")
return None
return a / b
def calculer_logarithme(base, argument):
if base <= 0 or argument <= 0:
print("Les valeurs doivent être positives pour le logarithme.")
return None
return math.log(argument, base)
mode_actif = True
while mode_actif:
type_nombre = input("Calcul avec (1) nombres complexes ou (2) réels ?\n")
if type_nombre == "1":
premier = complex(input("Entrez le premier nombre : "))
deuxieme = complex(input("Entrez le deuxième nombre : "))
else:
premier = float(input("Entrez le premier nombre : "))
deuxieme = float(input("Entrez le deuxième nombre : "))
operateur = input("Choisissez l'opérateur (+, -, *, /, log) : ")
resultat = None
if operateur == "+":
resultat = effectuer_addition(premier, deuxieme)
elif operateur == "-":
resultat = effectuer_soustraction(premier, deuxieme)
elif operateur == "*":
resultat = effectuer_multiplication(premier, deuxieme)
elif operateur == "/":
resultat = effectuer_division(premier, deuxieme)
elif operateur == "log":
resultat = calculer_logarithme(premier, deuxieme)
if resultat is not None:
print(f"Résultat : {premier} {operateur} {deuxieme} = {resultat}")
suite = input("Effectuer un autre calcul ? (O/N)\n")
if suite.upper() != "O":
mode_actif = False
Évolution : Saisei d'expressions multiples et chaînées
Pour améliorer l'ergonomie, la version suivante a permis de saisir une séquence de nombres et d'opérateurs jusqu'à rencontrer le signe '='. Le calcul s'effectuait alors séquentiellement, de gauche à droite.
import math
# ... (Les fonctions d'opération sont identiques à la version précédente)
calcul_en_cours = True
while calcul_en_cours:
liste_nombres = []
liste_operations = []
type_mode = input("Mode (1) complexe, (2) réel ?\n")
if type_mode == "1":
while True:
val = complex(input())
op = input()
liste_nombres.append(val)
liste_operations.append(op)
if op == "=":
break
else:
while True:
val = float(input())
op = input()
liste_nombres.append(val)
liste_operations.append(op)
if op == "=":
break
accumulateur = liste_nombres[0]
compteur = 1
while compteur < len(liste_operations):
op_courante = liste_operations[compteur - 1]
if op_courante == "=":
break
valeur_suivante = liste_nombres[compteur]
if op_courante == "+":
accumulateur = effectuer_addition(accumulateur, valeur_suivante)
elif op_courante == "-":
accumulateur = effectuer_soustraction(accumulateur, valeur_suivante)
elif op_courante == "*":
accumulateur = effectuer_multiplication(accumulateur, valeur_suivante)
elif op_courante == "/":
accumulateur = effectuer_division(accumulateur, valeur_suivante)
elif op_courante == "log":
accumulateur = calculer_logarithme(accumulateur, valeur_suivante)
compteur += 1
print(f"Résultat final : {accumulateur}")
reprendre = input("Nouveau calcul ? (O/N)\n")
calcul_en_cours = reprendre.upper() == "O"
Version finale : Gestion des priorités opératoires
L'étape cruciale a été d'implémenter la priorité des opérateurs (multiplication et division avant addition et soustraction). Cela a nécessité la conception d'un algorithme d'évaluation en deux passes.
import math
# ... (Les fonctions d'opération restent similaires)
def evaluer_expression(nombres, operateurs):
"""Évalue une expression en respectant les priorités."""
# Première passe : traiter les opérations à haute priorité (*, /, log)
index = 0
while index < len(operateurs):
op = operateurs[index]
if op in ('*', '/', 'log'):
val_gauche = nombres[index]
val_droite = nombres[index + 1]
resultat_intermediaire = None
if op == '*':
resultat_intermediaire = effectuer_multiplication(val_gauche, val_droite)
elif op == '/':
resultat_intermediaire = effectuer_division(val_gauche, val_droite)
elif op == 'log':
resultat_intermediaire = calculer_logarithme(val_gauche, val_droite)
# Remplacer les deux opérandes et l'opérateur par le résultat
nombres[index] = resultat_intermediaire
del nombres[index + 1]
del operateurs[index]
# Ne pas incrémenter l'index car les listes ont été réduites
else:
index += 1
# Deuxième passe : calculer les opérations restantes (+, -)
resultat_final = nombres[0]
for i in range(len(operateurs)):
operande = nombres[i + 1]
op = operateurs[i]
if op == '+':
resultat_final = effectuer_addition(resultat_final, operande)
elif op == '-':
resultat_final = effectuer_soustraction(resultat_final, operande)
return resultat_final
session_active = True
while session_active:
liste_val = []
liste_op = []
mode = input("Mode (1) complexe, (2) réel ?\n")
try:
if mode == "1":
while True:
nombre = complex(input())
operation = input()
liste_val.append(nombre)
liste_op.append(operation)
if operation == "=":
break
else:
while True:
nombre = float(input())
operation = input()
liste_val.append(nombre)
liste_op.append(operation)
if operation == "=":
break
# On passe des copies pour ne pas altérer les listes originales
expression_val = liste_val.copy()
expression_op = liste_op[:-1].copy() # On exclut le '=' final
resultat = evaluer_expression(expression_val, expression_op)
print(f"Résultat de l'expression : {resultat}")
except (ValueError, ZeroDivisionError, TypeError) as e:
print(f"Erreur dans le calcul ou la saisie : {e}")
except IndexError:
print("Expression mal formée.")
continuation = input("Continuer ? (O/N)\n")
if continuation.upper() != 'O':
session_active = False
Un point d'apprentissage important a été le placement de l'initialisation de l'index à l'intérieur de la boucle principale pour chaque nouveau calcul, sinon les calculs itératifs produisaient des errreurs. De plus, l'utilisation de blocs try...except s'est avérée essentielle pour gérer proprement les erreurs de saisie (ValueError) et les erreurs de calcul (ZeroDivisionError).