Aller au contenu principal

TP1 đŸ„• Calcul de racines

🧠 Contexte

Un ordinateur, c’est trĂšs rapide, mais pas trĂšs intelligent. On va en profiter pour lui faire calculer la racine carrĂ©e
 de façon trĂšs bĂȘte.

Vous devez implĂ©menter deux mĂ©thodes de calcul « brutales » d’une racine carrĂ©e :

  1. Une méthode chiffre par chiffre, par essais successifs
  2. Une méthode par dichotomie (recherche binaire)

Puis vous devrez :

  • Comparer ces mĂ©thodes Ă  la fonction standard math.sqrt() en termes de performance
  • Étendre le calcul Ă  une racine n-iĂšme
🎯 Objectifs pĂ©dagogiques

À la fin de ce travail, vous serez capable de :

  • Utiliser des variables, types de base, opĂ©rateurs et fonctions
  • Utiliser des structures conditionnelles et expressions logiques
  • Utiliser des structures rĂ©pĂ©titives
  • DĂ©composer un algorithme en fonctions rĂ©utilisables
  • Évaluer la performance d’un algorithme avec des mesures de temps
  • Appliquer la logique pour rĂ©soudre un problĂšme numĂ©rique complexe sans bibliothĂšque
  • Valider le fonctionnement de vos algorithmes Ă  l'aide de jeux d'essais
Créer le projet

Pour faire ce TP, vous devez créer un nouveau projet PyCharm et utiliser un répertoire GitHub dÚs le début.

  • Si votre enseignant utilise GitHub Classroom, utilisez le rĂ©pertoire créé par votre enseignant.
  • Si votre enseignant n'utilise pas GitHub Classroom, crĂ©ez votre propre rĂ©pertoire et partagez-lui l'accĂšs en lecture.
Plagiat

â—đŸ€– 👀 đŸš«

