Me contacter

Maths Seconde, programme français • Exercices corrigés à Montréal

Exercices corrigés : algorithmique et programmation Python (Seconde)

Voici une série d'exercices corrigés d'algorithmique et de programmation Python, au niveau de la classe de Seconde du programme français, tel qu'il est suivi au Lycée Marie de France et au Collège Stanislas à Montréal.

En Seconde, l'algorithmique n'est pas un cours d'informatique : c'est un outil de mathématiques. Chaque programme de cette série calcule quelque chose qui figure ailleurs au programme, un seuil, une moyenne, une fréquence, une valeur approchée. L'exercice 10 montre pourquoi une boucle qui ajoute 0,1 finit par mentir.

Rappel de cours

  • Une affectation `x = 3` range une valeur dans une variable. Elle se lit de droite à gauche, et `x = x + 1` est parfaitement licite : on calcule d'abord, on range ensuite.
  • `=` affecte une valeur, `==` teste une égalité. Confondre les deux produit une erreur de syntaxe.
  • `for k in range(a, b)` parcourt les entiers de `a` à `b - 1` : la borne de droite est exclue. `range(a, b, p)` avance de `p` en `p`.
  • On utilise une boucle `for` quand le nombre de tours est connu à l'avance, et une boucle `while` quand il dépend d'une condition, typiquement une recherche de seuil.
  • Dans une boucle `while`, il faut que quelque chose change à chaque tour, sinon la boucle est infinie.
  • `return` renvoie une valeur exploitable ; `print` se contente d'afficher. Une fonction sans `return` renvoie `None`.
  • Pour une liste `L` : `len(L)` donne son nombre d'éléments, `L[0]` est le premier et `L[len(L) - 1]` le dernier.
  • L'écriture des nombres décimaux en machine est approchée : on n'additionne pas 0,1 des dizaines de fois si l'on veut un résultat exact.

Partie A : Les bases (/50)

Exercice 1 : Variables et trace d'exécution

On considère le programme suivant. Répondez sans machine : savoir suivre une exécution à la main est exactement ce qui est évalué.

a = 5
b = 3
a = a + b
b = a - b
a = a - b
print(a, b)
  • a) Dressez le tableau des valeurs successives de a et de b, ligne par ligne, et donnez ce qui est affiché.
  • b) Que réalise ce programme, quelles que soient les valeurs initiales ?
  • c) Écrivez le programme qui réalise la même chose en utilisant une troisième variable.
  • d) Que va afficher le programme suivant : x = 7, puis y = x, puis x = 10, puis print(y) ? Expliquez.
Voir la correction

a) Après les deux premières lignes, a vaut 5 et b vaut 3. La ligne `a = a + b` donne a = 8, b inchangé à 3. La ligne `b = a - b` donne b = 8 - 3 = 5, a inchangé à 8. La ligne `a = a - b` donne a = 8 - 5 = 3. Le programme affiche donc 3 5.

b) Il échange le contenu des deux variables, sans utiliser de variable supplémentaire. On est parti de a = 5 et b = 3, on arrive à a = 3 et b = 5.

c) Avec une variable auxiliaire, on écrit : `c = a` puis `a = b` puis `b = c`. C'est la version que l'on écrit en pratique, car elle fonctionne avec n'importe quel type de données, alors que la version de l'énoncé n'a de sens que pour des nombres.

d) Il affiche 7. Au moment de l'affectation `y = x`, Python range dans y la valeur que x contient alors, c'est-à-dire 7. Modifier x ensuite ne modifie pas y : une affectation copie une valeur, elle ne crée pas de lien permanent entre deux variables.

c = a
a = b
b = c

Exercice 2 : Instructions conditionnelles

On considère la fonction suivante, qui attribue une mention à une note sur 20.

