Héron d’Alexandrie, c’était un peu le MacGyver de l’Antiquité : ingénieur, mécanicien, mathématicien, il savait tout faire (sauf peut-être poster sur TikTok).
Il a vécu au 1er siècle après J.-C., en pleine époque romaine, mais dans l’ambiance grecque d’Alexandrie. On sait qu’il était contemporain de Pline l’Ancien (celui qui écrivait des encyclopédies avant que Wikipédia existe).
Son coup de génie ? Une méthode simple et efficace pour calculer une racine carrée à la main. Aujourd’hui, on la refait en Python pour le plaisir ! 🐍
La méthode de Héron (simplifiée)
voici une méthode pour déterminer une approximation d’un nombre x donné.
- Choisir une première valeur d’essai, c’est notre première approximation.
- Amélioration de la valeur de l’approximation : elle vaudra la moyenne entre la valeur précédente notée essai et la quotient «
x/essai« . - Vérifier si c’est assez précis.
- Recommencer tant que ce n’est pas bon.
Et hop, on obtient une approximation de √x !
Passons à la pratique en Python !
Question 1
👉 Comment écrire une fonction moyenne qui calcule la moyenne de deux nombres donnés ?
indication : moyenne(a, b) calcule et retourne la moyenne des deux nombres réels a et b.
la première ligne de code sera :
- def moyenne(a: float, b: float) -> float:
Question 2
👉 Comment coder une fonction valeur_absolue qui retourne la valeur absolue d’un nombre (sans utiliser abs) ?
indication : la première ligne de code sera : def valeur_absolue(x: float) -> float:
Question 3
👉 Comment écrire une fonction puissance qui calcule x^n sans utiliser ** ni pow ?
indication : on pourra vérifier notre fonction avec les assertions suivantes :
assert puissance(2, 8) == 256
assert puissance(0, 2) == 0
assert puissance(3, 0) == 1
Question 4
👉 Comment améliorer un essai en prenant la moyenne entre l’essai et x/essai ?
indication : on pourra vérifier notre fonction avec :
assert amelioration_essai(1, 2) == 1.5
assert amelioration_essai(2, 1) == 1.25
Question 5
👉 Comment savoir si un essai est « suffisamment bon », c’est-à-dire si |essai² – x| < 0.001 ?
indication : on pourra vérifier notre travail avec les assertions suivantes :
assert est_suffisamment_bon(1.9, 4) == False
assert est_suffisamment_bon(1.999, 4) == False
assert est_suffisamment_bon(1.9999, 4) == True
Question 6
👉 Comment utiliser ces briques pour écrire la fonction test qui implémente l’algorithme complet de Héron ?
indication : on pourra vérifier notre travail avec les assertions suivantes :
assert test(2, 4) == 2
assert test(1, 4) == 2.0000000929222947
assert test(7, 4) == 2.0000000271231317
Question 7
👉 Comment simplifier l’appel précédent avec une fonction racine_carree qui démarre toujours avec essai = 1 ?
indication : on pourra vérifier notre travail avec les assertions suivantes :
assert racine_carree(4) == 2.0000000929222947
assert racine_carree(9) == 3.00009155413138
assert racine_carree(16) == 4.000000636692939
Question 8
👉 Enfin, comment afficher la liste des racines carrées de tous les nombres pairs entre 1 et 100 ?
indication : on utilisera une fonction main qui va créer une liste par compréhension avec la fonction de la question précédente.
🎉 Conclusion
Grâce à Héron, on calcule des racines carrées à l’ancienne, mais en mode Python moderne.
Un joli mélange entre l’Antiquité et le numérique : pas mal pour un type qui vivait 2000 ans avant nos ordinateurs !
Solutions
Question 1
def moyenne(a: float, b: float) -> float:
"""
Calcule et retourne la moyenne des deux nombres a et b.
"""
return (a + b) / 2
# Tests
assert moyenne(12, 16) == 14
assert moyenne(0, 8) == 4
Question 2
def valeur_absolue(x: float) -> float:
"""
Calcule et retourne la valeur absolue du nombre x.
"""
if x >= 0:
return x
else:
return -x
# Tests
assert valeur_absolue(3) == 3
assert valeur_absolue(0) == 0
assert valeur_absolue(-3) == 3
Question 3
def puissance(x: float, n: int) -> float:
"""
Calcule et retourne le résultat de x^n = x . x . ... . x (n fois).
"""
res = 1
for _ in range(1, n + 1):
res *= x
return res
# Tests
assert puissance(2, 8) == 256
assert puissance(0, 2) == 0
assert puissance(3, 0) == 1
Question 4
def amelioration_essai(essai: float, x: float) -> float:
"""
Calcule et retourne la moyenne entre essai (strictement positif) et x/essai.
"""
return moyenne(essai, x/essai)
# Tests
assert amelioration_essai(1, 2) == 1.5
assert amelioration_essai(2, 1) == 1.25
Question 5
def est_suffisamment_bon(essai: float, x: float) -> bool:
"""
Retourne True si |essai^2 - x| < 0.001.
"""
tolerance = 0.001
return valeur_absolue(puissance(essai, 2) - x) < tolerance
# Tests
assert est_suffisamment_bon(1.9, 4) == False
assert est_suffisamment_bon(1.999, 4) == False
assert est_suffisamment_bon(1.9999, 4) == True
Question 6
def test(essai: float, x: float) -> float:
"""
Retourne la racine carrée de x en partant d'une valeur d'essai.
"""
while not est_suffisamment_bon(essai, x):
essai = amelioration_essai(essai, x)
return essai
# Tests
assert test(2, 4) == 2
assert test(1, 4) == 2.0000000929222947
assert test(7, 4) == 2.0000000271231317
Question 7
def racine_carree(x: float) -> float:
"""
Retourne la racine carrée de x en utilisant 1 comme valeur d'essai initiale.
"""
return test(1, x)
# Tests
assert racine_carree(4) == 2.0000000929222947
assert racine_carree(9) == 3.00009155413138
assert racine_carree(16) == 4.000000636692939
Question 8
def main():
return [racine_carree(i) for i in range(1, 101) if i % 2 == 0]
print(main())
Ping : Terminale NSI 2025-26 – Maths & Informatique