Aller au contenu

Une notion à retrouver ?

15B — Les algorithmes du programme

Terminale · Mathématiques

Sept algorithmes cités nommément par le programme officiel : seuil, dichotomie, Newton, Euler, rectangles, simulation d'un échantillon ou d'une marche aléatoire, et la comparaison avec Bienaymé-Tchebychev. Chacun est relié au chapitre où il sert.

Suivi enregistré sur cet appareil

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

AlgorithmeCe qu'il calculeBoucleChapitre
Recherche de seuille premier rang qui franchit un seuilnon bornéesuites
Dichotomieun encadrement de la solution de \(f(x)=0\)non bornéecontinuité
Newtonune valeur approchée de cette solutionbornéedérivation
Eulerune solution approchée d'une équation différentiellebornéeexponentielle, équations différentielles
Rectanglesun encadrement d'une intégralebornéecalcul intégral
Simulation, marche aléatoiredes observations d'une variable aléatoirebornéeprobabilités
Fréquence contre majorationcompare une probabilité simulée à la borne de Bienaymé-Tchebychevbornéeconcentration

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))
Ce que Python affiche10

Contrôle à la main : \(2^9=512<1000\) et \(2^{10}=1024\geqslant1000\), donc le premier rang qui atteint \(1000\) est bien \(10.\)

Ce que renvoie exactement la fonction. À la sortie de la boucle, \(n\) est le nombre de tours effectués, et c'est aussi le premier rang tel que \(u_n\geqslant S\), parce que \(u\) contient \(u_n\) après \(n\) tours. Les deux coïncident ici ; ce n'est plus vrai si la suite ne part pas de \(u_0.\)
Le piège. Si la suite ne tend pas vers \(+\infty\), la condition peut ne jamais devenir fausse et le programme tourne indéfiniment. Avec \(q=1\), la suite est constante : la boucle ne s'arrête jamais. Voir la méthode B.
Où ça sert → fiche 3B — Suites arithmétiques et géométriques (le seuil d'une suite géométrique) et fiche 3C — Récurrence et limites de suites (le seuil traduit la définition de \(\lim u_n=+\infty\)). La résolution exacte de \(q^n\geqslant S\) se fait ensuite au logarithme : fiche 6C.

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))
Ce que Python affiche(0.681640625, 0.6826171875, 10)

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

Le test du signe. On écrit 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.\)
Où ça sert → fiche 5C — Continuité et théorème des valeurs intermédiaires : le théorème donne l'existence, la stricte monotonie donne l'unicité, la dichotomie donne l'encadrement. Le programme officiel cite aussi, au chapitre des suites, la recherche de valeurs approchées de \(\sqrt2\) ou de \(\pi\), pour laquelle la dichotomie est une méthode possible : fiche 3C.

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)
Ce que Python affiche1 1.5 2 1.4166666666666667 3 1.4142156862745099 4 1.4142135623746899

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.

On se limite aux cas favorables. Le programme officiel cite la méthode de Newton comme exemple d'algorithme « en se limitant à des cas favorables » (Première, dérivation) et n'exige aucune étude de convergence. On l'emploie donc seulement quand : \(f\) est dérivable, \(f'\) ne s'annule pas près de la solution, et le point de départ \(x_0\) en est déjà proche. Hors de ces cas, la suite peut osciller ou s'échapper — la dichotomie, elle, converge toujours.
Où ça sert → fiche 4A — Nombre dérivé et tangente (l'équation de la tangente, c'est toute la méthode) et fiche 5C — Continuité et théorème des valeurs intermédiaires, où le programme la cite à côté de la dichotomie.

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))
Ce que Python affiche2.44140625

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))
Ce que Python affiche2.875

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.\)

Où ça sert → fiche 6A — La fonction exponentielle (le programme de Première cite explicitement « construction de l'exponentielle par la méthode d'Euler ») et fiche 12B — Équations différentielles, dont la visualisation compare la ligne brisée à la solution exacte.

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.

L'intérêt : on obtient un encadrement. Si \(f\) est croissante sur \([a\,;b]\), le rectangle de gauche est toujours sous la courbe et celui de droite toujours au-dessus, donc \[\text{somme des rectangles à gauche}\ \leqslant\ \int_a^b f(x)\,\mathrm dx\ \leqslant\ \text{somme des rectangles à droite}.\] Si \(f\) est décroissante, les deux rôles s'échangent.
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))
Ce que Python affiche4 (0.21875, 0.46875) 16 (0.302734375, 0.365234375) 64 (0.3255615234375, 0.3411865234375) 256 (0.33138275146484375, 0.33528900146484375)

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.\)

La précision. La largeur de l'encadrement vaut exactement \(h\times|f(b)-f(a)|=\dfrac{b-a}{n}\times|f(b)-f(a)|\) : les deux sommes ne diffèrent que par le premier et le dernier rectangle. Ici elle vaut \(\dfrac1n\) : \(0{,}25\) puis \(0{,}0625\) puis \(0{,}015625\) puis \(0{,}00390625.\) Multiplier \(n\) par \(4\) divise l'écart par \(4\) : la méthode est lente, il faut cent fois plus de rectangles pour gagner deux décimales.
Où ça sert → fiche 13A — Intégrales, aires et valeur moyenne (l'intégrale comme aire, et son approche par des rectangles) et fiche 13B — Intégration par parties et approximations, qui donne la valeur exacte par les primitives. Le programme cite aussi les méthodes des milieux et des trapèzes, plus précises, et la méthode de Monte-Carlo.

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)
Ce que Python affiche[1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0] 0.3 0.501

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.