def mention(note):
    if note >= 16:
        return 'Tres bien'
    elif note >= 14:
        return 'Bien'
    elif note >= 12:
        return 'Assez bien'
    else:
        return 'Pas de mention'
  • a) Donnez la valeur renvoyée par mention(14), mention(11.5), mention(16) et mention(20).
  • b) Que se passerait-il si l'on plaçait le test `note >= 12` en premier ? Illustrez avec une note précise.
  • c) Modifiez la fonction pour qu'elle renvoie 'Refuse' lorsque la note est strictement inférieure à 10.
  • d) Un élève écrit `if note >= 16 and note >= 14:`. Que vaut réellement cette condition ? Quelle était son intention probable ?
Voir la correction

a) mention(14) renvoie 'Bien', car 14 n'est pas supérieur ou égal à 16 mais l'est à 14. mention(11.5) renvoie 'Pas de mention'. mention(16) renvoie 'Tres bien', car le test utilise une inégalité large. mention(20) renvoie 'Tres bien'.

b) Tous les tests suivants deviendraient inaccessibles pour les notes élevées : une note de 18 vérifie déjà `note >= 12`, donc la fonction renverrait 'Assez bien' et s'arrêterait là. Dans une cascade de `elif`, il faut ordonner les tests du plus restrictif au plus large.

c) Il suffit d'ajouter un test avant le `else` final : `elif note >= 10:` renvoyant 'Pas de mention', et le `else` renvoie alors 'Refuse'. L'ordre reste décroissant.

d) La condition équivaut à `note >= 16` tout court : si une note est supérieure ou égale à 16, elle est automatiquement supérieure ou égale à 14, donc le second test n'apporte rien. L'élève voulait sans doute exprimer un intervalle, ce qui s'écrit `note >= 14 and note < 16`, avec un `and` entre deux bornes différentes.

def mention(note):
    if note >= 16:
        return 'Tres bien'
    elif note >= 14:
        return 'Bien'
    elif note >= 12:
        return 'Assez bien'
    elif note >= 10:
        return 'Pas de mention'
    else:
        return 'Refuse'

Exercice 3 : Boucles for

On rappelle que `range(a, b)` parcourt les entiers de a jusqu'à b - 1 inclus : la borne de droite est exclue.

s = 0
for k in range(1, 11):
    s = s + k
print(s)
  • a) Que calcule ce programme ? Donnez la valeur affichée.
  • b) Modifiez-le pour qu'il calcule la somme des carrés des entiers de 1 à 10, et donnez le résultat.
  • c) Quelles valeurs prend k dans `for k in range(0, 20, 5)` ?
  • d) Un second programme initialise p à 1 puis, pour k allant de 1 à 5, effectue `p = p * k`. Que calcule-t-il et que vaut p à la fin ?
Voir la correction

a) Il calcule la somme des entiers de 1 à 10, puisque range(1, 11) s'arrête à 10. La valeur affichée est 55, ce que confirme la formule 10×112=55\frac{10\times 11}{2}=55. Écrire range(1, 10) donnerait 45 : oublier que la borne est exclue est l'erreur la plus fréquente.

b) Il suffit de remplacer la ligne du corps par `s = s + k*k`. Le résultat est 1+4+9+16+25+36+49+64+81+100=3851+4+9+16+25+36+49+64+81+100=385.

c) La variable k prend les valeurs 0, 5, 10 et 15. Le troisième argument est le pas ; la valeur 20 est exclue, exactement comme dans range(a, b).

d) Il calcule le produit des entiers de 1 à 5, c'est-à-dire la factorielle de 5. À la fin, p vaut 1×2×3×4×5=1201\times 2\times 3\times 4\times 5=120. Remarquez qu'il faut initialiser p à 1 et non à 0, sinon tous les produits seraient nuls : l'élément neutre de la multiplication n'est pas celui de l'addition.

s = 0
for k in range(1, 11):
    s = s + k*k
print(s)

Exercice 4 : Boucle while et recherche de seuil

Une culture de 5 000 bactéries voit sa population augmenter de 8 % par heure. On considère le programme suivant.

