Héron d’Alexandrie et sa super astuce pour les racines carrées

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é.

  1. Choisir une première valeur d’essai, c’est notre première approximation.
  2. 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« .
  3. Vérifier si c’est assez précis.
  4. 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())


Une réflexion sur “ Héron d’Alexandrie et sa super astuce pour les racines carrées ”

Les commentaires sont fermés