Algorithme de dichotomie
Ce deuxième projet d'approximation numérique va te faire découvrir un algorithme beaucoup plus rapide que le balayage.
Souviens toi du jeu que tu as créé dans le tout premier projet, le juste prix. Quelle était la meilleure stratégie, c'est-à-dire la stratégie qui gagne en général le plus rapidement ?
Le mieux c'est de choisir le centre de l'intervalle. On doit tout d'abord choisir un nombre entre 0 et 100 donc on prend le centre qui est 50. Si ce nombre est trop petit, le nouvel intervalle de recherche est [50; 100]. On choisi ensuite le centre de cet intervalle, ici 75. On continue comme ça jusqu'à trouver le nombre.
Voici un exemple d'une partie utilisant cette stratégie :
| Nombre choisi par le joueur | Réponse ordinateur | Nouvel interval |
|---|---|---|
| Trop petit | ||
| Trop grand | ||
| Trop petit | ||
| C'est ça ! |
- 1
J'ai redéfini la fonction
jeudu juste prix. Appelle-la dans la console et fais une partie en appliquant l'algorithme de dichotomie.Solution
On appelle la fonction
jeuet on suit la procédure décrite dans l'introduction : prendre le milieu de chaque nouvel intervalle de recherche>>> jeu() - 2
Je viens de définir la fonction
fdans ton éditeur. Cette fonction renvoie le carré d'un nombre, et comme dans le projet précédent, nous allons déterminer une approximation de . Par dichotomie cette fois !L'algorithme repose sur la présence d'un intervalle dont on calcule le milieu. Comme on souhaite calculer une approximation de on choisit un intervalle de départ qui contient ce nombre. Par exemple on peut prendre l'intervalle [1; 2]
En-dessous de la fonction
fdéfini une variableainitialisée à 1 et une variablebinitialisée à 2. Ces variables représentent les bornes de l'intervalle de départ dans lequel on recherche l'approximation.Solution
On initialise
aà 1 etbà 2def f(x): return x**2 a = 1 b = 2 - 3
L'algorithme consiste à répéter successivement une même procédure : déterminer l'intervalle de recherche puis prendre son milieu. Il faut donc qu'on utilise une boucle. Comme on ne sait pas à l'avance combien d'étapes sont nécessaires, on utilise une boucle while.
Pour le moment écrivons uniquement le code correspondant à la première itération pour bien comprendre. On ajoutera la boucle while à la prochaine question :
- On commence par calculer le milieu de l'intervalle [a; b].
Crée une variable
met utilise la formule du milieu pour lui assigner comme valeur le centre de l'intervalle [a; b]. - Ensuite il faut déterminer si
mest trop petit ou trop grand et en déduire les nouvelles bornes de l'intervalle de recherche, c'est-à-dire les nouvelles valeurs deaetb.Si
f(m) < 2alorsmest trop petit puisque son carré (le nombref(m)) est inférieur à 2. Dans ce cas, l'intervalle de recherche peut être réduit à[m; b]. Donc il faut réassigner la variableapour qu'elle prenne la même valeur quemen faisanta = mAjoute une instruction conditionnelle qui détermine si
mest trop petit, puis réassigne les bornes de l'intervalle de recherche en conséquence. De même simest trop grand (il faut adapter).
Solution
On commence par créer la variable
m. C'est le milieu de l'intervalle [a;b] doncmvaut 1.5 mais l'idée est d'avoir une formule, car dans la question suivante, la valeur demsera calculée automatiquement à chaque itération.Donc on utilise la formule du milieu
m = (a+b)/2Ensuite l'instruction conditionnelle nous indique si
mest trop petit ou trop grand, ce qui permet de déterminer le nouvel intervalle de rechercheOn utilise la comparaison
f(m)<2pour savoir simest trop petit. Dans ce cas le nouvel intervalle de recherche est [m ; b]. Donc on réassigneaen faisanta = mSinon,
mest trop grand. Alors le nouvel intervalle de recherche est [a;m] et il faut réassignerben faisantb = mdef f(x): return x**2 a = 1 b = 2 m = (a+b)/2 if f(m) < 2: a = m else: b = m - On commence par calculer le milieu de l'intervalle [a; b].
- 4
Nous allons répéter la procédure de la question précédente à chaque itération de l'algorithme. Ainsi, à chaque itération on obtient une nouvelle valeur de
mun peu plus proche du nombre cherché. À la fin du processus, la dernière valeur demobtenue est notre approximation.Nous allons créer une fonction dont le paramètre correspond à la précision de l'approximation recherchée. Ce paramètre va servir pour la condition d'arrêt : tant que l'écart entre
aetbest supérieur à la précision voulue, c'est que l'intervalle de recherche n'est pas assez fin. Donc on fait une itération supplémentaire.Défini une fonction
dichotomiequi dépend d'un argument, le pas. Le corps de cette fonction reprend le code des questions précédentes que tu peux indenter : initialisation deaetbpuis instruction conditionnelle. Enfin indente ton instruction conditionnelle et le calcul demdans le corps d'une boucle while : tant que l'écart entreaetbest supérieur aupas(condition d'arrêt), alors calcule le milieumpuis réassigne les bornes de l'intervalle. N'oublie pas de renvoyermà la fin.Solution
On commence par définir la fonction
dichotomiequi dépend d'un argument, lepas.On indente le code des questions précédentes dans le corps de cette fonction : l'initialisation de
a, debetc.Ensuite on crée une boucle while. Celle-ci s'exécute tant que l'écart entre
aetbest supérieur aupas, donc tant que l'intervalle de recherche est plus large que la précision voulue. Ainsi la condition d'arrêt estb-a > pasLe corps de la boucle while reprend les étapes de la question précédente : calculer le milieu
mde l'intervalle puis déterminer simest trop petit ou trop grand avec une instruction conditionnelle. On reprend le code de la question précédente.À la fin de la fonction on renvoie
mdef f(x): return x**2 def dichotomie(pas): a = 1 b = 2 while b-a > pas: m = (a+b)/2 if f(m) < 2: a = m else: b = m return m - 5
Appelle la fonction
dichotomiedans la console avec différentes valeurs du pas (10**-1,10**-2etc.) pour obtenir des approximations de plus en plus précises deSolution
Lorsque le pas diminue les approximations sont de plus en plus précises.
>>> dichotomie(10**-1) 1.4375 >>> dichotomie(10**-2) 1.4140625 >>> dichotomie(10**-3) 1.4150390625 - 6
Pour comparer la vitesse de calcul de la fonction
dichotomieavec la fonctionbalayagedu précédent projet, nous allons ajouter un compteur.Dans le corps de la fonction
dichotomie, initialise une variablecompteuravant la boucle while avec une valeur de départ de 0. À chaque itération de la boucle while, incrémente cecompteurde 1. Enfin renvoie la valeur du compteur avec l'approximation. Rappel : tu peux renvoyer plusieurs valeurs en les séparant par une virgule. Renvoie le compteur en deuxième.Solution
On initialise la variable
compteurà 0 avant la boucle while. Ensuite on incrémente ce compteur de 1 à chaque itération de la boucle. Enfin on renvoie le compteur avec l'approximationmdef f(x): return x**2 def dichotomie(pas): a = 1 b = 2 compteur = 0 while b-a > pas: compteur = compteur + 1 m = (a+b)/2 if f(m) < 2: a = m else: b = m return m, compteur - 7
Dans le projet précédent, la fonction
balayageavait besoin de 414214 calculs pour trouver une approximation de à près.>>> balayage(10**-6) 1.414213999965924,414214Qu'en est-il de la fonction
dichotomie? Appelle-la dans la console pour voir !Solution
La fonction
dichotomiea besoin de beaucoup moins de calculs que la fonctionbalayage: seulement 20 itérations pour une approximation à , 34 itérations pour une approximations à et 50 itérations pour un pas de !>>> dichotomie(10**-6) 1.4142141342163086,20 >>> dichotomie(10**-10) 1.4142135623260401,34 >>> dichotomie(10**-15) 1.414213562373095,50
Cette stratégie est la plus rapide car à chaque étape l'intervalle de recherche est deux fois plus petit qu'à l'étape précédente. On passe ainsi de l'intervalle [0; 100] à l'intervalle [50; 100] etc.
La procédure à suivre consiste à calculer les bornes de l'intervalle de recherche (initialement 0 et 100), puis à déterminer le centre de cet intervalle, et répéter ces étapes si besoin. Cette procédure porte un nom : c'est l'algorithme de dichotomie
Bonus : comme dans le précédent projet tu peux adapter ton code pour déterminer d'autres approximations.
Par exemple tu peux modifier le code de la fonction f
pour calculer des approximations numériques de . Vérifie quand même
s'il ne faut pas ajuster l'initialisation des variables a et b sinon
tu risques une boucle infinie.
En terme de complexité, l'algorithme de dichotomie fait partie de la famille des algorithmes les plus rapides possibles. C'est un incontournable !