n = 5000
t = 0
while n < 10000:
    n = n * 1.08
    t = t + 1
print(t)
  • a) Que représente la valeur affichée par ce programme ?
  • b) Déterminez cette valeur. On donne 1,0891,99901{,}08^{9}\approx 1{,}9990 et 1,08102,15891{,}08^{10}\approx 2{,}1589.
  • c) Pourquoi une boucle while est-elle nécessaire ici, plutôt qu'une boucle for ?
  • d) Que se passerait-il si le taux d'évolution était nul, c'est-à-dire si la ligne devenait `n = n * 1.0` ?
Voir la correction

a) Elle représente le nombre d'heures au bout desquelles la population atteint ou dépasse 10 000 bactéries, c'est-à-dire le temps de doublement arrondi à l'heure supérieure.

b) Après 9 heures, la population vaut 5000×1,999099955\,000\times 1{,}9990\approx 9\,995 bactéries : c'est encore strictement inférieur à 10 000, donc la boucle continue. Après 10 heures, elle vaut 5000×2,1589107955\,000\times 2{,}1589\approx 10\,795 bactéries, la condition devient fausse et la boucle s'arrête. Le programme affiche 10. Le cas à 9 heures est à 5 bactéries près du seuil : conclure sans calculer aurait conduit à répondre 9.

c) Parce que le nombre de tours n'est pas connu avant l'exécution. Une boucle for exige de fixer le nombre d'itérations à l'avance, alors qu'ici c'est justement ce nombre que l'on cherche. La boucle while est l'outil des problèmes de seuil.

d) La valeur de n resterait bloquée à 5 000, la condition `n < 10000` resterait vraie indéfiniment et la boucle ne s'arrêterait jamais : le programme tournerait sans fin. Une boucle while n'est sûre que si quelque chose progresse réellement vers la sortie à chaque tour.

Exercice 5 : Écrire et utiliser des fonctions

Une fonction se définit avec `def`, reçoit des paramètres entre parenthèses et renvoie une valeur avec `return`.

  • a) Écrivez une fonction `aire_rectangle(L, l)` qui renvoie l'aire d'un rectangle de longueur L et de largeur l. Donnez le résultat de aire_rectangle(7, 3).
  • b) Écrivez une fonction `est_pair(n)` qui renvoie True si n est pair et False sinon.
  • c) Une élève écrit une fonction `affiche_double(x)` dont le corps est `print(2*x)`, puis exécute `y = affiche_double(5)`. Que vaut y ? Expliquez.
  • d) On définit `def f(x): return 2*x + 3`. Calculez f(0) et f(5), puis résolvez f(x) = 17.
Voir la correction

a) La fonction se réduit à une ligne : `return L * l`. On obtient aire_rectangle(7, 3) = 21.

b) On teste le reste de la division par 2 : `return n % 2 == 0`. L'expression `n % 2 == 0` vaut déjà True ou False, il est donc inutile d'écrire une structure if renvoyant True ou False, même si c'est correct.

c) y vaut None. La fonction affiche bien 10 à l'écran, mais elle ne renvoie rien : en l'absence de `return`, Python renvoie automatiquement None. C'est la distinction essentielle entre afficher et renvoyer, et elle explique la plupart des programmes qui semblent fonctionner mais dont on ne peut pas réutiliser le résultat.

d) f(0) = 3 et f(5) = 13. Pour résoudre f(x) = 17, on résout 2x+3=172x+3=17, soit 2x=142x=14 et x=7x=7. On vérifie que f(7) = 17.

def aire_rectangle(L, l):
    return L * l

def est_pair(n):
    return n % 2 == 0

def f(x):
    return 2*x + 3

Partie B : Niveau contrôle (/50)

Exercice 6 : Parcourir une liste