Pourquoi 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)])
Ce que Python affiche[4, 2, 2, 2, -2]

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

Où ça sert → fiche 8B — Variables aléatoires, espérance et variance (espérance et variance, que la simulation permet d'estimer), fiche 10A — Loi binomiale (le nombre de succès d'un échantillon suit une loi binomiale) et fiche 14A — Sommes de variables aléatoires (la marche aléatoire est une somme de variables indépendantes).

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.

L'inégalité. Pour une variable aléatoire \(X\) d'espérance \(\mu\) et de variance \(V\), et pour tout réel \(\delta>0\) : \[P\left(|X-\mu|\geqslant\delta\right)\leqslant\dfrac{V}{\delta^2}.\] Ici \(X=S_n\) suit \(\mathcal B(n,p)\), donc \(\mu=np\) et \(V=np(1-p).\)
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))
Ce que Python affiche0.0581 0.25

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.\)

Ce que l'algorithme montre. L'inégalité est vraie — \(0{,}0581\leqslant0{,}25\) — mais loin d'être optimale : la vraie probabilité est ici plus de quatre fois plus petite que la borne. C'est exactement ce que dit le texte officiel. L'intérêt de l'inégalité n'est pas sa précision, c'est qu'elle vaut pour toute variable aléatoire, sans rien savoir de sa loi.
Deux nombres de natures différentes. \(0{,}0581\) est une fréquence observée, qui change à chaque simulation ; \(0{,}25\) est un majorant démontré, qui ne change jamais. Ne pas écrire que la probabilité « vaut » \(0{,}0581.\)
Où ça sert → fiche 14B — Concentration et loi des grands nombres : l'inégalité de Bienaymé-Tchebychev, l'inégalité de concentration et la taille d'échantillon. La loi binomiale simulée est celle de la fiche 10A.

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

La question décisive, à se poser avant d'écrire la première ligne : au moment où la boucle démarre, le nombre de tours est-il connu ?
  • 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 :

AlgorithmeLe nombre de tours est-il connu ?Boucle
Seuilnon — c'est la réponse cherchéewhile
Dichotomienon si on impose une précision \(e\)while
Dichotomie à \(n\) étapesoui, \(n\) est donnéfor
Newtonoui, on fixe le nombre d'itérationsfor
Euleroui, \(n\) pas de longueur \(h\)for
Rectanglesoui, \(n\) rectanglesfor
Simulation, marcheoui, \(n\) tirages ou \(n\) pasfor
Le même algorithme peut changer de boucle. La dichotomie s'écrit avec un 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.
Réflexe de relecture. Un 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 :

  1. Quelle quantité change ? Dans while u < S:, c'est \(u.\) Si aucune instruction du corps ne modifie \(u\), la boucle est infinie.
  2. 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.
  3. 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))
Ce que Python affiche10 -1

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.

Attention à l'ordre des deux tests. On écrit 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.

  1. On la réutilise sans la réécrire. La même fonction dichotomie sert pour toutes les équations, si la fonction \(f\) est elle-même un paramètre.
  2. 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))
Ce que Python affiche(0.625, 0.75) (1.375, 1.5)

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.\)

Le découpage type d'un de ces algorithmes, en trois fonctions.
  • la fonction mathématique du problème : f, et s'il le faut sa dérivée fp ;
  • 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.
Une fonction retourne, elle n'affiche pas. Une fonction qui fait 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.

TestExemple
Ordre de grandeurUne 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 connuLa dichotomie doit rendre un intervalle où \(f\) change de signe : on vérifie \(f(a)\times f(b)\leqslant0.\)
Cas particulier calculable à la mainseuil(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'unOn 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.
Le meilleur contrôle est celui qui utilise les mathématiques du chapitre. La valeur exacte \(\displaystyle\int_0^1x^2\,\mathrm dx=\dfrac13\) doit être dans l'encadrement des rectangles ; la solution de \(y'=-2y+6\) doit tendre vers \(3\) ; la fréquence simulée doit être sous la majoration de Bienaymé-Tchebychev. Un programme qui contredit le cours est un programme faux.

Les quatre erreurs fréquentes

1. La condition d'arrêt ne se réalise jamais. 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.
2. Le décalage d'une itération. Dans les rectangles, 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))
Ce que Python affiche0.21875 0.46875
Les deux programmes tournent sans erreur et donnent des résultats plausibles : seule la comparaison avec \(\dfrac13\) révèle que le second majore au lieu de minorer.
3. Comparer deux flottants par égalité stricte. Les nombres décimaux ne sont pas représentés exactement en machine.
x = 0.1 + 0.2
print(x)
print(x == 0.3)
print(abs(x - 0.3) < 1e-9)
Ce que Python affiche0.30000000000000004 False True
On n'écrit donc jamais 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é.
4. Oublier le 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))
Ce que Python afficheNone
La boucle a pourtant bien compté \(10\) tours : la valeur a simplement été perdue à la sortie de la fonction.

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.

Sortie (console)

Ce qu'il faut regarder

  • Seuil : la condition du while est 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.

← Fiche précédenteListes et programmation en PythonParcours terminé →Revenir au programme
↑ Haut de la fiche
© 2026 Solucions Digitals JOA · Contenu pédagogique sous licence CC BY-SA 4.0 · Offrir un café