Spécialité maths, Première • Exercices corrigés à Montréal
Exercices corrigés : Python en spécialité maths et en sciences (Première)
Voici une série d'exercices corrigés de Python appliqué à la spécialité mathématiques, au niveau de la classe de Première du programme français, telle qu'elle est suivie au Lycée Marie de France et au Collège Stanislas à Montréal.
En Première, l'algorithmique n'est plus un chapitre à part : elle traverse les suites, la dérivation, le second degré et les probabilités. Chaque programme de cette série calcule un objet du cours, et chaque résultat affiché doit être retrouvé par un calcul exact. C'est ce va-et-vient qui est évalué au contrôle, jamais la syntaxe pour elle-même. Vous y programmez une suite récurrente et son point fixe (exercice 1), un algorithme de seuil avec une boucle while, prouvé ensuite par la forme explicite (exercice 2), la somme de versements annuels et sa formule fermée (exercice 3), le nombre dérivé approché par le taux d'accroissement (exercice 4), le nombre de racines par le discriminant (exercice 5), l'espérance et l'écart-type d'une variable aléatoire (exercice 6) et la résolution approchée d'une équation par balayage (exercice 7).
Les problèmes mettent ces outils en situation : la décroissance radioactive de l'iode 131 par la méthode d'Euler (exercice 9), la trajectoire d'un ballon qui franchit ou non un mur (exercice 10), la méthode d'Archimède pour approcher π par des polygones (exercice 12), la géométrie repérée en Python (exercice 13), la suite de Syracuse et son temps de vol (exercice 14) et la fluctuation des moyennes d'échantillons (exercice 15). Les corrigés traitent les pièges propres à la machine : le return placé dans la boucle (exercice 1), le test d'égalité == sur des décimaux (exercices 6 et 13), le pas h trop petit qui détruit le nombre dérivé (exercice 4) et la formule de doublement qui finit par afficher 0 (exercice 12) ; l'exercice 8 fait corriger cinq affirmations fausses.
La partie D suit le programme de Première en vigueur depuis la rentrée 2026. Elle travaille la seule notion nouvelle de l'algorithmique de Première, la liste, puis les exemples d'algorithme que le programme cite chapitre par chapitre : factorielle et Fibonacci pour les suites, sécantes et méthode de Newton pour la dérivation, intérêts composés pour le nombre e, Monte-Carlo pour les probabilités et fréquence des lettres pour les variables aléatoires. Son fil : une liste est un ensemble qu'on a rangé, et ses indices partent de 0.
Série autocorrigéeTape tes réponses et vérifie-les question par question : la page te dit juste ou faux avant d'ouvrir la correction. Avec un compte, chaque bonne réponse du premier coup rapporte des points, et tes réponses justes restent remplies quand tu reviens.
•Une suite définie par récurrence se calcule terme après terme : on initialise, puis on répète la mise à jour dans une boucle.
•Si un+1=aun+b avec a=1, le point fixe L vérifie L=aL+b, et la suite vn=un−L est géométrique de raison a.
•Un seuil se cherche avec une boucle while : on répète tant que la condition d'arrêt n'est pas atteinte, en comptant les tours.
•Somme des termes d'une suite géométrique de raison q=1 : u0×1−q1−qn+1.
•Le nombre dérivé est la limite du taux d'accroissement hf(a+h)−f(a) quand h tend vers 0, et non sa valeur en h=0.
•Discriminant Δ=b2−4ac : deux racines si Δ>0, une racine double si Δ=0, aucune racine réelle si Δ<0.
•Espérance E(X)=∑xipi, variance V(X)=E(X2)−E(X)2 et écart-type σ=V(X).
•Les décimaux sont représentés de façon approchée en machine : une condition d'arrêt s'écrit avec une inégalité, jamais avec ==.
•Une liste se génère en extension, L = [1, 2, 3], par ajouts successifs avec L.append(x), ou en compréhension avec une condition, [x for x in range(n) if ...]. Ses indices vont de 0 à len(L) - 1.
•L.remove(v) retire la première occurrence de la valeur v ; L.pop(i) et del L[i] retirent l'élément d'indice i. On ne supprime jamais dans une liste pendant qu'on la parcourt.
•Méthode de Newton : xk+1=xk−f′(xk)f(xk), abscisse du point où la tangente en xk coupe l'axe des abscisses.
Partie A : les bases (/50)
Exercice 1 : Suite récurrente et point fixe
La suite (un) est définie par u0=2 et un+1=0,8un+3 pour tout entier n. On veut la calculer en Python.
def terme(n):
u = 2
for k in range(n):
u = 0.8*u + 3
return u
a) Calculez à la main u1, u2 et u3, puis vérifiez que terme(3) renvoie la même valeur.
b) Un élève place l'instruction return u À L'INTÉRIEUR de la boucle. Que renvoie alors terme(3) ?
c) Que renvoie terme(0) ? Pourquoi ce cas est-il correct sans aucune ligne supplémentaire ?
d) Le programme affiche des valeurs qui se rapprochent d'un nombre. Déterminez-le par le calcul.
Voir la correction
Réponses
a)u1=4,6, u2=6,68, u3=8,344
b)4,6 : return interrompt la boucle
c)2 : la boucle ne tourne pas
d)15
a)
On applique la relation trois fois : u1=0,8×2+3=4,6, puis u2=0,8×4,6+3=3,68+3=6,68, puis u3=0,8×6,68+3=5,344+3=8,344. La boucle for k in range(3) effectue exactement trois mises à jour, donc terme(3) renvoie 8,344. La variable de boucle k ne sert à rien d'autre qu'à compter : c'est normal, la relation de récurrence ne dépend pas de n.
b)
Elle renvoie 4,6, c'est-à-dire u1. L'instruction return ne se contente pas de renvoyer une valeur, elle INTERROMPT immédiatement la fonction : dès la fin du premier tour, tout s'arrête. C'est l'erreur la plus fréquente sur ce type de programme, et elle est silencieuse, puisque 4,6 est une valeur parfaitement plausible. Le return d'une fonction de calcul itératif se place toujours APRÈS la boucle, au même niveau d'indentation que le for.
c)
Il renvoie 2, c'est-à-dire u0. La boucle range(0) est vide, donc aucune mise à jour n'a lieu et la fonction renvoie la valeur d'initialisation. Ce comportement est exactement celui que l'on veut, et il illustre un principe utile : une boucle qui tourne zéro fois n'est pas une erreur, c'est le cas de base traité gratuitement.
d)
Si la suite converge vers un réel L, alors en passant à la limite dans la relation on obtient L=0,8L+3, donc 0,2L=3 et L=15. On le démontre proprement en posant vn=un−15 : alors vn+1=un+1−15=0,8un+3−15=0,8(un−15)=0,8vn. La suite (vn) est donc GÉOMÉTRIQUE de raison 0,8 et de premier terme v0=2−15=−13, d'où un=15−13×0,8n. Comme 0<0,8<1, le terme 0,8n tend vers 0 et un tend vers 15 en croissant, sans jamais l'atteindre.
Le fil de la série commence ici : la boucle produit des NOMBRES, le calcul produit une FORMULE. On vérifie la formule sur les nombres, ici u3=15−13×0,512=15−6,656=8,344 ✓, et c'est ensuite la formule qui permet de répondre à toutes les questions de limite et de seuil.
def terme(n):
u = 2
for k in range(n):
u = 0.8*u + 3
return u
Coche ici les exercices faits ou à revoir : un compte gratuit, sans mot de passe, retient tes coches et tes réponses justes d'une visite à l'autre, te dit quel chapitre attaquer ensuite et te permet de demander l'exercice qui te manque. Crée ton espace, un courriel suffit.
Exercice 2 : Recherche de seuil et preuve associée
On garde la suite u0=2 et un+1=0,8un+3, dont on admet la forme explicite un=15−13×0,8n. On cherche le premier rang à partir duquel un dépasse 14,9.
a) Écrivez un programme utilisant une boucle while qui affiche ce rang.
b) Donnez la valeur trouvée, en justifiant par les deux termes qui encadrent le seuil.
c) Retrouvez ce rang par le calcul, à l'aide de la forme explicite.
d) Pourquoi la boucle se termine-t-elle ? Que se passerait-il si le seuil valait 15 ?
Voir la correction
Réponses
a)Boucle while u <= 14.9, avec mise à jour et compteur
b)22 (u21≈14,880, u22≈14,904)
c)0,8n<1301 : n=22
d)un tend vers 15 ; avec le seuil 15, boucle infinie
a)
u = 2 puis n = 0 puis while u <= 14.9: puis u = 0.8*u + 3 puis n = n + 1 puis print(n). Les deux instructions du corps sont indissociables : la mise à jour du terme et le comptage du rang doivent avancer ENSEMBLE, sans quoi le rang affiché ne correspond pas au terme calculé.
b)
Le programme affiche 22. En effet u21=15−13×0,821≈15−13×0,009223≈14,8801, encore sous le seuil, tandis que u22=15−13×0,822≈15−13×0,007379≈14,9041, qui le dépasse. Donner ces deux valeurs est indispensable : un rang de seuil ne se justifie jamais par le seul affichage du programme.
c)
On résout 15−13×0,8n>14,9, soit 13×0,8n<0,1, soit 0,8n<1301≈0,00769. La suite (0,8n) est géométrique de raison comprise entre 0 et 1, donc strictement DÉCROISSANTE : dès qu'un rang convient, tous les suivants conviennent. La calculatrice donne 0,821≈0,00922, encore trop grand, et 0,822≈0,00738, qui convient. Le premier entier convenable est donc n=22 ✓. C'est la décroissance qui fait de ce rang le SEUIL : sans elle, un rang convenable pourrait être suivi d'un rang qui ne convient plus.
d)
Elle se termine parce que 0,8n tend vers 0, donc un tend vers 15 : la suite finit par franchir n'importe quel seuil strictement inférieur à 15. Avec un seuil égal à 15, la boucle ne s'arrêterait JAMAIS, car un=15−13×0,8n reste strictement inférieur à 15 pour tout n. Une suite convergente ne dépasse pas sa limite : c'est le piège classique de la boucle while en analyse, et il ne se voit pas à la lecture du programme, seulement en connaissant la limite.
Le fil : le programme donne le rang, la forme explicite et la décroissance le démontrent, et les deux doivent coïncider. Quand ils diffèrent d'une unité, l'erreur est presque toujours un < écrit à la place d'un <= dans la condition d'arrêt.
u = 2
n = 0
while u <= 14.9:
u = 0.8*u + 3
n = n + 1
print(n)
Exercice 3 : Somme de termes et formule fermée
Une personne place 200 dollars au début de chaque année sur un compte rémunéré à 5% par an. Au bout de n années, le capital vaut la somme Sn=200×1,05+200×1,052+⋯+200×1,05n.
def capital(n):
s = 0
for k in range(1, n+1):
s = s + 200*1.05**k
return s
a) Que renvoie capital(10) ? Donnez la valeur au centime.
b) Établissez la formule fermée de Sn et vérifiez-la sur n=10.
c) Un élève initialise s = 200 au lieu de s = 0. De combien son résultat est-il faux ?
d) Écrivez un programme qui donne le nombre d'années nécessaires pour dépasser 5000 dollars, et retrouvez-le par le calcul.
Voir la correction
Réponses
a)≈2641,36 dollars
b)Sn=4200(1,05n−1)
c)Trop grand de 200 dollars
d)17 ans
a)
La boucle ajoute dix termes, de k=1 à k=10, puisque range(1, 11) s'arrête à 10 inclus. La fonction renvoie environ 2641,36 dollars. La ligne s = s + 200*1.05**k est le motif de l'ACCUMULATEUR : une variable qui part de zéro et à laquelle on ajoute un terme par tour, la division ou la conclusion venant après la boucle.
b)
C'est la somme des termes d'une suite géométrique de premier terme 210 et de raison 1,05, comptant n termes : Sn=210×1,05−11,05n−1=4200(1,05n−1). Pour n=10 : 1,0510≈1,62889, donc S10≈4200×0,62889≈2641,36 dollars, ce qui coïncide avec l'affichage ✓. Comparaison instructive : si les versements avaient lieu en FIN d'année, la somme partirait de k=0 et vaudrait 200×0,051,0510−1≈2515,58 dollars, soit 125,78 dollars de moins. Un décalage d'un seul indice se paie donc en argent réel, et c'est exactement ce que la comparaison programme contre formule permet de détecter.
c)
Il ajoute 200 dollars qui ne correspondent à aucun versement rémunéré : son résultat est trop grand de exactement 200 dollars, soit 2841,36 au lieu de 2641,36. L'initialisation d'un accumulateur de somme est toujours 0, comme celle d'un accumulateur de produit est toujours 1 : c'est l'élément neutre de l'opération que l'on répète.
d)
s = 0 puis n = 0 puis while s <= 5000: puis n = n + 1 puis s = s + 200*1.05**n puis print(n). Le programme affiche 17. Par le calcul : 4200(1,05n−1)>5000 équivaut à 1,05n>1+42005000≈2,1905, et la suite (1,05n) est croissante : 1,0516≈2,1829 ne suffit pas, 1,0517≈2,2920 convient, d'où n=17 ✓. On vérifie : S16≈4968,07 dollars et S17≈5426,48 dollars.
Le fil : dès qu'une somme apparaît, deux écritures coexistent, la boucle et la formule. La formule est indispensable pour les seuils, la boucle sert de contrôle, et le seul vrai danger est l'indice de départ.
s = 0
n = 0
while s <= 5000:
n = n + 1
s = s + 200*1.05**n
print(n)
Exercice 4 : Nombre dérivé approché et limites de la machine
Soit f définie sur R par f(x)=x3−2x. On veut estimer le nombre dérivé de f en a=1 à l'aide du taux d'accroissement T(h)=hf(1+h)−f(1).
def f(x):
return x**3 - 2*x
for k in range(1, 7):
h = 10**(-k)
print(h, (f(1+h) - f(1))/h)
a) Donnez les valeurs affichées pour k=1, k=2 et k=3, au millième.
b) Développez T(h) en fonction de h et déduisez-en la limite quand h tend vers 0.
c) Retrouvez le résultat en dérivant f, puis donnez l'équation de la tangente en 1.
d) Un élève prend h=10−17 et obtient 0. Expliquez pourquoi, et dites quel ordre de grandeur de h il faut choisir.
Voir la correction
Réponses
a)1,310 ; 1,030 ; 1,003
b)T(h)=1+3h+h2, limite 1
c)f′(1)=1 ; tangente y=x−2
d)1+10−17 vaut 1 en machine ; choisir h vers 10−6 à 10−8
a)
On a f(1)=1−2=−1. Pour h=0,1 : f(1,1)=1,331−2,2=−0,869, donc T=0,1−0,869+1=1,310. Pour h=0,01 : f(1,01)=1,030301−2,02=−0,989699, donc T=1,030. Pour h=0,001 : T=1,003. Les valeurs se rapprochent visiblement de 1.
b)
On développe : f(1+h)=(1+h)3−2(1+h)=1+3h+3h2+h3−2−2h=−1+h+3h2+h3. En retranchant f(1)=−1 il reste h+3h2+h3, et en divisant par h, qui est non nul, on obtient T(h)=1+3h+h2. La limite quand h tend vers 0 vaut donc 1. Cette écriture explique les chiffres observés : pour h=0,1 on lit 1+0,3+0,01=1,31 ✓, et l'erreur est de l'ordre de 3h, ce qui se voit à l'oeil sur la colonne des résultats.
c)
f′(x)=3x2−2, donc f′(1)=3−2=1, ce qui confirme la limite. La tangente en 1 a pour équation y=f′(1)(x−1)+f(1), soit y=(x−1)−1, c'est-à-dire y=x−2. Le taux d'accroissement est le coefficient directeur de la SÉCANTE passant par les points d'abscisses 1 et 1+h ; quand h diminue, cette sécante bascule vers la tangente, et le nombre dérivé est la position limite de sa pente.
d)
Parce qu'en machine 1+10−17 est arrondi à 1 exactement : les nombres flottants ne retiennent qu'une quinzaine de chiffres significatifs, et un 1 suivi de dix-sept zéros puis d'un 1 ne tient pas. Le numérateur f(1+h)−f(1) devient donc 0, et le quotient vaut 0 au lieu de 1. Il y a deux erreurs qui se combattent : si h est trop GRAND, l'approximation mathématique est mauvaise, de l'ordre de 3h ; si h est trop PETIT, la soustraction de deux nombres presque égaux détruit les chiffres significatifs. Le compromis se situe vers h=10−6 à 10−8. C'est un fait important : contrairement à l'intuition, diminuer indéfiniment le pas ne rend pas le résultat plus juste.
Le fil : la limite mathématique et le calcul en machine ne coïncident que dans une fenêtre. Le programme montre la convergence, la factorisation la démontre, et la représentation des flottants explique pourquoi la table s'arrête de progresser.
Exercice 5 : Discriminant et nombre de racines
On veut écrire une fonction nb_racines(a, b, c) qui renvoie le nombre de solutions réelles de l'équation ax2+bx+c=0.
a) Écrivez cette fonction à l'aide d'un if, d'un elif et d'un else.
b) Que renvoie-t-elle pour x2−4x+4=0, pour 2x2+x+3=0 et pour x2−5x+6=0 ? Justifiez chaque valeur.
c) Que renvoie nb_racines(0, 3, -6) ? Pourquoi la réponse est-elle mathématiquement fausse, et comment corriger la fonction ?
d) Écrivez une fonction racines(a, b, c) qui affiche les solutions lorsqu'il y en a.
Voir la correction
Réponses
a)Tests if d > 0, elif d == 0, else
b)1 ; 0 ; 2
c)Renvoie 2 au lieu de 1 : traiter a=0 d'abord
d)Calculer sqrt(d) seulement si d≥0
a)
def nb_racines(a, b, c): puis d = b*b - 4*a*c puis if d > 0: puis return 2 puis elif d == 0: puis return 1 puis else: puis return 0. L'ordre des tests importe : écrire if d >= 0: return 2 fusionnerait à tort le cas de la racine double avec celui des deux racines distinctes.
b)
Pour x2−4x+4 : Δ=16−16=0, la fonction renvoie 1. L'équation admet la racine double x=24=2, ce que confirme la factorisation (x−2)2. Pour 2x2+x+3 : Δ=1−24=−23<0, la fonction renvoie 0 et la parabole ne coupe pas l'axe des abscisses. Pour x2−5x+6 : Δ=25−24=1>0, la fonction renvoie 2, et les racines sont 25−1=2 et 25+1=3.
c)
Elle calcule Δ=32−0=9>0 et renvoie 2. C'est faux : avec a=0 l'équation n'est pas du second degré, elle s'écrit 3x−6=0 et n'a qu'UNE solution, x=2. La formule du discriminant n'a de sens que pour a=0, hypothèse que le programme ne vérifie pas. On corrige en plaçant un test en tête : if a == 0: puis if b == 0: puis return 0 puis return 1. Ce cas a=0 est régulièrement introduit en contrôle par un paramètre, par exemple (m−1)x2+3x−6=0 avec m=1, et l'oublier coûte tous les points de la question.
d)
def racines(a, b, c): puis d = b*b - 4*a*c puis if d > 0: puis print((-b - sqrt(d))/(2*a), (-b + sqrt(d))/(2*a)) puis elif d == 0: puis print(-b/(2*a)), la fonction sqrt étant importée du module math. On n'écrit jamais sqrt(d) avant de savoir que d≥0 : la racine carrée d'un nombre négatif provoque une erreur qui interrompt le programme. Le test doit donc précéder le calcul, et non l'inverse.
Le fil : un programme de second degré est un arbre de cas, et chaque branche correspond à une phrase du cours. Les deux cas que l'on oublie sont toujours les mêmes, la racine double et le coefficient a nul.
def nb_racines(a, b, c):
if a == 0:
if b == 0:
return 0
return 1
d = b*b - 4*a*c
if d > 0:
return 2
elif d == 0:
return 1
else:
return 0
Partie B : problèmes et raisonnement (/50)
Exercice 6 : Espérance et écart-type d'une variable aléatoire
Une variable aléatoire X prend les valeurs 0, 1, 2 et 3 avec les probabilités respectives 0,1, 0,3, 0,4 et 0,2. En Python, on stocke x = [0, 1, 2, 3] et p = [0.1, 0.3, 0.4, 0.2].
a) Écrivez un programme qui calcule E(X) à l'aide d'une boucle, et donnez sa valeur.
b) Écrivez un programme qui calcule V(X) par la formule V(X)=E(X2)−E(X)2, puis l'écart-type.
c) Écrivez une fonction loi_valide(p) qui vérifie que la liste des probabilités définit bien une loi. Pourquoi ne faut-il pas y écrire if s == 1 ?
d) On répète l'expérience 10000 fois et l'on obtient une moyenne de 1,72. Ce résultat est-il compatible avec l'espérance calculée ? E(X) est-elle une valeur prise par X ?
Voir la correction
Réponses
a)E(X)=1,7
b)V(X)=0,81, σ=0,9
c)Tester abs(s - 1) < 1e-9 et la positivité
d)Compatible ; 1,7 n'est pas une valeur de X
a)
E = 0 puis for i in range(len(x)): puis E = E + x[i]*p[i] puis print(E). On obtient E(X)=0×0,1+1×0,3+2×0,4+3×0,2=0+0,3+0,8+0,6=1,7. La boucle parcourt les INDICES et non les valeurs, parce qu'il faut avancer simultanément dans les deux listes : c'est la structure à connaître dès que deux tableaux se correspondent terme à terme.
b)
E2 = 0 puis for i in range(len(x)): puis E2 = E2 + x[i]*x[i]*p[i], puis V = E2 - E*E et print(V, sqrt(V)). On a E(X2)=0×0,1+1×0,3+4×0,4+9×0,2=0,3+1,6+1,8=3,7, donc V(X)=3,7−1,72=3,7−2,89=0,81 et σ=0,81=0,9. Attention à la place des carrés : dans E(X2) on élève les VALEURS au carré avant de multiplier par les probabilités, alors que dans E(X)2 on élève au carré le résultat final. Les deux ne sont jamais égaux dès que X n'est pas constante, et leur différence est précisément la variance.
c)
def loi_valide(p): puis s = 0 puis for q in p: puis if q < 0: puis return False puis s = s + q puis return abs(s - 1) < 1e-9. On n'écrit pas s == 1 parce que la somme 0,1+0,3+0,4+0,2 ne vaut pas exactement 1 en machine : ces décimaux n'ont pas d'écriture finie en base deux, et la somme obtenue diffère de 1 d'environ 10−16. Le test d'égalité renverrait False pour une loi pourtant parfaitement valide. On teste donc un ÉCART, jamais une égalité, et l'on n'oublie pas la seconde condition d'une loi de probabilité : toutes les valeurs doivent être positives.
d)
Oui, c'est compatible. La loi des grands nombres dit que la moyenne observée sur un grand nombre de répétitions se rapproche de l'espérance : 1,72 est très proche de 1,7, l'écart de 0,02 est de l'ordre de nσ=1000,9=0,009 à quelques unités près, ce qui est banal. En revanche E(X)=1,7 n'est PAS une valeur prise par X, qui ne prend que des entiers : l'espérance est la moyenne pondérée théorique, pas un résultat possible de l'expérience. C'est la même chose que le nombre moyen d'enfants par famille.
Le fil : deux listes qui se correspondent se parcourent par les indices, et toute vérification numérique se fait avec une inégalité. Ces deux réflexes valent pour les probabilités comme pour les mesures de sciences.
E = 0
E2 = 0
for i in range(len(x)):
E = E + x[i]*p[i]
E2 = E2 + x[i]*x[i]*p[i]
V = E2 - E*E
print(E, V, sqrt(V))
Exercice 7 : Compléter un programme : résolution approchée par balayage
Soit f définie sur R par f(x)=x3+x−3. On admet que l'équation f(x)=0 possède une unique solution α, située entre 1 et 2.
Le programme suivant cherche un encadrement de α au centième. Trois éléments sont incomplets.
def f(x):
return x**3 + x - 3
k = ...
while f(k/100) < ... :
k = k + 1
print(..., k/100)
a) Complétez les trois éléments du programme.
b) Donnez l'encadrement obtenu, en précisant les deux valeurs de f qui le justifient.
c) Démontrez que la solution est bien unique sur R.
d) Combien de tours la boucle effectue-t-elle ? Combien en faudrait-il pour un encadrement au millième ?
Voir la correction
Réponses
a)k = 100 ; f(k/100) < 0 ; (k-1)/100
b)1,21<α<1,22
c)f′(x)=3x2+1>0 : f strictement croissante
d)22 tours ; 214 au millième
a)
On part de k=100, ce qui correspond à x=1, on avance tant que f reste négative, et l'on affiche l'encadrement final : k = 100, puis while f(k/100) < 0:, puis print((k-1)/100, k/100). Le balayage se fait sur un ENTIER k et non directement sur x, pour la raison vue en Seconde : additionner 0,01 des centaines de fois accumule les erreurs d'arrondi, alors qu'une division unique n'en accumule aucune.
b)
La boucle s'arrête à k=122, donc 1,21<α<1,22. Les deux valeurs qui le justifient sont f(1,21)=1,771561+1,21−3=−0,018439, encore négative, et f(1,22)=1,815848+1,22−3=0,035848, devenue positive. La fonction change donc de signe entre ces deux abscisses. Une valeur plus fine, f(1,213)≈−0,00223, montre que α≈1,2134.
c)
La fonction f est dérivable sur R avec f′(x)=3x2+1. Comme 3x2≥0, on a f′(x)≥1>0 pour tout réel x : f est STRICTEMENT CROISSANTE sur R. Elle prend donc au plus une fois chaque valeur, en particulier la valeur 0, ce qui donne l'unicité. L'existence vient du changement de signe entre f(1)=−1 et f(2)=7. Le programme, lui, ne démontre rien de tout cela : il trouve UNE solution, et rien dans son affichage ne dit qu'il n'y en a pas d'autres ailleurs.
d)
Elle part de k=100 et s'arrête à k=122, donc elle effectue 22 tours. Pour un encadrement au millième, on balaierait avec k/1000 à partir de k=1000 jusqu'à k=1214, soit 214 tours : diviser le pas par dix multiplie par dix le nombre de tours pour une décimale de plus. C'est le défaut du balayage, et c'est pourquoi on lui préfère la dichotomie quand la précision demandée est grande : celle-ci divise l'intervalle par deux à chaque tour et gagne une décimale toutes les trois ou quatre étapes.
Le fil : le programme FOURNIT un encadrement, le calcul de la dérivée DÉMONTRE qu'il n'y a rien d'autre à chercher. Une question de contrôle qui demande de justifier l'unicité attend le tableau de variations, jamais la sortie du programme.
def f(x):
return x**3 + x - 3
k = 100
while f(k/100) < 0:
k = k + 1
print((k-1)/100, k/100)
Exercice 8 : Cinq affirmations à corriger
Chacune des cinq affirmations suivantes est FAUSSE. Dites pourquoi, puis énoncez la version correcte.
a) « Le taux d'accroissement hf(a+h)−f(a) devient exactement égal à f′(a) lorsque l'on prend h=0. »
b) « Pour tester le signe du discriminant, if delta >= 0: return 2 suffit, puisqu'une racine double compte pour deux racines. »
c) « Si une suite converge vers L, alors la boucle while u < L finit toujours par s'arrêter. »
d) « L'espérance d'une variable aléatoire est la valeur qu'elle a le plus de chances de prendre. »
e) « Plus le pas d'un balayage est petit, plus le résultat obtenu en machine est précis, sans limite. »
Voir la correction
Réponses
a)f′(a) est une limite
b)Δ=0 : une racine double
c)Seulement pour un seuil strictement inférieur à la limite
d)C'est le mode, pas l'espérance
e)Il existe un pas optimal
a)
FAUX. Pour h=0, le quotient n'existe pas : son dénominateur est nul. Le nombre dérivé est une LIMITE, c'est-à-dire la valeur dont le taux se rapproche autant qu'on veut quand h tend vers 0, sans jamais y être évalué. Version correcte : « f′(a) est la limite du taux d'accroissement quand h tend vers 0 ». La différence est visible sur l'exercice 4 : le taux vaut 1+3h+h2, expression qui a bien une valeur en 0, mais seulement APRÈS simplification par h, opération licite uniquement pour h=0.
b)
FAUX. Si Δ=0, l'équation admet UNE racine, dite double, x0=−2ab : la parabole est tangente à l'axe des abscisses et ne le coupe qu'en un point. Version correcte : « on teste Δ>0 pour deux racines, puis Δ=0 pour une racine double, puis Δ<0 pour aucune ». Dire qu'une racine double « compte pour deux » a un sens en factorisation, ax2+bx+c=a(x−x0)2, mais pas quand on dénombre les solutions.
c)
FAUX. Une suite convergente peut approcher sa limite sans jamais l'atteindre ni la dépasser. Avec un=15−13×0,8n de l'exercice 2, la boucle while u < 15 ne s'arrête JAMAIS. Version correcte : « la boucle s'arrête pour tout seuil strictement inférieur à la limite, si la suite est croissante ». C'est la vérification à faire avant d'écrire tout programme de seuil : le seuil demandé est-il réellement franchi ?
d)
FAUX, cela confond espérance et mode. L'espérance est la moyenne PONDÉRÉE des valeurs, E(X)=∑xipi, et elle n'est en général même pas une valeur prise par X : à l'exercice 6, E(X)=1,7 alors que X ne prend que les entiers 0 à 3. La valeur la plus probable, ici 2 avec p=0,4, s'appelle le mode. Version correcte : « l'espérance est la moyenne des valeurs pondérée par leurs probabilités ».
e)
FAUX. Deux erreurs s'opposent : l'erreur de méthode, proportionnelle au pas, et l'erreur d'arrondi, qui augmente quand le pas diminue, car on soustrait des nombres de plus en plus proches. En dessous d'un certain pas, le résultat se dégrade au lieu de s'améliorer, jusqu'au cas extrême de l'exercice 4 où 1+10−17 vaut 1. Version correcte : « il existe un pas optimal, au-delà duquel la précision machine limite le gain ».
Ces cinq erreurs se ressemblent : chacune consiste à transporter en machine une propriété mathématique exacte, ou l'inverse. L'ordinateur travaille avec des nombres approchés et un nombre fini d'étapes, ce que le cours d'analyse ne fait jamais.
Exercice 9 : Décroissance radioactive et méthode d'Euler
L'iode 131 a une demi-vie de 8,0 jours. Le nombre de noyaux restants est modélisé par N(t)=N0e−λt, où t est en jours et λ=0,086643 jour−1, valeur choisie pour que e−8λ=21. La vitesse de désintégration vérifie N′(t)=−λN(t).
On approche l'évolution par la méthode d'Euler : sur un petit intervalle Δt, on considère la vitesse comme constante, ce qui donne Nk+1=Nk(1−λΔt).
a) Vérifiez à la calculatrice que e−8λ≈0,5, puis écrivez un programme qui affiche la fraction de noyaux restants après 8 jours avec un pas Δt=1 jour.
b) Comparez le résultat obtenu à la valeur exacte. Quel est l'écart relatif ?
c) Reprenez avec un pas Δt=0,1 jour. Que constate-t-on sur l'erreur ?
d) Démontrez que la méthode d'Euler sous-estime TOUJOURS le nombre de noyaux restants.
Voir la correction
Réponses
a)e−8λ≈0,5 ; programme : ≈0,4843
b)Écart relatif ≈3,1%
c)≈0,4985, écart ≈0,3% : erreur divisée par dix
d)1−x<e−x pour x>0
a)
e−8×0,086643=e−0,693144≈0,5000 : c'est bien la demi-vie de 8 jours. Le programme s'écrit lam = 0.086643 puis N = 1 puis for k in range(8): puis N = N*(1 - lam*1) puis print(N). On travaille en fraction, c'est-à-dire avec N0=1, ce qui évite d'avoir à choisir un nombre de noyaux et rend le résultat directement comparable à 21.
b)
Le programme affiche environ 0,4843. La valeur exacte est 21 par définition de la demi-vie, ce que confirme le modèle : N(8)=N0e−8λ=2N0. L'écart relatif vaut 0,50,5−0,4843≈3,1%, ce qui est considérable pour une grandeur physique : la méthode d'Euler avec un pas d'un jour n'est pas utilisable ici, parce que le pas n'est pas petit devant la demi-vie.
c)
On écrit for k in range(80): puis N = N*(1 - lam*0.1), et l'on obtient environ 0,4985, soit un écart relatif de 0,3%. Diviser le pas par dix a divisé l'erreur par dix, ce qui est la signature de la méthode d'Euler : son erreur est proportionnelle au pas. Pour gagner un facteur cent sur la précision, il faut donc cent fois plus de tours de boucle, et c'est ce compromis qui décide en pratique du pas choisi.
d)
Sur un pas, la méthode donne Nk(1−λΔt) alors que la solution exacte donne Nke−λΔt. Or pour tout réel x>0 on a 1−x<e−x : il suffit d'étudier g(x)=e−x−1+x, dont la dérivée g′(x)=1−e−x est strictement positive pour x>0, avec g(0)=0, donc g(x)>0. En posant x=λΔt, chaque pas d'Euler retire donc un peu TROP de noyaux, et ces sous-estimations se multiplient d'un pas à l'autre. La raison physique est claire : Euler applique pendant tout l'intervalle la vitesse de désintégration du DÉBUT du pas, alors que la vitesse réelle diminue à mesure que les noyaux disparaissent.
Le fil : la méthode d'Euler transforme la relation N′=−λN en suite géométrique de raison 1−λΔt, objet parfaitement connu du programme de Première. L'exponentielle est la limite de ces suites quand le pas tend vers zéro, et l'inégalité 1−x<e−x dit dans quel sens on se trompe.
lam = 0.086643
N = 1
for k in range(80):
N = N*(1 - lam*0.1)
print(N)
Exercice 10 : Problème de synthèse : trajectoire d'un ballon
Un ballon est frappé depuis une hauteur de 1,8 m. Dans un repère où x est la distance horizontale en mètres et y la hauteur en mètres, sa trajectoire est décrite par y(x)=−0,05x2+0,8x+1,8.
Un mur de 4 m de haut se dresse à 14 m du point de frappe.
La figure ci-dessous représente la situation.
a) Écrivez un programme qui balaie x de 0 à 20 m par pas de 0,5 m et affiche la hauteur maximale atteinte, puis donnez cette valeur.
b) Retrouvez l'abscisse du sommet par la dérivée, et donnez la hauteur maximale exacte.
c) Calculez la portée du tir, c'est-à-dire la distance au bout de laquelle le ballon touche le sol.
d) Le ballon passe-t-il au-dessus du mur ? Écrivez le programme qui répond, et démontrez le résultat par le calcul.
Voir la correction
Réponses
a)5 m
b)y′(x)=−0,1x+0,8 : sommet en 8 m, hauteur 5 m
c)Portée 18 m
d)y(14)=3,2<4 : le ballon ne passe pas
a)
def y(x): puis return -0.05*x*x + 0.8*x + 1.8, puis M = 0 puis for k in range(0, 41): puis if y(k/2) > M: puis M = y(k/2) puis print(M). Le programme affiche 5, atteint pour x=8 m. Comme d'habitude, on boucle sur l'entier k et l'on pose x=2k ; range(0, 41) donne bien les 41 abscisses de 0 à 20 m.
b)
La dérivée vaut y′(x)=−0,1x+0,8, qui s'annule en x=0,10,8=8 m. Elle est positive avant et négative après, donc y atteint son MAXIMUM en 8 : y(8)=−0,05×64+0,8×8+1,8=−3,2+6,4+1,8=5 m. Le balayage donnait la même valeur, mais par chance : le sommet tombait exactement sur une abscisse balayée. Avec un pas de 0,7 m, il aurait donné une valeur légèrement inférieure, et c'est pourquoi une hauteur maximale se justifie toujours par la dérivée ou par la forme canonique.
c)
On résout −0,05x2+0,8x+1,8=0. En multipliant par −20 : x2−16x−36=0, donc Δ=256+144=400 et Δ=20. Les racines sont 216−20=−2 et 216+20=18. Seule la racine positive a un sens physique : la portée est de 18 m. La racine −2 correspond au point d'où serait parti le ballon s'il avait décollé du sol avec la même parabole, information sans objet ici.
d)
if y(14) > 4: puis print("passe") puis else: puis print("touche le mur"). On calcule y(14)=−0,05×196+0,8×14+1,8=−9,8+11,2+1,8=3,2 m, ce qui est INFÉRIEUR à 4 m : le ballon ne passe pas. On peut préciser où il aurait fallu placer le mur : résoudre y(x)=4 donne −0,05x2+0,8x−2,2=0, soit x2−16x+44=0, de discriminant 256−176=80 et de racines 216±45=8±25, c'est-à-dire environ 3,53 m et 12,47 m. Le ballon est donc au-dessus de 4 m entre ces deux abscisses seulement, et le mur à 14 m est trop loin de 1,5 m environ.
Le fil de la série se referme ici : le balayage EXPLORE, la dérivée LOCALISE, le discriminant DÉCIDE. Un programme seul aurait répondu à d) mais n'aurait donné ni la hauteur exacte, ni la portée, ni l'intervalle de franchissement, qui sont les trois résultats attendus dans un exercice de contrôle.
def y(x):
return -0.05*x*x + 0.8*x + 1.8
M = 0
for k in range(0, 41):
if y(k/2) > M:
M = y(k/2)
print(M)
if y(14) > 4:
print("passe")
else:
print("touche le mur")
Partie C : les classiques (/50)
Exercice 11 : Construire et exploiter une liste de termes
On considère la suite définie pour tout entier naturel n par un=n2−7n+15, et le programme suivant.
L = [n*n - 7*n + 15 for n in range(10)]
print(L)
print(min(L))
a) Quelle liste contient la variable L ?
b) Que renvoie min(L) ? Pour quels rangs ce minimum est-il atteint ?
c) Complétez le programme pour qu'il affiche le nombre de termes de L strictement inférieurs à 10, et donnez ce nombre.
d) On construit D = [L[i+1] - L[i] for i in range(9)]. Que contient D ? Justifiez par le calcul de un+1−un.
e) Que renvoie sum(L) ?
Voir la correction
Réponses
a)[15, 9, 5, 3, 3, 5, 9, 15, 23, 33]
b)3, aux rangs 3 et 4
c)6 termes
d)D = [-6, -4, ..., 10] : un+1−un=2n−6
e)120
a)
La liste en compréhension calcule un pour n allant de 0 à 9, soit dix termes : L = [15, 9, 5, 3, 3, 5, 9, 15, 23, 33]. On contrôle deux termes : u0=15 et u9=81−63+15=33 ✓.
b)
min(L) renvoie 3, atteint aux rangs 3 et 4 (les indices 3 et 4 de la liste, qui commence à l'indice 0). C'est cohérent avec la fonction x↦x2−7x+15, dont le sommet est en x=3,5, au milieu de 3 et 4, qui sont donc à égale distance du sommet.
c)
On ajoute un compteur : c = 0, puis for u in L:, puis if u < 10:, puis c = c + 1, et enfin print(c). Les termes inférieurs à 10 sont 9, 5, 3, 3, 5 et 9 : le programme affiche 6. Parcourir directement les VALEURS de la liste suffit ici, puisqu'on n'a pas besoin des rangs.
d)
D = [-6, -4, -2, 0, 2, 4, 6, 8, 10]. En effet un+1−un=(n+1)2−7(n+1)+15−(n2−7n+15)=2n+1−7=2n−6. Les écarts forment une suite ARITHMÉTIQUE de raison 2 : c'est la signature d'une suite du second degré. Le signe de 2n−6 explique aussi b) : la suite décroît tant que n<3, stagne de u3 à u4, puis croît.
e)
sum(L) renvoie 15+9+5+3+3+5+9+15+23+33=120.
Une liste en compréhension est la traduction directe de « la liste des un pour n de 0 à 9 ». Les fonctions min, sum et les listes d'écarts transforment ensuite des questions de cours, minimum, sens de variation, somme, en une ligne de programme ; mais seul le calcul de un+1−un justifie ce que la liste montre.
L = [n*n - 7*n + 15 for n in range(10)]
c = 0
for u in L:
if u < 10:
c = c + 1
print(c)
D = [L[i+1] - L[i] for i in range(9)]
print(D, sum(L))
Exercice 12 : La méthode d'Archimède pour approcher π
Archimède encadrait π par les périmètres de polygones réguliers inscrits dans un cercle de rayon 1. On note cn le côté du polygone régulier à n côtés inscrit ; son demi-périmètre 2ncn approche π par défaut.
On admet la formule de doublement c2n=2−4−cn2, obtenue par le théorème de Pythagore dans le cercle.
La figure ci-dessous représente la situation.
from math import sqrt
def archimede(k):
c = 1
n = 6
for i in range(k):
...
...
return n*c/2
a) Justifiez que c6=1, puis calculez le demi-périmètre de l'hexagone.
b) Calculez c12 au millionième et le demi-périmètre du dodécagone au millième.
c) Écrivez un programme qui part de l'hexagone et double k fois le nombre de côtés, puis affiche le demi-périmètre. Donnez les valeurs obtenues pour 48 et 96 côtés, au millième.
d) En doublant une vingtaine de fois, le programme affiche des valeurs de plus en plus fausses, puis 0. Expliquez ce phénomène.
e) Montrez que 2−4−c2=2+4−c2c2, et déduisez-en une formule de doublement qui évite le problème.
Voir la correction
Réponses
a)c6=1, demi-périmètre 3
b)c12≈0,517638 ; ≈3,106
c)≈3,139 et ≈3,141
d)Soustraction de nombres presque égaux : perte des chiffres significatifs
e)c2n=2+4−cn2cn
a)
L'hexagone régulier inscrit se découpe en six triangles équilatéraux de côté égal au rayon : c6=1. Son demi-périmètre vaut 26×1=3, première approximation de π, déjà connue des Babyloniens.
On initialise c = 1 et n = 6, puis, dans une boucle for exécutée k fois, on remplace c par sqrt(2 - sqrt(4 - c*c)) et n par 2*n ; on affiche enfin n*c/2. Avec 48 côtés, on obtient environ 3,13935, soit 3,139 ; avec 96 côtés, environ 3,14103, soit 3,141. C'est l'encadrement du polygone à 96 côtés qu'avait atteint Archimède.
d)
Quand c devient très petit, 4−c2 est extrêmement proche de 2, et la différence 2−4−c2 soustrait deux nombres presque égaux. Les flottants ne gardant qu'une quinzaine de chiffres significatifs, cette différence perd presque tous ses chiffres justes, puis vaut exactement 0 quand c2 devient négligeable devant 4. C'est le même phénomène que pour le taux d'accroissement de l'exercice 4 avec un pas trop petit.
e)
On multiplie par la quantité conjuguée : (2−4−c2)(2+4−c2)=4−(4−c2)=c2, d'où l'égalité. Donc c2n=2+4−cn2cn2=2+4−cn2cn. Cette formule n'ADDITIONNE que des nombres positifs : plus aucune soustraction de nombres voisins, et le programme converge vers 3,14159265358979 sans jamais se dégrader.
Deux formules mathématiquement égales peuvent se comporter très différemment en machine. La quantité conjuguée, outil de calcul de limites au lycée, est aussi l'outil qui réécrit une soustraction instable en une division stable : c'est un réflexe de programmeur autant que de mathématicien.
from math import sqrt
def archimede(k):
c = 1
n = 6
for i in range(k):
c = c/sqrt(2 + sqrt(4 - c*c))
n = 2*n
return n*c/2
print(archimede(3), archimede(4))
Exercice 13 : Géométrie repérée en Python
Un point du plan est représenté par une liste de deux nombres, par exemple A = [1, 2]. On veut écrire trois fonctions de géométrie repérée.
a) Écrivez une fonction alignes(A, B, C) qui renvoie True si les trois points sont alignés, à l'aide du déterminant des vecteurs AB et AC. Que renvoie-t-elle pour A(1;2), B(4;8) et C(−2;−4) ?
b) Écrivez une fonction equation(A, B) qui renvoie les coefficients a, b, c d'une équation cartésienne ax+by+c=0 de la droite (AB). Donnez le résultat pour A(1;2) et B(4;8).
c) Écrivez une fonction perpendiculaires(A, B, C, D) qui teste si (AB)⊥(CD). Que renvoie-t-elle pour A(1;2), B(4;8), C(1;2) et D(5;0) ?
d) Avec des points à coordonnées décimales, alignes([0, 0], [0.1, 0.3], [0.3, 0.9]) renvoie False. Pourquoi, et comment corriger la fonction ?
Voir la correction
Réponses
a)Déterminant nul : True
b)a=6, b=−3, c=0 : 2x−y=0
c)AB⋅CD=0 : True
d)Arrondis binaires : tester abs(det) < 1e-9
a)
Les vecteurs AB(xB−xA;yB−yA) et AC sont colinéaires si et seulement si leur déterminant det=(xB−xA)(yC−yA)−(yB−yA)(xC−xA) est nul. Ici AB(3;6) et AC(−3;−6) : det=3×(−6)−6×(−3)=0. La fonction renvoie True.
b)
Un vecteur directeur est AB(u;v) ; un vecteur normal est (v;−u), d'où a=v, b=−u, puis c=−(axA+byA). Pour AB(3;6) : a=6, b=−3, c=−(6−6)=0. La droite a pour équation 6x−3y=0, soit 2x−y=0. Vérification avec B : 24−24=0 ✓.
c)
Les droites sont perpendiculaires si et seulement si AB⋅CD=0. AB(3;6) et CD(4;−2) : 12−12=0. La fonction renvoie True.
d)
Mathématiquement, det=0,1×0,9−0,3×0,3=0,09−0,09=0. Mais 0,1, 0,3 et 0,9 n'ont pas d'écriture finie en base deux : le calcul en machine donne un nombre de l'ordre de 10−17, et le test det == 0 échoue. On corrige en testant abs(det) < 1e-9. Tout test d'égalité entre flottants issus d'un calcul se remplace par un test d'écart.
La géométrie repérée se programme presque mot pour mot : un déterminant nul pour la colinéarité, un produit scalaire nul pour l'orthogonalité, l'échange des coordonnées pour passer du vecteur directeur au vecteur normal. Le seul ajout propre à la machine est la tolérance, indispensable dès que les coordonnées ne sont pas entières.
def alignes(A, B, C):
d = (B[0]-A[0])*(C[1]-A[1]) - (B[1]-A[1])*(C[0]-A[0])
return abs(d) < 1e-9
def equation(A, B):
u, v = B[0]-A[0], B[1]-A[1]
a, b = v, -u
return a, b, -(a*A[0] + b*A[1])
def perpendiculaires(A, B, C, D):
p = (B[0]-A[0])*(D[0]-C[0]) + (B[1]-A[1])*(D[1]-C[1])
return abs(p) < 1e-9
Exercice 14 : La suite de Syracuse
On part d'un entier n≥1. S'il est pair, on le divise par 2 ; s'il est impair, on le multiplie par 3 et on ajoute 1. On recommence jusqu'à obtenir 1. La conjecture de Syracuse affirme qu'on atteint toujours 1, quel que soit l'entier de départ ; elle n'a jamais été démontrée.
Le TEMPS DE VOL est le nombre d'étapes pour atteindre 1, l'ALTITUDE MAXIMALE la plus grande valeur rencontrée.
a) Écrivez une fonction vol(n) qui renvoie la liste des valeurs, de n jusqu'à 1 compris.
b) Donnez la liste obtenue pour n=7, son temps de vol et son altitude maximale.
c) Pour n=27, le programme donne un temps de vol de 111. Quelle altitude maximale affiche-t-il ?
d) Écrivez un programme qui cherche, parmi les entiers de 1 à 99, celui dont le temps de vol est le plus long. Il affiche 97. Quel est ce temps de vol ?
e) Pourquoi la boucle while de la fonction vol ne constitue-t-elle pas une démonstration de la conjecture ?
Voir la correction
Réponses
a)Boucle while n != 1 avec n // 2 ou 3*n + 1
b)Temps de vol 16, altitude maximale 52
c)9232
d)118 étapes
e)Un programme ne teste qu'un nombre fini d'entiers
a)
On range n dans une liste, puis tant que n != 1 : si n % 2 == 0, on remplace n par n // 2, sinon par 3*n + 1, et l'on ajoute chaque nouvelle valeur à la liste. L'opérateur // donne le quotient entier et garde un entier ; / donnerait un flottant, 11,0 au lieu de 11.
b)
7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. La liste compte 17 valeurs, donc 16 étapes : le temps de vol vaut 16, c'est-à-dire len(L) - 1, et non len(L). L'altitude maximale vaut 52, bien plus que le départ.
c)
L'altitude maximale est 9232, atteinte en partant de 27 : un nombre de départ modeste peut monter très haut avant de redescendre, et c'est ce comportement erratique qui rend la conjecture si difficile.
d)
On garde le meilleur temps dans une variable, en parcourant for k in range(1, 100) et en comparant len(vol(k)) - 1 au record. Le record est atteint pour k=97, avec un temps de vol de 118 étapes ; son altitude maximale est aussi 9232, car la trajectoire de 97 rejoint celle de 27.
e)
Le programme vérifie la conjecture pour chaque entier TESTÉ, en s'arrêtant quand il atteint 1. Si un entier ne l'atteignait jamais, la boucle tournerait indéfiniment et le programme ne répondrait rien : il ne peut ni prouver que tous les entiers conviennent, puisqu'il y en a une infinité, ni prouver qu'un entier ne convient pas. Des vérifications ont été menées sur des milliards de milliards d'entiers ; ce ne sont pas des démonstrations.
La suite de Syracuse est définie par récurrence, mais sans aucune formule explicite ni sens de variation : c'est l'exemple type où seul le programme permet d'explorer. Il fournit des conjectures et des contre-exemples potentiels ; la démonstration, elle, reste un travail de mathématicien, ici toujours inachevé.
def vol(n):
L = [n]
while n != 1:
if n % 2 == 0:
n = n // 2
else:
n = 3*n + 1
L.append(n)
return L
print(len(vol(7)) - 1, max(vol(7)), max(vol(27)))
record, meilleur = 0, 1
for k in range(1, 100):
t = len(vol(k)) - 1
if t > record:
record, meilleur = t, k
print(meilleur, record)
Exercice 15 : La fluctuation des moyennes d'échantillons
On lance un dé équilibré ; on note X le résultat. Un ÉCHANTILLON de taille n est une série de n lancers indépendants, dont on calcule la moyenne m.
Le programme ci-dessous simule 1000 échantillons de taille n=100 et compte la proportion de ceux dont la moyenne m vérifie ∣m−μ∣≤n2σ, où μ et σ sont l'espérance et l'écart-type de X.
from random import randint
from math import sqrt
def moyenne(n):
...
mu, sigma = 3.5, sqrt(35/12)
c = 0
for i in range(1000):
m = moyenne(100)
if abs(m - mu) <= 2*sigma/sqrt(100):
c = c + 1
print(c/1000)
a) Calculez μ=E(X) et σ=σ(X), ce dernier au millième.
b) Calculez 1002σ au millième. Complétez la fonction moyenne(n) du programme.
c) Le programme affiche une proportion d'environ 0,95. Les résultats diffèrent d'une exécution à l'autre : est-ce une erreur ?
d) On passe à des échantillons de taille 400. Que devient la demi-largeur n2σ ?
e) Quelle taille minimale d'échantillon faut-il pour que n2σ≤0,1 ?
Voir la correction
Réponses
a)μ=3,5, σ=1235≈1,708
b)≈0,342
c)Non : la proportion fluctue autour de 0,95
d)≈0,171, divisée par deux
e)n≥1167
a)
μ=61+2+3+4+5+6=3,5. E(X2)=61+4+9+16+25+36=691, donc V(X)=691−3,52=1235 et σ=1235≈1,708.
b)
102×1,708≈0,342. La fonction moyenne(n) additionne n tirages randint(1, 6) dans un accumulateur initialisé à 0, puis renvoie la somme divisée par n.
c)
Non. Chaque exécution tire de nouveaux nombres au hasard, donc de nouveaux échantillons : la proportion observée fluctue elle aussi, en restant voisine de 0,95. C'est le résultat attendu : environ 95% des moyennes d'échantillons tombent à moins de n2σ de l'espérance.
d)
4002σ=202×1,708≈0,171 : quatre fois plus de lancers divisent la demi-largeur par DEUX seulement, car 400=2100.
e)
n2σ≤0,1⟺n≥20σ≈34,16⟺n≥(20σ)2=400×1235≈1166,7. Il faut au moins 1167 lancers par échantillon.
La moyenne d'un échantillon fluctue autour de l'espérance, et d'autant moins que l'échantillon est grand ; mais la précision progresse comme n, pas comme n. C'est pourquoi un sondage deux fois plus précis coûte quatre fois plus cher, et c'est ce que la simulation permet d'observer avant de le démontrer.
def moyenne(n):
s = 0
for i in range(n):
s = s + randint(1, 6)
return s/n
Partie D : les listes et les algorithmes du programme (/60)
En Première, la seule notion nouvelle d'algorithmique est la LISTE. Le programme ci-dessous construit de trois façons la liste des diviseurs de 36, puis fait travailler la suppression d'éléments et le parcours par indices.
# programme 1 : trois façons de construire une liste
L1 = [1, 2, 3, 4, 6, 9, 12, 18, 36]
L2 = []
for d in range(1, 37):
if 36 % d == 0:
L2.append(d)
L3 = [d for d in range(1, 37) if 36 % d == 0]
# programme 2 : retirer les nombres pairs de M
M = [2, 4, 5, 6, 8, 9]
for x in M:
if x % 2 == 0:
M.remove(x)
print(M)
# programme 3 : un parcours par indices
s = 0
for i in range(len(L3)):
if i % 2 == 0:
s = s + L3[i]
print(s)
a) Nommez les trois façons de générer une liste utilisées dans le programme 1. Les trois listes sont-elles égales ? Que valent len(L3) et L3[4] ?
b) On pose ET = [n for n in range(1, 41) if n % 4 == 0 and n % 6 == 0] et OU = [n for n in range(1, 41) if n % 4 == 0 or n % 6 == 0]. Donnez la liste ET, puis len(OU). Quel lien avec les ensembles ?
c) Le programme 2 devait retirer de M tous les nombres pairs. Qu'affiche-t-il ? Expliquez le résultat, puis choisissez une ligne qui fait correctement le travail.
d) Qu'affiche le programme 3 ? Et si l'on remplace sa boucle par un parcours des VALEURS, for x in L3, avec le test if x % 2 == 0 et l'ajout s = s + x ?
c)[4, 5, 8, 9] : remove décale la liste ; M = [x for x in M if x % 2 != 0] donne [5, 9]
d)58 par les indices pairs ; 78 par les valeurs paires
a)
L1 est écrite EN EXTENSION : on énumère ses éléments entre crochets. L2 est construite PAR AJOUTS SUCCESSIFS : on part de la liste vide [] et la méthode append ajoute un élément à la fin, à chaque diviseur rencontré. L3 est écrite EN COMPRÉHENSION : c'est la traduction mot à mot de l'ensemble {d∈{1,…,36}:d divise 36}, la condition if jouant le rôle du « tel que ». Les deux boucles parcourent les entiers dans l'ordre croissant, donc les trois listes sont égales, éléments ET ordre compris : [1, 2, 3, 4, 6, 9, 12, 18, 36]. On a len(L3) =9. Les indices partent de 0 : L3[0] vaut 1, L3[1] vaut 2, et L3[4] est le CINQUIÈME élément, 6, pas 4. Le dernier élément est L3[8], c'est-à-dire L3[len(L3) - 1] ; écrire L3[9] provoque une erreur, l'indice n'existe pas.
b)
Le « and » ne garde que les entiers multiples de 4 ET de 6, c'est-à-dire les multiples de 12 : ET = [12, 24, 36]. Le « or » garde ceux qui sont multiples de 4 OU de 6, et c'est un « ou » INCLUSIF : un multiple des deux est gardé une seule fois. Il y a 10 multiples de 4 et 6 multiples de 6 entre 1 et 40 ; les ajouter compte deux fois les trois multiples de 12, donc len(OU) =10+6−3=13. En notant A et B ces deux ensembles, ET décrit l'intersection A∩B et OU la réunion A∪B, et l'on vient de retrouver Card(A∪B)=Card(A)+Card(B)−Card(A∩B). Répondre 16, c'est compter deux fois les multiples de 12. Un « ou » EXCLUSIF, qui les écarterait, donnerait 13−3=10 : en mathématiques comme en Python, « ou » est toujours inclusif.
c)
Il affiche [4, 5, 8, 9], et non [5, 9]. La boucle for avance d'un INDICE à chaque tour, pendant que remove décale vers la gauche tout ce qui suit l'élément retiré. Tour 1 : indice 0, x vaut 2, on le retire, M devient [4, 5, 6, 8, 9]. Tour 2 : indice 1, x vaut 5 : le 4, passé à l'indice 0, a été SAUTÉ. Tour 3 : indice 2, x vaut 6, retiré, M devient [4, 5, 8, 9]. Tour 4 : indice 3, x vaut 9 : le 8 a été sauté à son tour. La règle : on ne supprime jamais dans une liste pendant qu'on la parcourt. La bonne ligne construit une NOUVELLE liste par compréhension, M = [x for x in M if x % 2 != 0], qui donne [5, 9]. Pour mémoire, remove(v) retire la première occurrence de la VALEUR v, alors que pop(i) et del M[i] retirent l'élément d'INDICE i : M.remove(9) et M.pop(9) ne font pas du tout la même chose.
d)
Le programme 3 parcourt les INDICES 0 à 8 et additionne les éléments d'indice pair, L3[0], L3[2], L3[4], L3[6] et L3[8] : 1+3+6+12+36=58. La version modifiée parcourt les VALEURS et additionne celles qui sont paires : 2+4+6+12+18+36=78. Les deux programmes se ressemblent ligne à ligne et ne calculent pas la même chose : dans for i in range(len(L3)), le test porte sur la POSITION ; dans for x in L3, il porte sur la VALEUR. On parcourt par indices quand la position compte (voisins, rang d'un élément), et l'on itère sur les éléments sinon, ce qui est plus court et plus sûr.
Le fil de la partie D commence ici : une liste est un ensemble qu'on a RANGÉ. La compréhension traduit « l'ensemble des ... tels que ... », le and et le or traduisent l'intersection et la réunion, et le rang d'un élément se compte à partir de 0.
Exercice 17 : Factorielle et suite de Fibonacci
Pour un entier n⩾1, on note n!=1×2×⋯×n la FACTORIELLE de n. La suite de Fibonacci est définie par F0=0, F1=1 et, pour tout entier n, Fn+2=Fn+1+Fn.
def fact(n):
p = 1
for k in range(1, n + 1):
p = p * k
return p
def fibo(n):
a, b = 0, 1
for k in range(n):
a, b = b, a + b
return a
a) Que renvoie fact(6) ? Que renverrait-elle si l'on initialisait p à 0 ?
b) Écrivez une boucle while qui affiche le plus petit entier n tel que n!>106, et donnez cet entier en le justifiant par deux valeurs.
c) Montrez qu'après k tours de boucle, a contient Fk et b contient Fk+1. Que renvoie fibo(12) ?
d) Un élève remplace la ligne a, b = b, a + b par les deux lignes a = b puis b = a + b. Que renvoie alors fibo(12) ?
e) On construit la liste F des termes F0 à F15 par ajouts successifs, puis P = [f for f in F if f % 2 == 0]. Combien la liste P contient-elle d'éléments ? Quels rangs ont les termes pairs ?
Voir la correction
Réponses
a)720 ; avec p = 0, la fonction renvoie toujours 0
b)10, car 9!=362880⩽106<10!=3628800
c)Après k tours, a =Fk et b =Fk+1 ; fibo(12) renvoie 144
d)2048=211 : b double à chaque tour
e)6 termes pairs, aux rangs multiples de 3
a)
La boucle multiplie p successivement par 1, 2, 3, 4, 5 et 6 : 1×2×3×4×5×6=720, donc fact(6) renvoie 720. Initialisée à 0, la variable p resterait nulle à chaque multiplication, et la fonction renverrait 0 pour tout n. Un accumulateur de PRODUIT s'initialise à 1, élément neutre de la multiplication, comme un accumulateur de somme s'initialise à 0. Remarquer aussi le range(1, n + 1) : range(n) ferait démarrer k à 0 et annulerait le produit dès le premier tour.
b)
Le nombre de tours n'est pas connu d'avance, d'où un while : n = 1, p = 1, puis tant que p <= 10**6, on fait n = n + 1 puis p = p * n, et l'on affiche n à la sortie. On met à jour n AVANT de multiplier, pour que p contienne toujours n!. Le programme affiche 10 : en effet 9!=362880⩽106 et 10!=3628800>106. La factorielle croît plus vite que toute suite géométrique : chaque tour multiplie par un facteur qui grandit lui-même.
c)
Avant la boucle, k=0 tour : a vaut 0=F0 et b vaut 1=F1. Si après k tours a vaut Fk et b vaut Fk+1, le tour suivant range dans a l'ancien b, soit Fk+1, et dans b l'ancien a plus l'ancien b, soit Fk+Fk+1=Fk+2 : la propriété passe au tour k+1. Après n tours, a contient donc Fn. Les termes sont 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 : fibo(12) renvoie F12=144. L'affectation SIMULTANÉE a, b = b, a + b calcule les deux membres de droite avec les ANCIENNES valeurs, avant de ranger quoi que ce soit.
d)
Avec deux lignes, la seconde utilise le NOUVEAU a, qui vaut déjà b : b = a + b revient à b = b + b, et b DOUBLE à chaque tour. Tour 1 : a =1, b =2 ; tour 2 : a =2, b =4 ; tour 3 : a =4, b =8. Après k tours, a vaut 2k−1 : fibo(12) renvoie 211=2048. Le programme tourne sans erreur et produit une suite géométrique au lieu de Fibonacci. Pour écrire la version en deux temps sans affectation simultanée, il faut une variable de sauvegarde : c = a + b, puis a = b, puis b = c.
e)
F = [0, 1] puis, pour n de 2 à 15, F.append(F[n - 1] + F[n - 2]), ce qui donne les seize termes de F0=0 à F15=610. Les termes pairs sont 0, 2, 8, 34, 144 et 610 : P contient 6 éléments, aux rangs 0, 3, 6, 9, 12 et 15, les multiples de 3. La liste le montre, le calcul l'explique : pair plus impair donne impair, impair plus impair donne pair, donc les parités se répètent selon le motif pair, impair, impair, pair, impair, impair... de période 3.
Deux suites, deux leçons de liste : la factorielle est une accumulation qu'on arrête par un seuil, Fibonacci une récurrence à deux termes qui exige de garder les deux derniers, et la liste de ses termes fait APPARAÎTRE une régularité que le calcul démontre ensuite.
Exercice 18 : Sécantes pour un pas donné, puis méthode de Newton
Soit f la fonction définie sur [0;2] par f(x)=x3+2x−5. On dresse d'abord la liste des coefficients directeurs des sécantes pour un pas h donné, puis on approche la solution de f(x)=0 par la méthode de Newton. Dans le second programme, une ligne est à compléter.
def f(x):
return x**3 + 2*x - 5
def d(x):
return 3*x**2 + 2
h = 0.5
X = [k*h for k in range(4)]
P = [(f(x + h) - f(x))/h for x in X]
print(P)
x, n, ecart = 1, 0, 1
while ecart > 10**-6:
y = ...
ecart = abs(y - x)
x = y
n = n + 1
print(x, n)
a) Quelle liste X contient-elle ? Que contient P ? Donnez son premier et son dernier élément.
b) On reprend le programme avec h = 0.25 et X = [k*h for k in range(8)]. Combien P contient-elle d'éléments ? Que vaut le premier ? Que représente cette liste quand le pas diminue ?
c) Montrez que l'équation f(x)=0 a une unique solution α dans [1;2]. Déterminez l'équation de la tangente en 1 et l'abscisse x1 du point où elle coupe l'axe des abscisses.
d) Justifiez qu'à chaque étape, xk+1=xk−f′(xk)f(xk), puis calculez x2.
e) Choisissez la ligne qui complète le second programme, puis donnez le nombre de tours et la valeur affichée, au millionième.
b)8 pentes, la première 2,0625 ; elles approchent f′(x)=3x2+2
c)f′>0, f(1)<0<f(2) ; tangente y=5x−7, x1=1,4
d)x2=1,4−7,880,544≈1,3310
e)y = x - f(x)/d(x) ; 5 tours ; α≈1,328269
a)
X = [0, 0.5, 1.0, 1.5] : les abscisses de 0 à 1,5 avec le pas 0,5, quatre valeurs puisque range(4) produit 0, 1, 2, 3. Chaque élément de P est la pente de la corde entre les points d'abscisses x et x+h. On a f(0)=−5, f(0,5)=−3,875, f(1)=−2, f(1,5)=1,375 et f(2)=7, d'où P = [2.25, 3.75, 6.75, 11.25] : premier élément 0,5−3,875+5=2,25, dernier 0,57−1,375=11,25. Le calcul général le confirme : hf(x+h)−f(x)=3x2+3xh+h2+2, qui donne 2,25 en x=0.
b)
range(8) produit huit abscisses, de 0 à 1,75, donc P contient 8 pentes, et la première vaut 0,25f(0,25)−f(0)=3×0+0+0,0625+2=2,0625. Le pas est une DONNÉE du programme : le diviser par deux double le nombre de sécantes pour couvrir le même intervalle. Quand h tend vers 0, chaque pente 3x2+3xh+h2+2 tend vers 3x2+2=f′(x) : la liste devient un tableau de valeurs approchées de la fonction dérivée.
c)
Toutes les pentes sont positives, ce qui SUGGÈRE que f croît ; la preuve vient de la dérivée : f′(x)=3x2+2>0, donc f est strictement croissante. Comme f(1)=−2<0 et f(2)=7>0, l'équation f(x)=0 a une unique solution α dans [1;2] : c'est le cas FAVORABLE, une seule racine et une dérivée qui ne s'annule jamais. La tangente en 1 a pour équation y=f′(1)(x−1)+f(1)=5(x−1)−2, soit y=5x−7, d'ordonnée à l'origine −7. Elle coupe l'axe des abscisses quand 5x−7=0, en x1=1,4.
d)
En un point xk, la tangente a pour équation y=f′(xk)(x−xk)+f(xk). Elle coupe l'axe des abscisses quand y=0, donc, f′(xk) étant non nul, en x=xk−f′(xk)f(xk) : c'est xk+1. On retrouve x1=1−5−2=1,4. Puis f(1,4)=2,744+2,8−5=0,544 et f′(1,4)=5,88+2=7,88, d'où x2=1,4−7,880,544≈1,4−0,0690≈1,3310.
e)
La ligne manquante est y = x - f(x)/d(x), traduction directe de d). Les écarts successifs valent environ 0,4, puis 0,069, puis 0,0027, puis 4×10−6, puis 9×10−12 : le cinquième tour est le premier dont l'écart passe sous 10−6, donc n=5, et le programme affiche x≈1,328269. Le nombre de décimales justes DOUBLE presque à chaque tour. Contrôle : f(1,328)<0<f(1,329). À titre de comparaison, un balayage de pas 10−6 parti de 1 ferait plus de 300000 tours pour la même précision.
La liste des sécantes montre la pente, la dérivée la démontre, et la tangente sert ensuite d'outil : Newton remplace la courbe par sa tangente et recommence.
Exercice 19 : Une valeur approchée de e par les intérêts composés
On place 1 dollar à un taux annuel de 100%. Si les intérêts sont versés en n fois dans l'année, au taux n100% à chaque versement et toujours sur le capital déjà acquis, le capital au bout d'un an vaut un=(1+n1)n. On admet que la suite (un) est croissante et converge vers le nombre e≈2,7182818.
from math import e
def u(n):
return (1 + 1/n)**n
L = [u(n) for n in [1, 2, 4, 12, 365]]
print(L)
n = 1
while e - u(n) >= 0.001:
n = n + 1
print(n)
a) Justifiez la formule donnant un en écrivant le capital après chaque versement. Calculez à la main u1, u2 et u4.
b) Donnez les deux dernières valeurs de la liste L, avec quatre décimales. Interprétez-les.
c) Que représente l'entier affiché par la boucle while ? Le programme affiche 1359 : justifiez-le par deux valeurs, puis dites combien vaut à peu près l'écart e−un pour n=10000.
d) Un élève affirme : « 1+n1 tend vers 1, donc un tend vers 1n=1 ». Que répondre ? Et pourquoi Python affiche-t-il 1.0 pour u(10**16) ?
Voir la correction
Réponses
a)Chaque versement multiplie par 1+n1 ; u1=2, u2=2,25, u4≈2,4414
b)u12≈2,6130 ; u365≈2,7146 : la suite croît vers e
c)Premier n tel que e−un<0,001 ; écart ≈0,00014 pour n=10000
d)Faux : la base tend vers 1 mais l'exposant vers l'infini ; 1+10−16 vaut 1 en machine
a)
Chaque versement ajoute au capital n1 de sa valeur : il le multiplie par 1+n1. Après n versements, le dollar de départ est devenu (1+n1)n : c'est une suite géométrique de raison 1+n1 arrêtée au rang n. À la main : u1=2 (un seul versement de 100%, le capital double), u2=1,52=2,25, u4=1,254=1,56252=2,44140625. Verser plus souvent rapporte davantage, parce que les intérêts produisent eux-mêmes des intérêts plus tôt.
b)
L = [2.0, 2.25, 2.44140625, 2.613..., 2.7145...] : u12≈2,6130 (versement mensuel) et u365≈2,7146 (versement quotidien). La suite croît, mais de moins en moins : passer de 12 à 365 versements ne rapporte qu'un dixième de dollar de plus. Même versé à chaque instant, le dollar ne dépasserait jamais e≈2,7183 dollars : c'est l'origine historique du nombre e, chez Jacques Bernoulli, en 1683.
c)
La boucle s'arrête au premier n tel que e−un<0,001 : c'est le plus petit nombre de versements pour lequel un approche e à moins d'un millième. La justification tient en deux valeurs : e−u1358≈0,0010001⩾0,001 et e−u1359≈0,0009994<0,001. La convergence est LENTE : l'écart se comporte comme 2ne, et 2×13592,718≈0,001 le confirme. Pour n=10000, l'écart vaut donc à peu près 200002,718≈0,00014 : dix fois plus de versements pour une seule décimale de plus.
d)
L'argument est faux, parce que la base tend vers 1 PENDANT que l'exposant tend vers l'infini : les deux effets se combattent, et aucune règle ne permet de passer à la limite dans la base seule. Les valeurs calculées le montrent, un croît au-delà de 2,7, loin de 1. Quant à Python, le calcul de u(10**16) commence par 1+10−16, et ce nombre n'est pas représentable : un flottant ne garde qu'une quinzaine de chiffres significatifs, donc 1+10−16 est arrondi à 1 exactement, et 1 élevé à n'importe quelle puissance reste 1. L'erreur est dans la MACHINE, pas dans les mathématiques, comme pour le taux d'accroissement de l'exercice 4 avec un pas trop petit.
La liste L montre la convergence, le while la chiffre, et le calcul à la main de u1, u2, u4 vérifie les premiers éléments : ce sont les trois gestes de tout algorithme d'approximation.
Exercice 20 : Monte-Carlo : l'aire sous la parabole et le nombre π
On note D le domaine situé sous la parabole y=x2, dans le carré [0;1]×[0;1]. La fonction random() renvoie un nombre au hasard dans [0;1[, uniformément. On tire n points M(x;y) au hasard dans le carré et l'on compte ceux qui tombent dans D.
from random import random
def aire(n):
c = 0
for k in range(n):
x = random()
y = random()
if ...:
c = c + 1
return c/n
a) Choisissez la condition qui complète le programme. Le point M(0,8;0,3) de la figure est-il compté ?
b) Pourquoi la proportion de points comptés estime-t-elle l'aire de D ? Un essai avec n=10000 compte 3310 points : quelle estimation obtient-on ?
c) On calcule bas = sum([(k/10)**2 for k in range(10)])/10 et haut = sum([(k/10)**2 for k in range(1, 11)])/10. Donnez ces deux valeurs et interprétez-les.
d) Pour estimer π, on tire x = 2*random() - 1 et y = 2*random() - 1, et l'on compte les points tels que x**2 + y**2 <= 1. Sur 20000 points, 15702 sont comptés. Quelle estimation de π en déduit-on, et pourquoi multiplie-t-on par 4 ?
e) Pour diviser par 2 l'erreur typique d'une telle estimation, par combien faut-il multiplier le nombre de points ?
Voir la correction
Réponses
a)y <= x**2 ; M est compté car 0,3⩽0,64
b)Proportion = rapport des aires, le carré ayant pour aire 1 ; estimation 0,331
c)bas =0,285, haut =0,385 : encadrement de l'aire par des rectangles
d)4×2000015702=3,1404 ; le carré [−1;1]2 a pour aire 4
e)Par 4
a)
Le point M(x;y) est sous la parabole quand son ordonnée ne dépasse pas celle du point de la courbe de même abscisse : la condition est y <= x**2. Pour M(0,8;0,3) : 0,82=0,64 et 0,3⩽0,64, donc M est compté. Le point N(0,3;0,6), lui, ne l'est pas : 0,32=0,09<0,6. Les conditions y >= x**2 et x <= y**2 décrivent d'autres régions du carré, la première le complémentaire de D.
b)
Les points sont répartis uniformément dans le carré : la probabilité qu'un point tombe dans D est le rapport des aires, 1aire(D), puisque le carré a pour aire 1. La fréquence observée sur un grand nombre de tirages approche cette probabilité. Avec 3310 points sur 10000, l'estimation vaut 0,331. Une autre exécution donnerait un nombre voisin mais différent : l'estimation fluctue, ce n'est pas une erreur de programme.
c)
bas =101(02+0,12+⋯+0,92)=102,85=0,285 et haut =101(0,12+⋯+12)=103,85=0,385. On découpe [0;1] en dix bandes de largeur 0,1 ; la fonction carré étant croissante sur [0;1], le rectangle de hauteur f au bord GAUCHE est sous la courbe et celui de hauteur f au bord DROIT la dépasse. D'où 0,285⩽aire(D)⩽0,385. L'estimation 0,331 tombe dans l'encadrement, ce qui la rend crédible ; la valeur exacte, 31, se démontre en Terminale avec le calcul intégral. Les deux listes en compréhension font en une ligne ce que la méthode d'Archimède faisait à la main.
d)
Les points sont maintenant tirés dans le carré [−1;1]×[−1;1], d'aire 4, et la condition décrit le disque de centre O et de rayon 1, d'aire π×12=π. La proportion de points comptés approche donc 4π, et l'estimation de π vaut quatre fois cette proportion : 4×2000015702=4×0,7851=3,1404. Oublier le facteur 4, c'est confondre la proportion avec l'aire : la proportion est un rapport d'aires, et l'aire du carré n'est plus 1.
e)
L'erreur typique d'une fréquence se comporte comme n1, comme la demi-largeur n2σ de l'exercice 15 : pour la diviser par 2, il faut multiplier n par 2, donc n par 4. Monte-Carlo est simple à programmer mais lent : une décimale de plus coûte cent fois plus de points.
Une aire devient une probabilité, une probabilité se lit comme une fréquence, et la fréquence se vérifie par un encadrement déterministe : le hasard donne l'estimation, la liste des rectangles dit si elle est plausible.
Exercice 21 : Fréquence d'apparition des lettres d'un texte
On veut compter les lettres d'un texte écrit en minuscules, sans accents, à l'aide d'une liste de 26 compteurs, un par lettre de l'alphabet. Dans de longs textes, la lettre e représente environ 15% des lettres en français et 13% en anglais, la lettre h environ 1% en français et 6% en anglais.
alphabet = "abcdefghijklmnopqrstuvwxyz"
texte = "les mathematiques se lisent aussi dans les lettres"
compte = [0 for k in range(26)]
for c in texte:
if c in alphabet:
i = alphabet.index(c)
compte[i] = compte[i] + 1
n = sum(compte)
freq = [round(100*x/n, 1) for x in compte]
a) Que contient la liste compte au départ ? Quelle lettre l'élément compte[4] compte-t-il, et que vaut-il à la fin ?
b) Que vaut n ? Et len(texte) ? Pourquoi ces deux nombres diffèrent-ils, et lequel faut-il utiliser pour une fréquence ?
c) Que vaut freq[4] ? Quelle lettre l'instruction alphabet[compte.index(max(compte))] renvoie-t-elle ?
d) On lance le même programme sur le texte anglais « the theory of numbers is the queen of mathematics ». Il compte 41 lettres, dont 4 h. Donnez la fréquence de h dans chacun des deux textes, en pourcentage au dixième.
e) Laquelle des lettres e et h distingue le mieux un texte français d'un texte anglais ? Et que penser d'une conclusion tirée d'un texte de quarante lettres ?
Voir la correction
Réponses
a)26 zéros ; compte[4] compte e et vaut 8
b)n =43 lettres, len(texte) =50 caractères dont 7 espaces ; on divise par n
c)freq[4] ≈18,6 ; la lettre renvoyée est s (9 occurrences)
d)h : 414≈9,8% en anglais, 431≈2,3% en français
e)h distingue les langues ; sur quarante lettres la conclusion reste fragile
a)
Au départ, compte est la liste de 26 zéros construite en compréhension, un compteur par lettre. La boucle ITÈRE sur les caractères du texte ; pour chaque lettre, alphabet.index(c) donne sa position dans l'alphabet, À PARTIR DE 0 : a est à l'indice 0, b à l'indice 1, et l'indice 4 est celui de e, la cinquième lettre. Le texte contient les e de « les » (deux fois), « mathematiques » (deux), « se », « lisent » et « lettres » (deux) : compte[4] vaut 8 à la fin. Croire que compte[4] compte d, la quatrième lettre, c'est l'erreur d'indice de l'exercice 16.
b)
n est la somme des compteurs, c'est-à-dire le nombre de LETTRES : 43. len(texte) compte tous les caractères, espaces compris : 50. La différence, 7, est le nombre d'espaces entre les huit mots ; le test if c in alphabet les écarte. Une fréquence de lettre se calcule sur les lettres : diviser par 50 donnerait pour e 508=16% au lieu de 18,6%.
c)
freq[4] =43100×8≈18,6. L'instruction cherche le maximum de la liste compte, puis l'INDICE de ce maximum, puis la lettre de même indice dans alphabet. Or le texte contient 9 s pour 8 e : elle renvoie s, pas e. Sur ce court texte, la lettre la plus fréquente du français n'est même pas en tête, les pluriels ayant multiplié les s.
d)
Dans le texte anglais, h apparaît dans « the » (deux fois), « theory » et « mathematics » : 414≈9,8%. Dans le texte français, un seul h, celui de « mathematiques » : 431≈2,3%. Les deux fréquences de e, elles, sont voisines : 438≈18,6% en français et 417≈17,1% en anglais.
e)
C'est h qui distingue les deux langues : de l'ordre de 1% contre 6% sur de longs textes, un rapport de un à six, alors que e passe seulement de 15% à 13%. On compare donc la lettre dont les fréquences de référence s'écartent le plus, pas la plus fréquente. Mais sur une quarantaine de lettres la fréquence fluctue beaucoup, comme le montre le s de la question c) : la conclusion n'est fiable que sur un texte long. C'est le lien avec les variables aléatoires : la fréquence observée approche la probabilité quand le nombre de lettres grandit.
La liste de 26 compteurs est la version programmée d'un tableau d'effectifs : l'indice désigne la lettre, la valeur son effectif, et une fréquence se calcule sur l'effectif total, jamais sur la longueur du texte brut.
Il manque quelque chose dans cette série ?Un type d'exercice que ton prof donne, un énoncé qui te bloque, une erreur repérée : dis-le-moi, je lis chaque demande.
L'envoi passe par ton espace gratuit : c'est ce qui me permet de te répondre et de te prévenir quand l'exercice est ajouté. Un courriel suffit, pas de mot de passe. Crée ton espace.
Pas envie de créer un compte ? Écris-moi directement.
Vous cherchez un tuteur de spécialité maths en Première à 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.