On considère la liste des notes d'un élève : notes = [12, 8, 15, 9, 18, 11].

  • a) Donnez les valeurs de len(notes), notes[0], notes[2] et notes[len(notes) - 1].
  • b) Écrivez l'instruction qui calcule la moyenne des notes, et donnez sa valeur arrondie au centième.
  • c) Écrivez une boucle qui compte le nombre de notes supérieures ou égales à 12, et donnez le résultat.
  • d) Écrivez une boucle qui trouve la plus grande note sans utiliser la fonction max, et expliquez pourquoi on initialise avec le premier élément plutôt qu'avec 0.
Voir la correction

a) len(notes) vaut 6, notes[0] vaut 12, notes[2] vaut 15 et notes[len(notes) - 1] vaut 11. Les indices commencent à 0, donc le dernier indice est 5 et non 6 : écrire notes[6] provoquerait une erreur.

b) On écrit `moyenne = sum(notes) / len(notes)`. La somme vaut 12+8+15+9+18+11=7312+8+15+9+18+11=73, donc la moyenne vaut 73612,17\frac{73}{6}\approx 12{,}17.

c) On initialise un compteur à 0, puis on parcourt la liste en incrémentant à chaque note qui vérifie la condition. Les notes concernées sont 12, 15 et 18, donc le compteur vaut 3 à la fin.

d) On initialise avec notes[0], puis on compare chaque élément suivant au maximum courant en le remplaçant s'il est plus grand. Le résultat est 18. Initialiser à 0 serait dangereux : si toutes les valeurs étaient négatives, par exemple des températures hivernales à Montréal, l'algorithme renverrait 0, qui n'appartient pas à la liste. Partir du premier élément garantit que le résultat est toujours une valeur réellement présente.

compteur = 0
for note in notes:
    if note >= 12:
        compteur = compteur + 1

maxi = notes[0]
for note in notes:
    if note > maxi:
        maxi = note

Exercice 7 : Compléter un programme de seuil

Un capital de 2 000 dollars est placé à un taux annuel de 3 %. On veut savoir au bout de combien d'années il dépasse 3 000 dollars.

Le programme suivant est incomplet, les pointillés doivent être remplacés.

capital = 2000
annee = 0
while capital < ... :
    capital = capital * ...
    annee = annee + 1
print(annee)
  • a) Complétez les deux pointillés.
  • b) Déterminez le nombre d'années affiché. On donne 1,03131,46851{,}03^{13}\approx 1{,}4685 et 1,03141,51261{,}03^{14}\approx 1{,}5126.
  • c) Quel est le capital atteint à cette date, arrondi au centime ?
  • d) On ajoute une instruction d'affichage à l'intérieur de la boucle pour suivre l'évolution année par année. Combien de lignes s'affichent alors ?
Voir la correction

a) La condition de poursuite est `capital < 3000` et la ligne de calcul est `capital = capital * 1.03`. Augmenter de 3 % revient à multiplier par 1+3100=1,031+\frac{3}{100}=1{,}03, et non à ajouter 3.

b) Après 13 ans, le capital vaut 2000×1,46852937,072\,000\times 1{,}4685\approx 2\,937{,}07 dollars, encore inférieur à 3 000 : la boucle continue. Après 14 ans, il vaut 2000×1,51263025,182\,000\times 1{,}5126\approx 3\,025{,}18 dollars, la condition devient fausse. Le programme affiche 14.

c) Le capital atteint est d'environ 3025,183\,025{,}18 dollars. Il dépasse le seuil de 25,18 dollars, ce qui est normal : la croissance est discontinue, on n'atterrit jamais exactement sur le seuil.

d) L'affichage se trouvant dans le corps de la boucle, il s'exécute une fois par tour. Comme la boucle effectue 14 tours, 14 lignes s'affichent. Si l'affichage était placé après la boucle, au même niveau d'indentation que le print final, il n'y en aurait qu'une : en Python, c'est l'indentation seule qui décide de ce qui est répété.

capital = 2000
annee = 0
while capital < 3000:
    capital = capital * 1.03
    annee = annee + 1
    print(annee, capital)
print(annee)

