1. Cours
Le chapitre d'algorithmique n'introduit aucune notion nouvelle : les variables, les boucles, les conditions, les fonctions et les listes sont ceux de la fiche 15A. Ce qui change, c'est l'usage : le programme officiel cite, chapitre par chapitre, des algorithmes à savoir mettre en œuvre. Les voici tous, groupés par domaine, avec le programme Python qui les réalise, ce qu'ils calculent, et le renvoi vers la fiche du chapitre concerné.
Les sept algorithmes en un coup d'œil
| Algorithme | Ce qu'il calcule | Boucle | Chapitre |
|---|---|---|---|
| Recherche de seuil | le premier rang qui franchit un seuil | non bornée | suites |
| Dichotomie | un encadrement de la solution de \(f(x)=0\) | non bornée | continuité |
| Newton | une valeur approchée de cette solution | bornée | dérivation |
| Euler | une solution approchée d'une équation différentielle | bornée | exponentielle, équations différentielles |
| Rectangles | un encadrement d'une intégrale | bornée | calcul intégral |
| Simulation, marche aléatoire | des observations d'une variable aléatoire | bornée | probabilités |
| Fréquence contre majoration | compare une probabilité simulée à la borne de Bienaymé-Tchebychev | bornée | concentration |
Le tableau se lit aussi à l'envers : on ne sait pas combien de tours \(\Rightarrow\) boucle non bornée while ; on sait combien de tours \(\Rightarrow\) boucle bornée for. C'est le sujet de la méthode A.
1Recherche de seuil — les suites
On connaît une suite \((u_n)\) et un seuil \(S.\) La question est : à partir de quel rang a-t-on \(u_n\geqslant S\) ? On ne sait pas d'avance combien de tours il faudra : c'est exactement ce qu'on cherche, donc la boucle est non bornée.
En langage naturel (celui des énoncés du bac), pour \(u_0=1\) et \(u_{n+1}=2u_n\) :
- \(u \leftarrow 1\) et \(n \leftarrow 0\) ;
- tant que \(u < S\) : \(u \leftarrow 2\times u\), puis \(n \leftarrow n+1\) ;
- afficher \(n.\)
La même chose en Python, écrite comme une fonction réutilisable, avec le premier terme, la raison et le seuil en paramètres :
def seuil(u0, q, S):
u = u0
n = 0
while u < S:
u = q * u
n = n + 1
return n
print(seuil(1, 2, 1000))
Contrôle à la main : \(2^9=512<1000\) et \(2^{10}=1024\geqslant1000\), donc le premier rang qui atteint \(1000\) est bien \(10.\)
2Dichotomie — continuité et valeurs intermédiaires
Le théorème des valeurs intermédiaires garantit qu'une fonction continue qui change de signe entre \(a\) et \(b\) s'annule quelque part entre les deux. Il ne dit pas où. La dichotomie le trouve : on coupe l'intervalle en deux, on garde la moitié où le changement de signe subsiste, et on recommence.
Le principe. On suppose \(f\) continue sur \([a\,;b]\) avec \(f(a)\) et \(f(b)\) de signes contraires. On pose \(m=\dfrac{a+b}{2}\), puis :
- si \(f(a)\) et \(f(m)\) sont de signes contraires, la solution est dans \([a\,;m]\) : on remplace \(b\) par \(m\) ;
- sinon elle est dans \([m\,;b]\) : on remplace \(a\) par \(m.\)
Dans les deux cas l'intervalle est deux fois plus court et contient toujours une solution.
def f(x):
return x**3 + x - 1
def dichotomie(a, b, e):
n = 0
while b - a > e:
m = (a + b) / 2
if f(a) * f(m) <= 0:
b = m
else:
a = m
n = n + 1
return a, b, n
print(dichotomie(0, 1, 0.001))
La solution \(\alpha\) de \(x^3+x-1=0\) vérifie donc \(0{,}681640625 < \alpha < 0{,}6826171875\), et il a fallu \(10\) étapes. Les deux bornes affichées sont exactes : ce sont les fractions \(\dfrac{698}{1024}\) et \(\dfrac{699}{1024}.\)
Combien d'étapes pour une précision \(e\) ? Après \(n\) coupes, l'intervalle a pour longueur \(\dfrac{b-a}{2^n}.\) On veut \(\dfrac{b-a}{2^n}\leqslant e\), c'est-à-dire \(2^n\geqslant\dfrac{b-a}{e}.\)
Ici \(b-a=1\) et \(e=0{,}001\) : il faut \(2^n\geqslant1000\), donc \(n=10\) puisque \(2^9=512\) et \(2^{10}=1024.\) C'est bien ce que le programme a compté.
f(a) * f(m) <= 0 et non f(a) < 0 and f(m) > 0 : le produit est négatif ou nul exactement quand les deux valeurs sont de signes contraires ou que l'une est nulle, quel que soit le sens de variation de \(f.\)3Méthode de Newton — dérivation et continuité
La dichotomie n'utilise que le signe de \(f.\) La méthode de Newton utilise en plus la tangente : on remplace la courbe par sa tangente, et on prend le point où cette droite coupe l'axe des abscisses.
La tangente en \(x_k\) a pour équation \(y=f'(x_k)(x-x_k)+f(x_k).\) Elle coupe l'axe des abscisses en \(y=0\), c'est-à-dire en
\[x_{k+1}=x_k-\dfrac{f(x_k)}{f'(x_k)}.\]Le nombre de tours est fixé d'avance : la boucle est bornée.
def f(x):
return x * x - 2
def fp(x):
return 2 * x
def newton(x, n):
for k in range(n):
x = x - f(x) / fp(x)
print(k + 1, x)
return x
newton(2, 4)
On cherche \(\sqrt2\), c'est-à-dire la solution positive de \(x^2-2=0.\) En quatre tours, on obtient \(1{,}41421356\ldots\) : la valeur \(\sqrt2\approx1{,}4142135624\) est retrouvée avec dix décimales justes, alors que la dichotomie en aurait demandé une trentaine d'étapes.
4Méthode d'Euler — exponentielle et équations différentielles
On connaît la pente de la courbe en chaque point, par l'équation \(y'=f(x,y)\), et un point de départ. La méthode d'Euler avance à petits pas en suivant à chaque fois la tangente : c'est encore une histoire de tangente, mais pour construire une courbe entière au lieu de chercher un zéro.
Avec un pas \(h\), on passe de \(y_k\) à
\[y_{k+1}=y_k+h\times(\text{pente en } y_k).\]Le nombre de pas est connu d'avance : boucle bornée.
a) Construire l'exponentielle. La fonction exponentielle est définie par \(y'=y\) et \(y(0)=1.\) La pente en \(y_k\) vaut donc \(y_k\) lui-même, et \(y_{k+1}=y_k+h\,y_k=(1+h)\,y_k.\)
def euler_exp(n):
h = 1 / n
y = 1
for k in range(n):
y = y + h * y
return y
print(euler_exp(4))
Avec quatre pas de \(h=0{,}25\) sur \([0\,;1]\), on obtient \((1{,}25)^4=2{,}44140625\) : c'est une valeur exacte de la ligne brisée, et une valeur approchée de \(\mathrm e\approx2{,}718.\) La ligne brisée reste en dessous de la courbe, parce que l'exponentielle est convexe.
b) Résoudre \(y'=ay+b.\) La même boucle sert pour n'importe quelle équation de ce type : il suffit de changer la pente.
def euler(a, b, y0, h, n):
y = y0
for k in range(n):
y = y + h * (a * y + b)
return y
print(euler(-2, 6, 1, 0.25, 4))
Pour \(y'=-2y+6\) avec \(y(0)=1\), la récurrence devient \(y_{k+1}=y_k+0{,}25\,(-2y_k+6)=0{,}5\,y_k+1{,}5.\) Les valeurs successives sont \(1\), \(2\), \(2{,}5\), \(2{,}75\), \(2{,}875\) : elles montent vers la solution constante \(y=3\), qui est bien la valeur d'équilibre \(-\dfrac ba=-\dfrac{6}{-2}=3.\)
5Méthode des rectangles — calcul intégral
L'intégrale \(\displaystyle\int_a^b f(x)\,\mathrm dx\) est une aire. On la découpe en \(n\) tranches de largeur \(h=\dfrac{b-a}{n}\), et on remplace chaque tranche par un rectangle : une fois en prenant la hauteur à gauche de la tranche, une fois à droite.
def f(x):
return x * x
def rectangles(a, b, n):
h = (b - a) / n
g = 0
d = 0
for k in range(n):
g = g + h * f(a + k * h)
d = d + h * f(a + (k + 1) * h)
return g, d
for n in [4, 16, 64, 256]:
print(n, rectangles(0, 1, n))
La valeur exacte est \(\displaystyle\int_0^1 x^2\,\mathrm dx=\dfrac13\), et elle est bien à l'intérieur des quatre encadrements. Les quatre nombres affichés sont exacts, sans arrondi : les bornes de l'encadrement sont des fractions de dénominateur une puissance de \(2.\)
6Simulation d'un échantillon, marche aléatoire — probabilités
Simuler, c'est demander à l'ordinateur de jouer l'expérience aléatoire, un grand nombre de fois, pour observer des fréquences. L'instruction de base est random.random(), qui rend un nombre au hasard entre \(0\) et \(1\), chaque intervalle ayant une probabilité égale à sa longueur. Un succès de probabilité \(p\) se simule donc par le test random.random() < p.
a) Un échantillon de taille \(n.\) Un échantillon de taille \(n\), c'est la liste de \(n\) observations indépendantes de la même variable aléatoire.
import random
def tirage(p):
if random.random() < p:
return 1
return 0
def echantillon(n, p):
return [tirage(p) for k in range(n)]
random.seed(2026)
E = echantillon(20, 0.5)
print(E)
print(sum(E) / 20)
print(sum(echantillon(1000, 0.5)) / 1000)
Sur \(20\) tirages, la fréquence observée vaut \(\dfrac{6}{20}=0{,}3\) : loin de \(0{,}5.\) Sur \(1000\) tirages elle vaut \(\dfrac{501}{1000}=0{,}501\) : la loi des grands nombres est à l'œuvre. Une fréquence observée n'est jamais la probabilité ; elle s'en rapproche quand \(n\) grandit.
random.seed(2026) ? Sans cette ligne, chaque exécution donne un résultat différent — c'est le but d'une simulation. Avec elle, le tirage est figé : tout le monde obtient exactement la sortie ci-dessus, ce qui permet de vérifier le programme. Dans un devoir, on ne met pas cette ligne.b) Marche aléatoire. Un pion part de \(0\) ; à chaque étape il avance de \(1\) ou recule de \(1\), à pile ou face. Où est-il après \(n\) pas ?
import random
def marche(n):
x = 0
for k in range(n):
if random.random() < 0.5:
x = x + 1
else:
x = x - 1
return x
random.seed(7)
print([marche(10) for i in range(5)])
Les cinq positions sont paires, et ce n'est pas un hasard : après \(10\) pas, la position est \(a-b\) avec \(a+b=10\), donc \(a-b=2a-10\) est toujours de la même parité que \(10.\) C'est un contrôle de vraisemblance immédiat du programme (méthode D).
7Fréquence simulée contre majoration de Bienaymé-Tchebychev
Le programme cite nommément cet algorithme : « calculer la probabilité de \(\left(|S_n-pn|>\sqrt n\right)\), où \(S_n\) est une variable aléatoire qui suit une loi binomiale \(\mathcal B(n,p)\). Comparer avec l'inégalité de Bienaymé-Tchebychev ». On simule la probabilité, on calcule la majoration, et on regarde l'écart entre les deux.
import random
def binomiale(n, p):
s = 0
for k in range(n):
if random.random() < p:
s = s + 1
return s
def frequence(N, n, p, a):
c = 0
for i in range(N):
if abs(binomiale(n, p) - n * p) >= a:
c = c + 1
return c / N
random.seed(2026)
print(frequence(10000, 100, 0.5, 10))
print(100 * 0.5 * 0.5 / (10 * 10))
Avec \(n=100\), \(p=0{,}5\) et \(\delta=\sqrt{100}=10\) (le texte officiel écrit l'inégalité stricte \(>\) ; la fonction frequence teste l'inégalité large >=, celle qui figure dans Bienaymé-Tchebychev), la fréquence observée de l'événement \(|S_n-50|\geqslant10\) vaut \(\dfrac{581}{10\,000}=0{,}0581\), alors que la majoration vaut \(\dfrac{100\times0{,}5\times0{,}5}{10^2}=\dfrac{25}{100}=0{,}25.\)
2. Méthode
Les sept algorithmes sont différents, mais on y retrouve quatre fois les mêmes questions : quelle boucle choisir, quand s'arrêter, comment découper le programme, et comment vérifier que le résultat n'est pas absurde. Ce sont les quatre méthodes qui suivent.
A — Choisir entre boucle bornée et boucle non bornée
- Oui → boucle bornée :
for k in range(n):. Le nombre de tours est \(n\), décidé à l'avance. - Non → boucle non bornée :
while condition:. On tourne tant que la condition reste vraie, et le nombre de tours est justement ce qu'on découvre.
Appliqué aux sept algorithmes de la fiche :
| Algorithme | Le nombre de tours est-il connu ? | Boucle |
|---|---|---|
| Seuil | non — c'est la réponse cherchée | while |
| Dichotomie | non si on impose une précision \(e\) | while |
| Dichotomie à \(n\) étapes | oui, \(n\) est donné | for |
| Newton | oui, on fixe le nombre d'itérations | for |
| Euler | oui, \(n\) pas de longueur \(h\) | for |
| Rectangles | oui, \(n\) rectangles | for |
| Simulation, marche | oui, \(n\) tirages ou \(n\) pas | for |
while si l'énoncé donne la précision (« encadrer \(\alpha\) à \(10^{-3}\) près »), et avec un for s'il donne le nombre d'étapes (« après \(5\) étapes »). C'est l'énoncé qui décide, pas l'algorithme.while dont la condition ne contient que le compteur, comme while k < n:, est presque toujours un for déguisé, plus long et plus risqué. Inversement, un for qu'on interrompt dès qu'une condition est remplie est un while déguisé.B — Écrire une condition d'arrêt correcte, et ne pas tourner sans fin
Une boucle non bornée s'arrête si — et seulement si — une quantité évolue dans le bon sens à chaque tour, et finit par franchir la frontière fixée par la condition. Trois vérifications, toujours les mêmes :
- Quelle quantité change ? Dans
while u < S:, c'est \(u.\) Si aucune instruction du corps ne modifie \(u\), la boucle est infinie. - Change-t-elle dans le bon sens, et assez vite ? \(u\leftarrow q\,u\) fait croître \(u\) seulement si \(q>1\) et \(u>0.\) Dans la dichotomie, c'est \(b-a\) qui doit décroître : elle est divisée par \(2\) à chaque tour, donc elle finit sous n'importe quel \(e>0\) strictement positif.
- La frontière est-elle atteignable ? \(u<S\) devient faux dès que \(u\geqslant S\) : il suffit que \(u\) dépasse \(S.\) En revanche
while u != S:exigerait une valeur exacte : à éviter absolument.
Le garde-fou. Quand on n'est pas certain que la boucle s'arrête, on ajoute un compteur maximal. Le programme rend alors une réponse convenue (ici \(-1\)) au lieu de tourner sans fin :
def seuil(u0, q, S, nmax):
u = u0
n = 0
while u < S and n < nmax:
u = q * u
n = n + 1
if u < S:
return -1
return n
print(seuil(1, 2, 1000, 10000))
print(seuil(1, 1, 1000, 10000))
Avec \(q=2\) le seuil est atteint en \(10\) tours ; avec \(q=1\) la suite est constante égale à \(1\), le seuil n'est jamais atteint, et le garde-fou renvoie \(-1\) après \(10\,000\) tours au lieu de bloquer la machine.
if u < S: return -1 après la boucle, pas if n == nmax : les deux sorties possibles doivent être distinguées par ce qu'on cherchait vraiment, c'est-à-dire par la valeur de \(u.\)C — Programmer par modules : une fonction par tâche
Le texte officiel insiste : « l'accent est mis sur la programmation modulaire qui permet de découper une tâche complexe en tâches plus simples ». Concrètement, chacun de ces algorithmes s'écrit comme une fonction qui reçoit ce dont elle a besoin en paramètres et retourne son résultat. Deux avantages immédiats.
- On la réutilise sans la réécrire. La même fonction
dichotomiesert pour toutes les équations, si la fonction \(f\) est elle-même un paramètre. - On la teste séparément. Si le résultat final est faux, on éprouve chaque fonction sur un cas dont on connaît la réponse, au lieu de relire trente lignes d'un bloc.
def dichotomie(f, a, b, e):
while b - a > e:
m = (a + b) / 2
if f(a) * f(m) <= 0:
b = m
else:
a = m
return a, b
def g(x):
return x**3 + x - 1
def h(x):
return x * x - 2
print(dichotomie(g, 0, 1, 0.125))
print(dichotomie(h, 1, 2, 0.125))
Une seule fonction, deux équations résolues. Le premier encadrement contient la solution de \(x^3+x-1=0\), le second contient \(\sqrt2\) : en effet \(1{,}375^2=1{,}890625<2\) et \(1{,}5^2=2{,}25>2.\)
- la fonction mathématique du problème :
f, et s'il le faut sa dérivéefp; - la méthode elle-même :
dichotomie,newton,euler,rectangles— elle ne connaît rien du problème ; - les appels, qui fixent les valeurs numériques et affichent.
print au lieu de return ne peut pas être réutilisée : son résultat n'est récupérable par aucun calcul. On affiche à l'extérieur.D — Contrôler la vraisemblance d'un résultat numérique
Un programme qui s'exécute sans message d'erreur peut très bien renvoyer un résultat faux. Avant d'écrire la réponse sur la copie, on lui applique au moins un de ces cinq tests — ils ne coûtent que quelques secondes.
| Test | Exemple |
|---|---|
| Ordre de grandeur | Une aire sous \(y=x^2\) entre \(0\) et \(1\) est comprise entre \(0\) et \(1\) : \(0{,}21875\) est plausible, \(21{,}875\) ne l'est pas. |
| Encadrement connu | La dichotomie doit rendre un intervalle où \(f\) change de signe : on vérifie \(f(a)\times f(b)\leqslant0.\) |
| Cas particulier calculable à la main | seuil(1, 2, 8) doit rendre \(3\), puisque \(2^3=8.\) |
| Signe et parité | Une marche aléatoire de \(10\) pas rend toujours un entier pair entre \(-10\) et \(10\) ; une fréquence est toujours entre \(0\) et \(1.\) |
| Deux réglages au lieu d'un | On relance avec \(n\) deux fois plus grand : les rectangles doivent se resserrer, Euler se rapprocher de la solution exacte. Si rien ne bouge, quelque chose ne va pas. |
Les quatre erreurs fréquentes
while u < S: sans que \(u\) augmente, ou avec une suite qui converge vers une limite inférieure à \(S\), donne une boucle infinie. Toujours identifier la quantité qui évolue et vérifier son sens de variation. Au besoin, ajouter le garde-fou de la méthode B.range(n) donne \(k=0,1,\dots,n-1\) : ce sont les bords gauches. Écrire range(1, n + 1) par distraction calcule les bords droits, donc l'autre somme.
def f(x):
return x * x
def gauche(a, b, n):
h = (b - a) / n
s = 0
for k in range(n):
s = s + h * f(a + k * h)
return s
def gauche_decale(a, b, n):
h = (b - a) / n
s = 0
for k in range(1, n + 1):
s = s + h * f(a + k * h)
return s
print(gauche(0, 1, 4))
print(gauche_decale(0, 1, 4))
x = 0.1 + 0.2 print(x) print(x == 0.3) print(abs(x - 0.3) < 1e-9)
while x != 0: ni if f(m) == 0: : on teste un encadrement (b - a > e) ou un signe (f(a) * f(m) <= 0), jamais une égalité.return. Une fonction sans return calcule tout, puis ne rend rien : Python renvoie None, et l'erreur n'apparaît qu'au moment de l'affichage.
def seuil(u0, q, S):
u = u0
n = 0
while u < S:
u = q * u
n = n + 1
print(seuil(1, 2, 1000))
3. Explorer
Une visualisation de l'exécution, ligne après ligne, pour quatre des algorithmes de la fiche. La ligne en cours est surlignée, l'état de chaque variable est affiché juste après son exécution, et la figure montre ce que l'algorithme est en train de faire : l'intervalle qui se réduit, les rectangles qui se remplissent, la ligne brisée qui avance. Le bouton « Autres valeurs » change les données sans changer l'algorithme.
Ce qu'il faut regarder
- Seuil : la condition du
whileest testée avant chaque tour, et une dernière fois pour sortir. Le compteur \(n\) compte les tours effectués. - Dichotomie : à chaque étape la largeur de l'intervalle est divisée par deux, et le changement de signe est conservé. Regarde la bande colorée se resserrer.
- Rectangles : les rectangles pleins sont ceux de gauche, les rectangles en pointillé ceux de droite. La courbe passe entre les deux, donc l'intégrale aussi.
- Euler : chaque segment de la ligne brisée a pour pente la valeur imposée par l'équation. L'écart avec la courbe exacte, en gris, grandit au fil des pas quand la solution s'éloigne de l'équilibre (\(a=1\)) ; quand elle s'en rapproche (\(a=-1\)), il finit par se réduire.
4. Exercices
Trois exercices génératifs, de difficulté croissante. Les réponses sont des entiers ou des décimaux exacts ; elles sont vérifiées à l'identique, sans aucune tolérance.
Exercice 1 Niveau 1 · nombre d'itérations
Exercice 2 Niveau 2 · encadrement par dichotomie
Exercice 3 Niveau 3 · rectangles et méthode d'Euler
5. QCM
Quatre questions tirées au hasard dans une banque de dix-huit, sur le choix de la boucle, les conditions d'arrêt, la précision atteinte et le rôle de chaque algorithme. Une seule bonne réponse par question.