TP1 🥕 Calcul de racines
À 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
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 :
- Une méthode chiffre par chiffre, par essais successifs
- Une méthode par dichotomie (recherche binaire)
Puis vous devrez :
- Comparer ces méthodes à la fonction standard
math.sqrt
- Étendre le calcul à une racine n-ième
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.
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).
- 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, limites et exceptions possibles.
Voici 2 méthodes brutes pour calculer la racine carrée d'un nombre.
Pour les décrire, supposons que nous cherchons la racine carrée de 8.
On construit le résultat décimale par décimale, en commençant par la plus grande.
Pour 8, on commence donc par l'unité :
- 0² = 0
- 1² = 1
- 2² = 4
- 3² = 9
Comme 8 est entre 4 et 9, on sait que la racine de 8 est entre 2 et 3, car 3² est plus grand que 8. Donc, la racine de 8 ressemble à 2 point quelque chose (ex : 2.0..., 2.1..., ..., 2.9...).
On passe à la première décimale :
- 2.0² = 4
- 2.1² = 4.41
- 2.2² = 4.84
- 2.3² = 5.29
- 2.4² = 5.76
- 2.5² = 6.25
- 2.6² = 6.76
- 2.7² = 7.29
- 2.8² = 7.84
- 2.9² = 8.41
La racine de 8 ressemble donc à 2.8...., car 2.9² est plus grand que 8.
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.
On cherche la racine dans un intervalle [bas, haut] qui se réduit de moitié à chaque étape.
On commence par déterminer l'intervalle initial :
- Si n ≥ 1 : intervalle initial = [0, n]
- Si 0 < n < 1 : intervalle initial = [n, 1]
- Si n = 0 : la racine est 0
- Si n < 0 : la racine n'existe pas dans les réels (on lève une exception)
Par la suite, on va réduire l'intervalle de moitié de la manière suivante :
- On calcule le milieu = (bas + haut) / 2
- Si milieu² est plus petit que n, on déplace bas = milieu
- Si milieu² est plus grand ou égal à n, on déplace haut = milieu
On répète l'opération de réduction de l'intervalle jusqu'à ce que la largeur de l’intervalle (haut - bas) soit inférieure à la précision souhaitée. Dans ce cas, la racine est approximée par (bas + haut) / 2.
Exemple (racine de 8, 3 décimales de précision) On arrête quand la largeur de l’intervalle < 0.001 :
- [0, 8] → largeur = 8 > 0.001 → on continue
- [0, 4] → largeur = 4 > 0.001 → on continue
- [2, 4] → largeur = 2 > 0.001 → on continue …
- [2.828125, 2.8291015625] → largeur = 0.0009765625 < 0.001 → on arrête
Résultat ≈ (2.828125 + 2.8291015625) / 2 = 2.82861328125 ≈ 2.829 (arrondi à 3 décimales).
Pour chacune des deux méthodes, vous devez créer une fonction qui prend un nombre en paramètre et qui retourne sa racine carrée en utilisant cette méthode.
La précision doit être entre 4 et 14 décimales à votre discrétion.
Supérieur à 14 décimales, le calcul prend trop de temps et le programme peut arrêter de fonctionner.
Tester vos 2 fonctions à l'aide d'appel de fonction similaire à ci-dessous.
Lorsque vous obtenez des résultats similaires, retirez ces tests de votre code.
Remarque : les dernières décimales peuvent varier selon le niveau de précision codée dans vos fonctions. Les résultats affichés sont les résultats de math.sqrt()
print(nom_de_la_fonction(0)) # 0.0
print(nom_de_la_fonction(0.1)) # 0.31622776601683794
print(nom_de_la_fonction(0.2)) # 0.4472135954999579
print(nom_de_la_fonction(0.9)) # 0.9486832980505138
print(nom_de_la_fonction(8)) # 2.8284271247461903
print(nom_de_la_fonction(9)) # 3.0
print(nom_de_la_fonction(81)) # 9.0
print(nom_de_la_fonction(123)) # 11.090536506409418
print(nom_de_la_fonction(999)) # 31.606961258558215
print(nom_de_la_fonction(-3)) # Doit lever une exception
Vous allez comparer vos 2 fonctions 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 (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
Pour chacune de vos 2 fonctions, faites-en une copie, nommez-la différemment, et généralisez-la pour qu'elle calcule la
racine n-ième d'un nombre.
Pour cela, vous devez ajouter un paramètre base
à vos nouvelles fonctions (ex. : 2 pour racine carrée, 3 pour racine cubique, etc.).
Il suffit ensuite de faire un changement minime aux 2 algorithmes pour calculer n'importe quelle racine n-ième.
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.
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...