Exercice 8 : Simulation aléatoire et fluctuation

On simule des lancers d'un dé équilibré à six faces à l'aide du programme suivant. La fonction randint(1, 6) renvoie un entier au hasard entre 1 et 6 inclus.

from random import randint

def simulation(n):
    compteur = 0
    for i in range(n):
        if randint(1, 6) == 6:
            compteur = compteur + 1
    return compteur / n
  • a) Que représente la valeur renvoyée par simulation(1000) ?
  • b) Autour de quelle valeur ce résultat doit-il se situer ? Donnez-la au millième.
  • c) Deux exécutions de simulation(100) renvoient 0.14 puis 0.19. Est-ce le signe d'une erreur de programme ?
  • d) On rappelle qu'un intervalle de fluctuation au seuil de 95 % est donné par [p1n ; p+1n]\left[p-\frac{1}{\sqrt{n}}\ ;\ p+\frac{1}{\sqrt{n}}\right]. Comparez sa largeur pour n=100n=100 et pour n=10000n=10\,000.
Voir la correction

a) Elle représente la fréquence d'apparition du 6 sur 1 000 lancers simulés, c'est-à-dire le nombre de 6 obtenus divisé par le nombre de lancers. C'est une fréquence observée, et non une probabilité.

b) Le dé étant équilibré, la probabilité d'obtenir un 6 vaut 160,167\frac{1}{6}\approx 0{,}167. La fréquence observée doit se situer autour de cette valeur.

c) Non, c'est parfaitement normal : c'est la fluctuation d'échantillonnage. Deux échantillons de même taille tirés de la même expérience donnent en général des fréquences différentes. Un programme qui renverrait exactement 0.1666 à chaque exécution serait au contraire suspect.

d) Pour n=100n=100, l'intervalle vaut [160,1 ; 16+0,1]\left[\frac{1}{6}-0{,}1\ ;\ \frac{1}{6}+0{,}1\right], soit environ [0,067 ; 0,267][0{,}067\ ;\ 0{,}267], de largeur 0,20{,}2. Les deux résultats observés, 0,14 et 0,19, y figurent bien. Pour n=10000n=10\,000, l'intervalle vaut [160,01 ; 16+0,01]\left[\frac{1}{6}-0{,}01\ ;\ \frac{1}{6}+0{,}01\right], soit environ [0,157 ; 0,177][0{,}157\ ;\ 0{,}177], de largeur 0,020{,}02. Multiplier la taille de l'échantillon par 100 divise donc la largeur par 10 seulement, puisque c'est la racine carrée de nn qui intervient : gagner une décimale de précision coûte cent fois plus de lancers.

Exercice 9 : Quatre programmes à corriger

Chacun des programmes suivants contient une erreur. Identifiez-la, expliquez son effet et proposez la correction.

  • a) Une fonction moyenne(a, b) dont le corps est `print((a + b)/2)`, appelée par `m = moyenne(4, 6)`. Que vaut m ?
  • b) Un programme initialise s à 0, puis pour k de 1 à 10 effectue `s = k`. Que vaut s à la fin, et que voulait-on ?
  • c) Un programme initialise n à 10, puis exécute `while n > 0:` avec pour seul corps `print(n)`.
  • d) Un programme contient la ligne `if x = 5:`.
Voir la correction

a) m vaut None. La fonction affiche bien 5 à l'écran, mais elle ne renvoie aucune valeur. La correction consiste à remplacer print par return : `return (a + b)/2`. On peut toujours afficher le résultat ensuite, avec `print(moyenne(4, 6))`.

b) À la fin, s vaut 10 : à chaque tour on écrase la valeur précédente au lieu de l'accumuler. On voulait la somme des entiers de 1 à 10, soit 55. La correction est `s = s + k`, qui ajoute au lieu de remplacer.

c) La variable n n'est jamais modifiée dans la boucle, donc la condition `n > 0` reste vraie indéfiniment : la boucle est infinie et le programme affiche 10 sans jamais s'arrêter. Il faut ajouter `n = n - 1` dans le corps de la boucle, ce qui affichera alors 10, 9, 8, jusqu'à 1.