Si votre travail est suspecté de plagiat (code copié d'un.e autre étudiant.e, code généré par IA, notions non abordées en classe, etc.), deux choses peuvent se produire :

  • Le plagiat est prouvĂ© par nos outils : note de 0, automatiquement.
  • Le plagiat est plutĂŽt Ă©vident, mais une validation est requise : vous serez convoquĂ©(e) au bureau de votre enseignant(e). Vous devrez rĂ©pondre Ă  certaines questions pour prouver que vous comprenez et maĂźtrisez le code qui a Ă©tĂ© utilisĂ©. Si vous ne rĂ©ussissez pas Ă  rĂ©pondre Ă  certaines questions, vous aurez la note de 0 (si vous ne comprenez pas votre propre code, c'est que vous avez plagiĂ©, d'une maniĂšre ou d'une autre).
1 point RĂ©pertoire Git 🐈‍⬛ et documentation des fonctions
  • Au moins 5 commits de tailles comparables (il n'y a pas un commit avec tout dedans et les autres vides)
  • Les commits dĂ©crivent l'avancement du projet dans un français sans faute (voir instructions)
  • Chaque fonction doit ĂȘtre documentĂ©e Ă  l'aide d'un docstring dans un français sans faute : description de la fonction, paramĂštres, valeur retournĂ©e, exceptions possibles, etc.
  • Votre projet doit contenir exactement 3 scripts Python et rien d'autre :
tp1/
├── racine.py # doit contenir vos 2 fonctions pour les 2 mĂ©thodes diffĂ©rentes du calcul de la racine carrĂ©e
├── validation.py # doit contenir vos tests validant le bon fonctionnement des fonctions du module "racine.py"
└── performance.py # doit contenir vos tests de performance des fonctions du module "racine.py"
6 points 🔧 Calculer la racine carrĂ©e « Ă  la main »

Dans le script racine.py, vous devez créer 2 fonctions, soit une pour chacune des deux méthodes du calcul de la racine carrée d'un nombre.
Pour décrire ces méthodes de calcul, supposons que nous cherchons la racine carrée de 88.

➀ MĂ©thode 1 : Chiffre par chiffre

On construit le résultat décimale par décimale, en commençant par la plus grande.

Pour 88, on commence donc par l'unité :

  • 02=00^2 = 0
  • 12=11^2 = 1
  • 22=42^2 = 4
  • 32=93^2 = 9

Comme 88 est entre 44 et 99, on sait que la racine de 88 est entre 22 et 33, car 323^2 est plus grand que 88. Donc, la racine de 88 ressemble Ă  22 point quelque chose (ex : 2.0...,2.1...,...,2.9...2.0..., 2.1..., ..., 2.9...).

On passe à la premiÚre décimale :

  • 2.02=42.0^2 = 4
  • 2.12=4.412.1^2 = 4.41
  • 2.22=4.842.2^2 = 4.84
  • 2.32=5.292.3^2 = 5.29
  • 2.42=5.762.4^2 = 5.76
  • 2.52=6.252.5^2 = 6.25
  • 2.62=6.762.6^2 = 6.76
  • 2.72=7.292.7^2 = 7.29
  • 2.82=7.842.8^2 = 7.84
  • 2.92=8.412.9^2 = 8.41

La racine de 88 ressemble donc Ă  2.8....2.8...., car 2.922.9^2 est plus grand que 88.

Et on fait ainsi de suite pour les dĂ©cimales suivantes. On fait des essais successifs pour chaque dĂ©cimale jusqu’à la prĂ©cision dĂ©sirĂ©e.

➀ MĂ©thode 2 : Dichotomie

On cherche la racine dans un intervalle [bas,haut][\text{bas}, \text{haut}] qui se réduit de moitié à chaque étape.

On commence par déterminer l'intervalle initial :

Si{n≄1:intervalle initial=[0,n],0<n<1:intervalle initial=[n,1],n=0:racine=0,n<0:non deˊfini dans R :on leˋve une exception.\text{Si} \begin{cases} n \ge 1 : & \text{intervalle initial} = [0, n],\\ 0 < n < 1 : & \text{intervalle initial} = [n, 1],\\ n = 0 : & \text{racine} = 0,\\ n < 0 : & \text{non dĂ©fini dans } \mathbb{R}\ : \text{on lĂšve une exception}. \end{cases}

Par la suite, on va réduire l'intervalle de moitié de la maniÚre suivante :

  • On calcule le milieu=bas+haut2\text{milieu} = \frac{\text{bas} + \text{haut}}{2}, puis :
Si{milieu2<n:on deˊplace bas = milieu,milieu2≄n:on deˊplace haut = milieu.\text{Si} \begin{cases} \text{milieu}^2 < n: & \text{on dĂ©place bas = milieu},\\ \text{milieu}^2 \ge n: & \text{on dĂ©place haut = milieu}. \end{cases}

On rĂ©pĂšte l'opĂ©ration de rĂ©duction de l'intervalle jusqu'Ă  ce que la largeur de l’intervalle (haut−bas\text{haut} - \text{bas}) soit infĂ©rieure Ă  la prĂ©cision souhaitĂ©e. À ce moment, la racine est approximĂ©e par bas+haut2\frac{\text{bas} + \text{haut}}{2}.

Exemple (racine de 88, avec 33 décimales de précision)
On arrĂȘte quand la largeur de l’intervalle <0.001< 0.001 :

  • [0,8][0, 8] → largeur=8≄0.001\text{largeur} = 8 \ge 0.001 → on continue
  • [0,4][0, 4] → largeur=4≄0.001\text{largeur} = 4 \ge 0.001 → on continue
  • [2,4][2, 4] → largeur=2≄0.001\text{largeur} = 2 \ge 0.001 → on continue
  • ...
  • [2.828125,2.8291015625][2.828125, 2.8291015625] → largeur=0.0009765625<0.001\text{largeur} = 0.0009765625 < 0.001 → on arrĂȘte

RĂ©sultat ≈2.828125+2.82910156252=2.82861328125≈2.829\approx \frac{2.828125 + 2.8291015625}{2} = 2.82861328125 \approx 2.829 (arrondi Ă  33 dĂ©cimales).

Les 2 fonctions doivent prendre un seul paramÚtre, un nombre, et retourner sa racine carrée.

La prĂ©cision doit ĂȘtre entre 4 et 12 dĂ©cimales Ă  votre discrĂ©tion.
SupĂ©rieur Ă  12 dĂ©cimales, le calcul peut prendre trop de temps et le programme peut arrĂȘter de fonctionner.
Mettez la précision de votre choix dans une variable globale constante (ex : PRECISION = 8), avant vos définitions de fonctions.

GARDER LE MODULE RACINE PROPRE

Votre module racine doit contenir uniquement ces 2 fonctions et aucune instruction dans ce module ne doit ĂȘtre placĂ©e Ă  l'extĂ©rieur de ces 2 fonctions (sauf la constante).

✅ Tests attendus

Dans le script validation.py, importez le module racine puis tester vos 2 fonctions Ă  l'aide d'appels de fonction similaires Ă  ceux-ci :

try:
print("*** VÉRIFICATION DU BON FONCTIONNEMENT ***")
print("attendu : 0.0 ")
print(" obtenu :", racine.nom_de_la_fonction(0))
print("attendu : 0.31622776601683794")
print(" obtenu :", racine.nom_de_la_fonction(0.1))
print("attendu : 0.4472135954999579")
print(" obtenu :", racine.nom_de_la_fonction(0.2))
print("attendu : 0.9486832980505138")
print(" obtenu :", racine.nom_de_la_fonction(0.9))
print("attendu : 2.8284271247461903")
print(" obtenu :", racine.nom_de_la_fonction(8))
print("attendu : 3.0")
print(" obtenu :", racine.nom_de_la_fonction(9))
print("attendu : 9.0")
print(" obtenu :", racine.nom_de_la_fonction(81))
print("attendu : 11.090536506409418")
print(" obtenu :", racine.nom_de_la_fonction(123))
print("attendu : 31.606961258558215")
print(" obtenu :", racine.nom_de_la_fonction(999))
print(nom_de_la_fonction(-3)) # Doit lever une exception
except e as Exception:
print(f"erreur {e}")

Remarque : les résultats attendus affichés sont les résultats de math.sqrt().
Assurez-vous pour tous les tests que les décimales obtenues sont les bonnes et les arrondis sont cohérents selon votre niveau de précision.
Voici 2 exemples d'erreurs :

    attendu : 2.8284271247461903
obtenu : 2.82842 # Mauvaise rĂ©ponse, car le dernier 2 aurait dĂ» ĂȘtre un 3

attendu : 2.8284271247461903
obtenu : 2.8284265122345312 # Mauvaise réponse, car certaines décimales sont fausses
2 points 📈 Comparaison des performances

Dans le script performance.py, vous allez comparer vos 2 fonctions du module racine avec la fonction math.sqrt() pour comparer leurs performances.

Pour chacune des 3 méthodes (fonction 1, fonction 2, math.sqrt()) vous devez :

  • À l'aide d'une boucle, appeler la fonction 100 000 fois avec un nombre flottant alĂ©atoire
    • Utilisez un nombre flottant alĂ©atoire diffĂ©rent Ă  chaque appel
    • Les nombres flottants gĂ©nĂ©rĂ©s doivent ĂȘtre compris entre 10 et 10 000
  • Calculer le temps total nĂ©cessaire pour rĂ©aliser les 100 000 appels (en ms)
  • Afficher :
    • Le temps de calcul total pour les 100 000 appels (en millisecondes)
    • Le temps moyen par appel de la fonction

Exemple d'affichage attendu (les valeurs sont fictives) :

Résultats des performances :
Méthode 1 (chiffre par chiffre) : Temps total = 150 ms, Temps moyen = 0.0015 ms
Méthode 2 (dichotomie) : Temps total = 50 ms, Temps moyen = 0.0005 ms
Méthode 3 (math.sqrt) : Temps total = 10 ms, Temps moyen = 0.0001 ms
1 point đŸŒ± GĂ©nĂ©raliser Ă  une racine n-iĂšme

Vous devez transformer vos 2 fonctions du module racine afin qu'elles puissent calculer la racine n-iĂšme d'un nombre.

Pour cela :

  • Vous devez ajouter un paramĂštre base Ă  vos fonctions (ex. : 2 pour racine carrĂ©e, 3 pour racine cubique, etc.). Ce paramĂštre doit ĂȘtre optionnel et avoir par dĂ©faut la valeur 2.
  • La racine carrĂ©e d'un nombre nĂ©gatif doit ĂȘtre possible uniquement si la base est impaire (ex. : la racine cubique de -27 est -3), sinon une exception doit encore ĂȘtre levĂ©e.
  • La valeur du paramĂštre base ne doit pas ĂȘtre infĂ©rieure Ă  2 (validation de la valeur passĂ©e en paramĂštre nĂ©cessaire).

Appelez chacune de ces 2 nouvelles fonctions et affichez les résultats pour la racine carrée, cubique et quatriÚme de 8, 9, 81 et 123.

try:
print("*** RACINE DEUX ***")
print("attendu : 2.8284271247461903")
print(" obtenu :", racine.nom_de_la_fonction(8,2))
print("attendu : 3.0")
print(" obtenu :", racine.nom_de_la_fonction(9,2))
print("attendu : 9.0")
print(" obtenu :", racine.nom_de_la_fonction(81,2))
print("attendu : 11.090536506409418")
print(" obtenu :", racine.nom_de_la_fonction(123,2))

print("*** RACINE CUBIQUE ***")
print("attendu : 2.0")
print(" obtenu :", racine.nom_de_la_fonction(8,3))
print("attendu : 2.080083823051904")
print(" obtenu :", racine.nom_de_la_fonction(9,3))
print("attendu : 4.3267487109222245")
print(" obtenu :", racine.nom_de_la_fonction(81,3))
print("attendu : 4.97318983326859")
print(" obtenu :", racine.nom_de_la_fonction(123,3))

print("*** RACINE QUATRIEME ***")
print("attendu : 1.681792830507429")
print(" obtenu :", racine.nom_de_la_fonction(8,4))
print("attendu : 1.7320508075688772")
print(" obtenu :", racine.nom_de_la_fonction(9,4))
print("attendu : 3.0")
print(" obtenu :", racine.nom_de_la_fonction(81,4))
print("attendu : 3.3302457126178266")
print(" obtenu :", racine.nom_de_la_fonction(123,4))
except e as Exception:
print(f"erreur {e}")

Fonctionnement global 2 points négatifs

Le projet fonctionne sans plantage et correctement, et le code est clair et facile à lire. Ce pointage fonctionne en négatif. Si le projet fonctionne correctement en tout temps, vous conservez votre note. Dans le cas contraire, vous perdez des points avec un maximum de 2.

  • Plantage -1 point
  • Code illisible -1 point
  • Information affichĂ©e incohĂ©rente -1 point
  • Autre cas...