d) C'est une erreur de syntaxe. Le simple `=` est l'affectation, qui range une valeur dans une variable ; le test d'égalité s'écrit avec un double `==`. La ligne correcte est `if x == 5:`. Python refuse d'exécuter le programme, ce qui est ici une chance : l'erreur est signalée immédiatement plutôt que de produire silencieusement un mauvais résultat.

def moyenne(a, b):
    return (a + b)/2

s = 0
for k in range(1, 11):
    s = s + k

n = 10
while n > 0:
    print(n)
    n = n - 1

Exercice 10 : Problème de synthèse : une racine carrée par balayage

On cherche une valeur approchée de la solution positive de l'équation x2=7x^{2}=7, sans utiliser la touche racine carrée de la calculatrice.

On considère le programme suivant.

x = 0
while x*x < 7:
    x = x + 0.1
print(x)
  • a) Quel encadrement d'amplitude 0,1 ce programme fournit-il ? Justifiez par deux calculs.
  • b) Comment modifier le programme pour obtenir un encadrement d'amplitude 0,01 ? Donnez cet encadrement.
  • c) L'accumulation de nombreux ajouts de 0,1 pose un problème de précision en machine. Proposez une version qui boucle sur des entiers pour l'éviter.
  • d) Combien de tours de boucle la version au centième effectue-t-elle ? Que faudrait-il pour gagner une décimale de plus, et pourquoi préfère-t-on souvent une autre méthode ?
Voir la correction

a) La boucle s'arrête dès que le carré atteint 7. On a 2,62=6,76<72{,}6^{2}=6{,}76<7, donc la boucle continue, et 2,72=7,2972{,}7^{2}=7{,}29\geq 7, donc elle s'arrête. Le programme affiche environ 2,7 et fournit l'encadrement 2,6<7<2,72{,}6<\sqrt{7}<2{,}7.

b) Il suffit de remplacer le pas par 0,01, c'est-à-dire d'écrire `x = x + 0.01`. On a 2,642=6,9696<72{,}64^{2}=6{,}9696<7 et 2,652=7,022572{,}65^{2}=7{,}0225\geq 7, d'où l'encadrement 2,64<7<2,652{,}64<\sqrt{7}<2{,}65.

c) Le nombre 0,1 n'a pas d'écriture binaire exacte : en l'ajoutant des centaines de fois, les petites erreurs s'accumulent et la variable finit par valoir un nombre légèrement différent de celui attendu. On contourne le problème en comptant avec un entier et en ne divisant qu'au moment du test : on initialise n à 0, la condition devient `while (n/100)*(n/100) < 7:`, le corps devient `n = n + 1`, et l'on affiche `n/100` à la fin. Les entiers, eux, sont exacts.

d) La boucle s'arrête pour n=265n=265, puisque (265100)2=7,02257\left(\frac{265}{100}\right)^{2}=7{,}0225\geq 7 alors que la valeur précédente est inférieure : elle effectue donc 265 tours. Pour gagner une décimale, il faudrait un pas dix fois plus petit, donc environ dix fois plus de tours, soit 2 650. Le coût croît linéairement avec la précision demandée. Une recherche par dichotomie sur l'intervalle [2 ; 3][2\ ;\ 3] atteindrait la même précision de 0,01 en 7 étapes seulement, car chaque étape divise l'amplitude par 2 et 1270,0078\frac{1}{2^{7}}\approx 0{,}0078.

n = 0
while (n/100)*(n/100) < 7:
    n = n + 1
print(n/100)

Voir aussi

Vous cherchez un tuteur de maths en Seconde à Montréal ?

Contactez-moi pour une première séance. On travaille sur des exercices calibrés sur le niveau réel des contrôles au Lycée Marie de France et au Collège Stanislas.

Site par Studio Squalli