Exercices corrigés — Algorithmique Et Programmation (2nde)
✏️ Exercices - Algorithmique & programmation (Python)
2nde
Thèmes : variables • affectations • conditions • boucles for/while • fonctions •
calcul numérique • géométrie algorithmique • simulation et probabilités.
Objectif : interpréter, compléter, corriger et écrire des algorithmes Python solides, puis relier le calcul
numérique aux notions mathématiques de 2nde.
Exercice 1 - Variables, types, conversions - pièges de input()
Ex. 1/30On exécute ce script :
age = input("Âge ? ")
x = input("Nombre réel ? ")
print(age + 1)
print(x * 2)
- Expliquer précisément l’erreur provoquée par
print(age + 1). - Si l’utilisateur saisit
3.5pourx, indiquer exactement ce qu’afficheprint(x * 2). - Corriger le script pour afficher l’âge augmenté de 1 et le double de \(x\) comme des nombres.
- Donner une entrée pour laquelle
int(...)échoue et expliquer pourquoi.
input()renvoie toujours une chaîne de caractères (str).- Une chaîne multipliée par un entier est répétée :
"ab" * 2donne"abab". - Convertir l’âge avec
int(...)et le réel avecfloat(...). - Une chaîne comme
"17.5"n’est pas l’écriture d’un entier.
(a)
age est une chaîne. Python ne peut pas additionner directement une chaîne et l’entier 1 : l’instruction déclenche donc une TypeError.
(b)
Après la saisie, x vaut la chaîne "3.5". Ainsi x * 2 répète la chaîne deux fois et affiche 3.53.5, et non 7.0.
(c)
age = int(input("Âge ? "))
x = float(input("Nombre réel ? "))
print(age + 1)
print(2 * x)
Les conversions sont effectuées avant les calculs ; age est alors un entier et x un flottant.
(d)
Par exemple int("17.5") échoue : le point décimal empêche Python d’interpréter la chaîne comme un entier. Pour une donnée réelle, on utilise float(...).
Exercice 2 - Affectation, priorités, // et % - lecture de trace
Ex. 2/30On pose a = 17 et b = 5.
- Calculer
a + b * 2puis(a + b) * 2. - Calculer
a / b,a // beta % b, puis relier les deux derniers résultats à la division euclidienne. - Faire la trace de
a = a + b; b = a - b; a = a - bet donner les valeurs finales. - Expliquer ce que réalise
a, b = b, aet pourquoi cette écriture est préférable en Python.
- La multiplication est prioritaire sur l’addition.
- Écrire \(17 = 5q+r\) avec \(0\le r<5\).
- Après chaque affectation, remplacer immédiatement l’ancienne valeur.
- L’affectation multiple évalue d’abord la partie droite.
(a)
a + b * 2 = 17 + 5*2 = 27, tandis que (a + b) * 2 = 22*2 = 44. Les parenthèses changent donc l’ordre des opérations.
(b)
a / b = 3.4, a // b = 3 et a % b = 2. Cela correspond à \(17=5\times3+2\) : quotient \(3\), reste \(2\).
(c)
Départ : a=17, b=5. Après a=a+b, on a a=22, b=5. Puis b=a-b donne b=17. Enfin a=a-b donne a=5. Les valeurs ont été échangées.
(d)
a, b = b, a échange directement les deux valeurs. C’est plus lisible et évite les erreurs d’ordre possibles avec plusieurs affectations successives.
Exercice 3 - Tests - intervalles et logique booléenne
Ex. 3/30Écrire des conditions Python correspondant exactement aux ensembles indiqués.
- Tester si \(x\in[-2\,;\,5[\).
- Tester si \(x\notin[0\,;\,1]\).
- Tester si \(x\in]-\infty\,;\,-3]\cup[2\,;\,+\infty[\).
- Tester si \(x\in[1\,;\,4]\) et \(x\ne3\).
- Une borne fermée donne
<=ou>=; une borne ouverte donne<ou>. - Être hors de
[0;1]signifie être strictement à gauche de 0 ou strictement à droite de 1. - Une union se traduit naturellement par
or. - Les trois conditions doivent être vraies simultanément.
(a)
La condition est (-2 <= x) and (x < 5). Python accepte aussi l’écriture chaînée -2 <= x < 5.
(b)
La condition est (x < 0) or (x > 1). Les bornes 0 et 1 sont exclues du complément car elles appartiennent à [0;1].
(c)
La condition est (x <= -3) or (x >= 2). Les points \(-3\) et \(2\) sont inclus.
(d)
On écrit (1 <= x) and (x <= 4) and (x != 3), ou plus simplement 1 <= x <= 4 and x != 3.
Exercice 4 - Logique - lois de De Morgan
Ex. 4/30On considère la condition :
not((x >= 0 and x <= 1) or (x == 3))
- Réécrire la condition sans
not, uniquement avecand,or, comparaisons et!=. - Décrire l’ensemble des réels qui valident cette condition.
- Tester mentalement la condition pour \(x=0{,}5\), \(x=2\), \(x=3\) et \(x=-1\).
- Écrire une version lisible utilisant deux variables booléennes intermédiaires.
- Utiliser
not(A or B) == (not A) and (not B). - Il faut être hors de
[0;1]et différent de 3. - Évaluer d’abord l’appartenance à
[0;1], puis le casx==3. - Nommer les propositions avant de les combiner.
(a)
Avec \(A=(0\le x\le1)\) et \(B=(x=3)\), De Morgan donne not(A or B) = (not A) and (not B). Une écriture sans not est donc ((x < 0) or (x > 1)) and (x != 3).
(b)
On prend tous les réels hors de \([0;1]\), puis on retire \(3\) : \(]-\infty;0[\cup]1;3[\cup]3;+\infty[\).
(c)
\(x=0{,}5\) : faux ; \(x=2\) : vrai ; \(x=3\) : faux ; \(x=-1\) : vrai.
(d)
dans_01 = (0 <= x <= 1)
est_3 = (x == 3)
ok = (not dans_01) and (not est_3)
Cette version sépare clairement les deux événements à exclure.
Exercice 5 - Boucle while - seuil et arrêt garanti
Ex. 5/30On définit \(u_0=1\) et \(u_{n+1}=1{,}15u_n+2\).
- Écrire un programme qui calcule le plus petit entier \(n\) tel que \(u_n\ge100\).
- Calculer \(u_0,u_1,u_2,u_3\).
- Justifier rigoureusement, à un niveau de 2nde, que la boucle finit.
- Donner le couple \((n,u_n)\) obtenu à l’arrêt, avec \(u_n\) arrondi au millième.
- Initialiser
u=1,n=0, puis répéter tant queu < 100. - Appliquer exactement la relation de récurrence.
- Étudier \(u_{n+1}-u_n=0{,}15u_n+2\) et utiliser le fait que \(u_n>0\).
- Une trace informatique ou des calculs successifs donnent le premier franchissement entre \(n=14\) et \(n=15\).
(a)
u = 1.0
n = 0
while u < 100:
u = 1.15*u + 2
n += 1
print(n, u)
Le test est effectué avant chaque nouvelle itération ; le compteur correspond donc bien à l’indice du terme calculé.
(b)
\(u_0=1\), \(u_1=3{,}15\), \(u_2=5{,}6225\) et \(u_3=8{,}465875\).
(c)
Comme \(u_0>0\) et que la relation conserve la positivité, on a toujours \(u_n>0\). Alors \(u_{n+1}-u_n=0{,}15u_n+2>2\). Par récurrence, \(u_n>1+2n\) ; cette quantité dépasse 100 pour \(n\) assez grand. La boucle atteint donc nécessairement son seuil et s’arrête.
(d)
On trouve \(u_{14}\approx88{,}085\) puis \(u_{15}\approx103{,}298\). Le plus petit indice recherché est donc \(n=15\), et le programme affiche approximativement (15, 103.298).
Exercice 6 - Boucle for - somme de carrés et vérification
Ex. 6/30On veut calculer \(S=1^2+2^2+\cdots+n^2\).
- Écrire un programme utilisant
forqui calcule \(S\) pour un entier naturel \(n\). - Calculer \(S\) à la main pour \(n=5\).
- Vérifier pour \(n=5\) la formule \(S=\dfrac{n(n+1)(2n+1)}{6}\).
- Écrire un programme qui vérifie automatiquement cette formule pour tous les entiers de 1 à 50.
- Initialiser
S=0, puis ajouterk*k. - Additionner \(1,4,9,16,25\).
- Remplacer \(n\) par 5 avant de simplifier.
- Comparer deux entiers ; le membre de droite peut être calculé avec
// 6.
(a)
def somme_carres(n):
S = 0
for k in range(1, n + 1):
S += k*k
return S(b)
\(S=1+4+9+16+25=55\).
(c)
\(\dfrac{5\times6\times11}{6}=5\times11=55\). Les deux calculs coïncident.
(d)
ok = True
for n in range(1, 51):
S = somme_carres(n)
F = n*(n+1)*(2*n+1)//6
if S != F:
ok = False
print("Erreur pour", n)
break
print("Formule OK" if ok else "Formule KO")
Tous les calculs sont entiers : on évite ainsi une comparaison fragile de flottants.
Exercice 7 - Division euclidienne - convertir une durée
Ex. 7/30On dispose d’une durée entière t = 9876 secondes. On veut l’écrire sous la forme heures, minutes, secondes.
- Calculer le nombre entier d’heures complètes.
- Calculer le nombre de minutes complètes restant après retrait des heures.
- Calculer le nombre de secondes restantes et donner la décomposition de 9876 s.
- Écrire une fonction
decompose(t)qui renvoie les trois valeurs, en refusant une durée négative.
- Une heure contient 3600 secondes : utiliser
//. - Après les heures, utiliser le reste
t % 3600. - Sur ce reste, les minutes utilisent
// 60et les secondes% 60. - Une fonction peut renvoyer plusieurs valeurs séparées par des virgules.
(a)
9876 // 3600 = 2 : il y a 2 heures complètes.
(b)
Le reste après 2 h vaut 9876 % 3600 = 2676. Puis 2676 // 60 = 44 : il reste 44 minutes complètes.
(c)
2676 % 60 = 36. Ainsi 9876 s = 2 h 44 min 36 s. Vérification : \(2\times3600+44\times60+36=9876\).
(d)
def decompose(t):
if t < 0:
return None
h = t // 3600
reste = t % 3600
m = reste // 60
s = reste % 60
return h, m, s
La garde t < 0 évite de donner un sens physique indésirable à une durée négative.
Exercice 8 - Fonction par morceaux - tarif progressif
Ex. 8/30Un service facture une consommation \(x\ge0\) selon le tarif suivant : \(2\) € par unité jusqu’à 10 unités ; puis \(1{,}5\) € par unité supplémentaire jusqu’à 25 ; puis \(1{,}2\) € par unité supplémentaire au-delà.
- Écrire une fonction Python
prix(x)qui renvoieNonesi \(x<0\). - Calculer
prix(8)etprix(18). - Calculer
prix(30)en justifiant la continuité des paliers. - Expliquer pourquoi, dans un bloc
if/elif/else, il suffit de testerx <= 10, puisx <= 25.
- Le deuxième palier paie d’abord les 10 premières unités, puis seulement
x-10. - Pour 18, le premier palier coûte 20 €.
- Pour 30, les 25 premières unités coûtent \(20+15\times1{,}5\).
- Si le premier test est faux, on sait déjà que
x > 10.
(a)
def prix(x):
if x < 0:
return None
if x <= 10:
return 2*x
elif x <= 25:
return 20 + 1.5*(x - 10)
else:
return 42.5 + 1.2*(x - 25)(b)
prix(8) = 16. Pour 18 unités : \(20+1{,}5\times8=32\), donc prix(18) = 32.
(c)
Jusqu’à 25 unités, le coût vaut \(20+1{,}5\times15=42{,}5\) €. Pour 30 unités, on ajoute \(1{,}2\times5=6\) €, soit \(48{,}5\) €. Les formules reprennent à chaque palier le coût déjà accumulé.
(d)
Dans la branche elif, le cas x <= 10 a déjà été éliminé. Tester seulement x <= 25 décrit donc exactement \(10
Exercice 9 - Fonction à plusieurs arguments - distance dans le plan
Ex. 9/30On rappelle que la distance entre \(A(x_A,y_A)\) et \(B(x_B,y_B)\) vaut \(AB=\sqrt{(x_B-x_A)^2+(y_B-y_A)^2}\).
- Écrire une fonction
distance(xA, yA, xB, yB)utilisantmath.sqrt. - Calculer exactement la distance entre \(A(-2;3)\) et \(B(4;-5)\).
- Vérifier que la fonction renvoie 10 pour ces coordonnées.
- Expliquer pourquoi la distance ne change pas si l’on échange A et B.
- Importer
sqrtdepuismath, ou utilisermath.sqrt. - Les écarts valent \(6\) et \(-8\).
- Le radicand vaut \(36+64\).
- Échanger les points change les deux écarts en leurs opposés, mais pas leurs carrés.
(a)
from math import sqrt
def distance(xA, yA, xB, yB):
return sqrt((xB-xA)**2 + (yB-yA)**2)(b)
\(AB=\sqrt{(4-(-2))^2+(-5-3)^2}=\sqrt{6^2+(-8)^2}=\sqrt{100}=10\).
(c)
L’appel distance(-2, 3, 4, -5) calcule sqrt(100) et renvoie donc 10.0, qui représente la même valeur mathématique 10.
(d)
En échangeant A et B, \(x_B-x_A\) et \(y_B-y_A\) sont remplacés par leurs opposés. Leurs carrés sont inchangés, donc la somme puis sa racine carrée sont identiques.
Exercice 10 - Algorithme d’Euclide - PGCD et invariant
Ex. 10/30On veut calculer le PGCD de deux entiers positifs avec l’algorithme d’Euclide.
def pgcd(a, b):
while b != 0:
r = a % b
a = b
b = r
return a
- Faire la trace pour
a=9999etb=3663. - Donner le PGCD obtenu.
- Expliquer pourquoi remplacer \((a,b)\) par \((b,a\%b)\) conserve les diviseurs communs.
- Adapter la fonction pour accepter des entrées négatives.
- Effectuer des divisions euclidiennes successives.
- Le dernier reste non nul est le PGCD.
- Si \(a=bq+r\), tout diviseur commun de \(a\) et \(b\) divise aussi \(r\) ; raisonner aussi dans l’autre sens.
- Commencer par prendre les valeurs absolues.
(a)
\(9999=3663\times2+2673\), \(3663=2673+990\), \(2673=990\times2+693\), \(990=693+297\), \(693=297\times2+99\), \(297=99\times3+0\).
(b)
Le dernier reste non nul est 99, donc \(\mathrm{PGCD}(9999,3663)=99\).
(c)
Si \(d\) divise \(a\) et \(b\), alors il divise \(a-bq=r\). Réciproquement, si \(d\) divise \(b\) et \(r\), il divise \(bq+r=a\). Les ensembles de diviseurs communs sont donc identiques.
(d)
def pgcd(a, b):
a = abs(a)
b = abs(b)
while b != 0:
a, b = b, a % b
return aExercice 11 - Simulation - pièce équilibrée puis biaisée
Ex. 11/30On simule des lancers indépendants d’une pièce et on estime la fréquence de Pile.
- Écrire une fonction
freq_pile(N)pour une pièce équilibrée. - Expliquer pourquoi le résultat n’est généralement pas exactement \(0{,}5\).
- Modifier la fonction pour une pièce donnant Pile avec probabilité \(p=0{,}62\).
- Ajouter une protection pour
N <= 0et expliquer l’effet d’un grand N.
- Pour une pièce équilibrée,
random.randint(0, 1)convient. - Une fréquence expérimentale fluctue autour de la probabilité théorique.
random.random()produit un réel de \([0;1[\) ; déclarer Pile quand ce réel est inférieur à \(p\).- Une fréquence ne doit pas diviser par zéro.
(a)
import random
def freq_pile(N):
if N <= 0:
return None
c = 0
for k in range(N):
if random.randint(0, 1) == 0:
c += 1
return c / N(b)
Sur un nombre fini d’essais, le hasard produit des fluctuations. La fréquence est une estimation de \(0{,}5\) ; elle n’a aucune raison d’être exactement égale à \(0{,}5\) à chaque exécution.
(c)
import random
def freq_pile_biaisee(N, p=0.62):
if N <= 0 or p < 0 or p > 1:
return None
c = 0
for k in range(N):
if random.random() < p:
c += 1
return c / N
Le test u < p sélectionne une portion de longueur \(p\) de l’intervalle \([0;1[\).
(d)
La garde évite une division par zéro et refuse un nombre d’essais non positif. Quand N augmente, les fluctuations relatives diminuent en général : la fréquence observée devient plus stable autour de la probabilité théorique.
Exercice 12 - Simulation - au moins un 6 en quatre lancers
Ex. 12/30On lance un dé équilibré quatre fois et on s’intéresse à l’événement « obtenir au moins un 6 ».
- Écrire une simulation de N expériences qui estime cette probabilité.
- Calculer la probabilité théorique exacte avec l’événement contraire.
- Donner une valeur décimale approchée au dix-millième.
- Expliquer ce que l’on doit observer pour un grand nombre d’expériences, par exemple
N=50000.
- Une expérience contient quatre lancers ; utiliser un booléen
ok. - Le contraire est « aucun 6 » : sa probabilité vaut \((\dfrac56)^4\).
- Calculer \(1-\dfrac{625}{1296}\).
- La fréquence simulée doit être proche de la valeur théorique, sans lui être nécessairement égale.
(a)
import random
def proba_au_moins_un_6(N):
if N <= 0:
return None
succes = 0
for experience in range(N):
ok = False
for lancer in range(4):
if random.randint(1, 6) == 6:
ok = True
if ok:
succes += 1
return succes / N(b)
\(P(\text{aucun 6})=(\dfrac56)^4=\dfrac{625}{1296}\). Donc \(P(\text{au moins un 6})=1-\dfrac{625}{1296}=\dfrac{671}{1296}\).
(c)
\(\dfrac{671}{1296}\approx0{,}5177\).
(d)
Pour N=50000, la fréquence obtenue devrait être assez proche de \(0{,}5177\). Deux exécutions peuvent donner des valeurs légèrement différentes : c’est normal car la simulation est aléatoire.
Exercice 13 - Boucles imbriquées - compter exactement les passages
Ex. 13/30On considère le programme :
c = 0
for i in range(n):
for j in range(i, n):
c += 1
- Pour \(n=4\), lister les couples \((i,j)\) parcourus.
- Exprimer le nombre final
cen fonction de \(n\). - Calculer
cpour \(n=10\). - Comparer approximativement le nombre de passages quand on remplace \(n\) par \(2n\).
- Pour un i fixé, j prend \(n-i\) valeurs.
- Additionner \(n+(n-1)+\cdots+1\).
- Utiliser la formule de la somme des n premiers entiers.
- Comparer \(\dfrac{2n(2n+1)}2\) à \(\dfrac{n(n+1)}2\) pour n grand.
(a)
Pour \(n=4\) : \((0,0),(0,1),(0,2),(0,3)\) ; \((1,1),(1,2),(1,3)\) ; \((2,2),(2,3)\) ; \((3,3)\). Il y a 10 couples.
(b)
Pour chaque i, le nombre de valeurs de j est \(n-i\). Ainsi \(c=n+(n-1)+\cdots+1=\dfrac{n(n+1)}2\).
(c)
Pour \(n=10\), \(c=\dfrac{10\times11}{2}=55\).
(d)
Avec \(2n\), on obtient \(c_{2n}=n(2n+1)\). Le quotient \(\dfrac{c_{2n}}{c_n}=\dfrac{2(2n+1)}{n+1}\) se rapproche de 4 lorsque n grandit. Doubler n multiplie donc approximativement le nombre de passages par 4.
Exercice 14 - Calcul itératif - terme d’une suite et somme partielle
Ex. 14/30On définit \(u_0=2\) et \(u_{n+1}=2u_n+1\).
- Écrire une fonction
terme(n)qui calcule \(u_n\). - Calculer \(u_1,u_2,u_3\).
- Écrire une fonction qui calcule \(S_n=u_0+u_1+\cdots+u_n\), puis donner \(S_3\).
- Conjecturer une expression de \(u_n\) et la vérifier en la remplaçant dans la relation de récurrence.
- Partir de
u=2et appliquer la relation n fois. - Les valeurs commencent par 2, 5, 11, 23.
- Initialiser la somme avec \(u_0\) avant la boucle.
- Observer qu’ajouter 1 donne 3, 6, 12, 24.
(a)
def terme(n):
if n < 0:
return None
u = 2
for k in range(n):
u = 2*u + 1
return u(b)
\(u_1=5\), \(u_2=11\), \(u_3=23\).
(c)
def somme_termes(n):
if n < 0:
return None
u = 2
S = u
for k in range(n):
u = 2*u + 1
S += u
return S
\(S_3=2+5+11+23=41\).
(d)
On conjecture \(u_n=3\times2^n-1\). Pour \(n=0\), cela donne 2. Si \(u_n=3\times2^n-1\), alors \(2u_n+1=6\times2^n-1=3\times2^{n+1}-1\), ce qui reproduit bien la même forme au rang suivant.
Exercice 15 - Boucle while - premier entier dépassant un seuil
Ex. 15/30On cherche le plus petit entier \(n\) tel que \(1+2+\cdots+n\ge1000\).
- Écrire un programme
whilequi calcule ce plus petit n. - Expliquer pourquoi la boucle s’arrête.
- Utiliser \(1+2+\cdots+n=\dfrac{n(n+1)}2\) pour prévoir la valeur de n.
- Vérifier la minimalité en comparant les sommes aux rangs \(n-1\) et \(n\).
- Conserver deux variables :
netS. - À chaque tour, S augmente d’un entier positif de plus en plus grand.
- Comparer \(44\times45/2\) et \(45\times46/2\) à 1000.
- La minimalité exige une somme précédente strictement inférieure à 1000.
(a)
S = 0
n = 0
while S < 1000:
n += 1
S += n
print(n, S)(b)
À chaque tour, n augmente de 1 et on ajoute ce nouvel entier positif à S. La somme devient arbitrairement grande ; elle finit donc par atteindre puis dépasser 1000.
(c)
\(S_{44}=\dfrac{44\times45}{2}=990\) et \(S_{45}=\dfrac{45\times46}{2}=1035\). On prévoit donc \(n=45\).
(d)
On a bien \(S_{44}=990<1000\) tandis que \(S_{45}=1035\ge1000\). Ainsi 45 est le premier entier qui convient, donc la condition de minimalité est vérifiée.
Exercice 16 - Débogage - erreur de borne dans range
Ex. 16/30Le but de la fonction suivante est de calculer \(1+2+\cdots+n\), mais elle est fausse :
def somme(n):
S = 0
for k in range(n):
S = S + k
return S
- Tester mentalement la fonction pour \(n=1,2,3\).
- Identifier précisément l’erreur.
- Donner deux corrections différentes de la boucle.
- Ajouter une validation qui renvoie 0 si \(n<1\).
range(n)parcourt \(0,1,\ldots,n-1\).- Le programme ajoute 0 et oublie n.
- On peut modifier soit les bornes du
range, soit le terme ajouté. - Tester n avant d’initialiser la boucle.
(a)
Pour \(n=1\), la fonction renvoie 0 ; pour \(n=2\), elle renvoie 1 ; pour \(n=3\), elle renvoie 3. Les bonnes valeurs seraient respectivement 1, 3 et 6.
(b)
La boucle parcourt 0 jusqu’à \(n-1\). Le 0 ne change pas la somme, mais surtout le terme n n’est jamais ajouté : c’est une erreur de borne dite « off-by-one ».
(c)
# Correction 1
for k in range(1, n + 1):
S += k
# Correction 2
for k in range(n):
S += k + 1(d)
def somme(n):
if n < 1:
return 0
S = 0
for k in range(1, n + 1):
S += k
return SExercice 17 - Multiples et diviseurs - fonctions booléennes
Ex. 17/30On travaille avec des entiers. L’opérateur % permet de tester une divisibilité.
- Écrire
est_multiple(a, b)qui indique si a est un multiple de b, en refusantb=0. - Utiliser la fonction pour décider si 357 est un multiple de 7.
- Écrire une fonction qui renvoie le plus grand multiple positif de a inférieur ou égal à b, avec \(a>0\) et \(b\ge0\).
- Déterminer le plus grand multiple de 7 inférieur ou égal à 100 et expliquer le calcul.
- a est multiple de b exactement quand le reste de la division de a par b est nul.
- Calculer
357 % 7. - Le quotient entier
b // adonne le nombre de paquets complets de taille a. - Multiplier le quotient entier par 7.
(a)
def est_multiple(a, b):
if b == 0:
return None
return a % b == 0(b)
\(357=7\times51\), donc 357 % 7 vaut 0 : 357 est bien un multiple de 7.
(c)
def plus_grand_multiple(a, b):
if a <= 0 or b < 0:
return None
return (b // a) * a
Le quotient entier compte combien de multiples entiers de a tiennent jusqu’à b.
(d)
100 // 7 = 14, donc le plus grand multiple est \(14\times7=98\). Le multiple suivant, 105, dépasse 100.
Exercice 18 - Nombres premiers - test par divisions successives
Ex. 18/30Un entier \(n\ge2\) est premier s’il n’a pas de diviseur autre que 1 et lui-même.
- Écrire une fonction
est_premier(n)utilisant une bouclewhile. - Expliquer pourquoi il suffit de tester jusqu’à ce que \(d^2>n\).
- Tester mentalement 1, 2, 9, 17 et 221.
- Optimiser le programme en traitant 2 séparément puis en ne testant que les diviseurs impairs.
- Commencer avec
d=2et arrêter dès qu’un reste nul apparaît. - Si \(n=ab\) et \(a\le b\), alors \(a^2\le n\).
- \(221=13\times17\).
- Après avoir éliminé les nombres pairs, commencer à 3 et augmenter de 2.
(a)
def est_premier(n):
if n < 2:
return False
d = 2
while d*d <= n:
if n % d == 0:
return False
d += 1
return True(b)
Si n est composé, on peut écrire \(n=ab\) avec \(2\le a\le b\). Alors \(a^2\le ab=n\), donc \(a\le\sqrt n\). S’il existe un diviseur non trivial, il y en a donc un au plus égal à \(\sqrt n\).
(c)
1 : non premier ; 2 : premier ; 9 : non premier car \(9=3^2\) ; 17 : premier ; 221 : non premier car \(221=13\times17\).
(d)
def est_premier(n):
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
d = 3
while d*d <= n:
if n % d == 0:
return False
d += 2
return TrueExercice 19 - Statistiques - lire une fonction à cinq valeurs
Ex. 19/30On considère cinq valeurs réelles \(x_1,\ldots,x_5\). On veut calculer leur moyenne, leur variance de population et leur écart-type sans utiliser de liste.
from math import sqrt
def stats5(a, b, c, d, e):
m = (a+b+c+d+e)/5
V = ((a-m)**2 + (b-m)**2 + (c-m)**2
+ (d-m)**2 + (e-m)**2)/5
return m, V, sqrt(V)
- Expliquer ce que représentent les trois valeurs renvoyées.
- Calculer la moyenne pour \((2,4,4,4,6)\).
- Calculer exactement la variance pour ces cinq valeurs.
- Donner l’écart-type approché au millième et interpréter son rôle.
- La fonction calcule d’abord m, puis la moyenne des carrés des écarts à m.
- La somme vaut 20.
- Les écarts à 4 sont \(-2,0,0,0,2\).
- L’écart-type est la racine carrée de la variance.
(a)
La fonction renvoie successivement la moyenne \(m\), la variance \(V=\dfrac15\sum(x_i-m)^2\), puis l’écart-type \(\sigma=\sqrt V\).
(b)
\(m=\dfrac{2+4+4+4+6}{5}=\dfrac{20}{5}=4\).
(c)
Les carrés des écarts à 4 sont 4, 0, 0, 0 et 4. Leur somme vaut 8, donc \(V=\dfrac85=1{,}6\).
(d)
\(\sigma=\sqrt{\dfrac85}\approx1{,}265\). L’écart-type mesure la dispersion des valeurs autour de leur moyenne : plus il est grand, plus les valeurs sont étalées.
Exercice 20 - Flottants - comparaison à une précision donnée
Ex. 20/30On exécute :
S = 0.0
for k in range(10):
S += 0.1
print(S)
- Donner le résultat attendu en mathématiques exactes.
- Expliquer pourquoi Python peut afficher une valeur comme
0.9999999999999999. - Écrire un test robuste pour vérifier que S est égal à 1 à \(10^{-9}\) près.
- Proposer une méthode évitant l’accumulation d’erreurs pour ce calcul particulier.
- Dix dixièmes valent 1.
- Les flottants stockent des approximations binaires de nombreux décimaux.
- Comparer
abs(S - 1.0)à un petiteps. - Compter des dixièmes avec des entiers, puis diviser une seule fois à la fin.
(a)
En calcul exact, \(10\times0{,}1=1\).
(b)
Le nombre décimal 0,1 n’a pas d’écriture binaire finie. Python le stocke donc par une approximation ; dix additions peuvent accumuler une très petite erreur d’arrondi.
(c)
eps = 1e-9
if abs(S - 1.0) < eps:
print("S est égal à 1 à la précision demandée")(d)
T = 0
for k in range(10):
T += 1 # nombre de dixièmes
S = T / 10
Tous les calculs intermédiaires sont entiers ; la conversion en nombre décimal n’intervient qu’à la fin.
Exercice 21 - Balayage - encadrer $\sqrt{2}$ au millième
Ex. 21/30On veut encadrer \(\sqrt2\) au millième sans utiliser sqrt. On cherche un entier n tel que \((n/1000)^2\le2<((n+1)/1000)^2\).
- Écrire une boucle
whilequi détermine n avec uniquement des calculs entiers. - Donner la valeur de n obtenue.
- En déduire un encadrement de \(\sqrt2\) au millième.
- Expliquer pourquoi tester
n*n <= 2000000évite les flottants pendant la recherche.
- Multiplier toute l’inégalité par \(1000^2=1000000\).
- Chercher le dernier entier n dont le carré ne dépasse pas 2 000 000.
- L’encadrement final utilise n/1000 et (n+1)/1000.
- Comparer des entiers est exact en Python pour ces valeurs.
(a)
n = 0
while (n + 1)*(n + 1) <= 2_000_000:
n += 1
print(n)
La boucle avance tant que l’entier suivant satisfait encore \((n+1)^2\le2\times1000^2\).
(b)
On obtient n = 1414, car \(1414^2=1\,999\,396\le2\,000\,000\) tandis que \(1415^2=2\,002\,225>2\,000\,000\).
(c)
En divisant par \(1000^2\), on obtient \(1{,}414^2\le2<1{,}415^2\). Comme les nombres sont positifs : \(1{,}414\le\sqrt2<1{,}415\).
(d)
L’inégalité \((n/1000)^2\le2\) équivaut à \(n^2\le2\,000\,000\). On peut donc effectuer toute la recherche avec des entiers, sans introduire d’erreur d’arrondi avant l’affichage final.
Exercice 22 - Boucle while - méthode de Babylone pour $\sqrt a$
Ex. 22/30Pour \(a>0\), on définit \(x_0=a\) et \(x_{n+1}=\dfrac12\left(x_n+\dfrac{a}{x_n}\right)\).
- Écrire une fonction qui s’arrête quand deux approximations successives diffèrent de moins de \(10^{-6}\).
- Calculer \(x_1\) et \(x_2\) pour \(a=2\) à quatre décimales.
- Expliquer le rôle du seuil
eps. - Ajouter les validations nécessaires pour
a <= 0oueps <= 0.
- Calculer
xn, comparerabs(xn-x)au seuil, puis remplacer x par xn. - Partir de \(x_0=2\).
- Le seuil impose un critère de stabilité des approximations.
- Une division par x suppose aussi que l’on reste dans le cas \(a>0\).
(a)
def sqrt_babylone(a, eps=1e-6):
if a <= 0 or eps <= 0:
return None
x = float(a)
while True:
xn = 0.5*(x + a/x)
if abs(xn - x) < eps:
return xn
x = xn(b)
\(x_1=\dfrac12(2+\dfrac22)=1{,}5\). Puis \(x_2=\dfrac12(1{,}5+\dfrac{2}{1{,}5})\approx1{,}4167\).
(c)
Le paramètre eps fixe la précision de l’arrêt : plus il est petit, plus on exige que deux valeurs successives soient proches avant de considérer le calcul stabilisé.
(d)
La condition a <= 0 or eps <= 0 renvoie None. Elle évite un cas non prévu par cette version de l’algorithme et un seuil d’arrêt impossible ou incohérent.
Exercice 23 - Dichotomie - approximer $\sqrt2$
Ex. 23/30On sait que \(1<\sqrt2<2\). On coupe répétitivement l’intervalle en deux et on conserve la moitié contenant \(\sqrt2\).
- Écrire une fonction
racine2_dicho(eps)qui renvoie le milieu d’un intervalle de largeur inférieure à eps. - Donner les trois premiers intervalles obtenus à partir de
[1,2]. - Expliquer pourquoi le test
m*m < 2permet de choisir la bonne moitié. - Indiquer la valeur approchée obtenue pour
eps=1e-6.
- Initialiser
a=1.0,b=2.0et répéter tant queb-a >= eps. - Les premiers milieux sont 1,5 ; 1,25 ; 1,375.
- La fonction carré est croissante sur les nombres positifs.
- Le résultat doit être proche de 1,41421356.
(a)
def racine2_dicho(eps=1e-6):
if eps <= 0:
return None
a = 1.0
b = 2.0
while b - a >= eps:
m = (a + b)/2
if m*m < 2:
a = m
else:
b = m
return (a + b)/2(b)
Départ : \([1;2]\). Le milieu 1,5 a un carré supérieur à 2, donc on garde \([1;1{,}5]\). Puis \(1{,}25^2<2\), donc \([1{,}25;1{,}5]\). Puis \(1{,}375^2<2\), donc \([1{,}375;1{,}5]\).
(c)
Sur \([0;+\infty[\), la fonction \(x\mapsto x^2\) est croissante. Ainsi m*m < 2 signifie exactement \(m<\sqrt2\) : m devient alors la nouvelle borne gauche.
(d)
Pour eps=1e-6, la fonction renvoie une valeur proche de \(1{,}41421356\). L’erreur est contrôlée par la largeur finale de l’intervalle.
Exercice 24 - Premier rang - puissance dépassant 2
Ex. 24/30Un capital est multiplié chaque année par \(1{,}07\). On cherche le plus petit entier n tel que \(1{,}07^n>2\).
- Écrire une boucle
whilequi calcule ce plus petit n sans utiliser de logarithme. - Donner la valeur de n.
- Vérifier numériquement la minimalité avec les puissances aux rangs n-1 et n.
- Adapter le programme en une fonction
premier_rang(q, seuil)avec validations.
- Partir de
u=1,n=0, puis multiplier u par 1.07. - Le franchissement se produit entre les rangs 10 et 11.
- Comparer \(1{,}07^{10}\) et \(1{,}07^{11}\) à 2.
- Pour garantir une croissance vers le seuil, imposer
q > 1etseuil > 1.
(a)
u = 1.0
n = 0
while u <= 2:
u *= 1.07
n += 1
print(n, u)(b)
Le premier rang trouvé est \(n=11\).
(c)
\(1{,}07^{10}\approx1{,}9672<2\) tandis que \(1{,}07^{11}\approx2{,}1049>2\). Le rang 11 convient et le rang précédent ne convient pas : la minimalité est prouvée.
(d)
def premier_rang(q, seuil):
if q <= 1 or seuil <= 1:
return None
u = 1.0
n = 0
while u <= seuil:
u *= q
n += 1
return nExercice 25 - Simulation - somme de deux dés au moins égale à 10
Ex. 25/30On lance deux dés équilibrés et indépendants. On note S la somme des deux résultats.
- Écrire une simulation de N expériences estimant \(P(S\ge10)\).
- Déterminer exactement les couples donnant une somme au moins égale à 10.
- Calculer la probabilité théorique exacte.
- Expliquer comment utiliser la théorie pour contrôler la cohérence d’une simulation.
- À chaque expérience, tirer deux entiers de 1 à 6.
- Lister les couples ordonnés pour les sommes 10, 11 et 12.
- Il y a 36 couples équiprobables.
- Une grande simulation doit donner une fréquence proche de la probabilité calculée.
(a)
import random
def proba_somme_10(N):
if N <= 0:
return None
succes = 0
for k in range(N):
d1 = random.randint(1, 6)
d2 = random.randint(1, 6)
if d1 + d2 >= 10:
succes += 1
return succes / N(b)
Somme 10 : \((4,6),(5,5),(6,4)\) ; somme 11 : \((5,6),(6,5)\) ; somme 12 : \((6,6)\). Il y a donc 6 couples favorables.
(c)
Les 36 couples ordonnés sont équiprobables, donc \(P(S\ge10)=\dfrac{6}{36}=\dfrac16\).
(d)
On exécute par exemple la simulation avec un grand N. La fréquence doit se situer près de \(\dfrac16\approx0{,}1667\). Un écart modéré est normal ; un écart très important et persistant invite à rechercher une erreur dans le code.
Exercice 26 - Géométrie algorithmique - tester l’alignement de trois points
Ex. 26/30Pour \(A(x_A,y_A)\), \(B(x_B,y_B)\) et \(C(x_C,y_C)\), on peut tester l’alignement avec le déterminant \(D=(x_B-x_A)(y_C-y_A)-(y_B-y_A)(x_C-x_A)\).
- Écrire une fonction
alignes(xA,yA,xB,yB,xC,yC)qui renvoie un booléen. - Tester \(A(1;2)\), \(B(4;5)\) et \(C(7;8)\).
- Tester les mêmes A et B avec \(D(7;9)\).
- Expliquer pourquoi cette méthode est préférable au calcul et à la comparaison de deux pentes.
- Trois points sont alignés exactement quand le déterminant vaut 0.
- Les vecteurs \(\overrightarrow{AB}\) et \(\overrightarrow{AC}\) valent respectivement \((3;3)\) et \((6;6)\).
- Avec D, le second vecteur devient \((6;7)\).
- La pente pose un problème lorsque deux abscisses sont égales.
(a)
def alignes(xA, yA, xB, yB, xC, yC):
det = (xB-xA)*(yC-yA) - (yB-yA)*(xC-xA)
return det == 0(b)
Pour C, \(D=3\times6-3\times6=0\). Les trois points A, B et C sont donc alignés.
(c)
Pour \(D(7;9)\), le déterminant vaut \(3\times7-3\times6=21-18=3\ne0\). A, B et D ne sont pas alignés.
(d)
La formule du déterminant ne comporte aucune division. Elle fonctionne donc aussi pour une droite verticale, alors qu’une pente \((y_B-y_A)/(x_B-x_A)\) serait impossible si \(x_A=x_B\). Avec des coordonnées entières, le test peut en outre rester exact.
Exercice 27 - Équations de droites - coefficient directeur et intersection
Ex. 27/30On considère la droite \((d)\) passant par \(A(-2;1)\) et \(B(4;7)\), ainsi que la droite \((d')\) d’équation \(y=-2x+6\).
- Calculer le coefficient directeur de \((d)\) puis déterminer une équation de \((d)\).
- Écrire une fonction qui, pour deux points d’abscisses différentes, renvoie les coefficients m et p de \(y=mx+p\).
- Calculer exactement les coordonnées du point d’intersection I de \((d)\) et \((d')\).
- Vérifier par substitution que I appartient aux deux droites et identifier ce point sur la figure.
- \(m=\dfrac{y_B-y_A}{x_B-x_A}\).
- Après m, utiliser \(p=y_A-mx_A\).
- Résoudre \(x+3=-2x+6\).
- Remplacer les coordonnées trouvées dans les deux équations.
(a)
\(m=\dfrac{7-1}{4-(-2)}=\dfrac66=1\). Avec A : \(1=(-2)+p\), donc \(p=3\). Ainsi \((d)\) a pour équation \(y=x+3\).
(b)
def equation_droite(xA, yA, xB, yB):
if xA == xB:
return None
m = (yB-yA)/(xB-xA)
p = yA - m*xA
return m, p
Pour A et B, la fonction renvoie (1.0, 3.0). Le cas vertical est volontairement signalé par None car il n’a pas d’équation de la forme \(y=mx+p\).
(c)
À l’intersection, \(x+3=-2x+6\), donc \(3x=3\) et \(x=1\). Alors \(y=1+3=4\). Ainsi \(I(1;4)\).
(d)
Dans \((d)\) : \(4=1+3\). Dans \((d')\) : \(4=-2\times1+6\). Les deux égalités sont vraies ; I appartient aux deux droites. Sur la figure, I est placé exactement au croisement des deux tracés.
Exercice 28 - Balayage numérique - rechercher un maximum
Ex. 28/30On étudie \(f(x)=-x^2+6x+1\) sur \([0;6]\). On veut approcher le maximum par balayage avec un pas h.
- Écrire une fonction
maximum_balayage(h)qui teste les points \(0,h,2h,\ldots,6\). - Avec \(h=0{,}5\), déterminer le point où le maximum est trouvé.
- Vérifier algébriquement la valeur exacte du maximum en écrivant \(f(x)=10-(x-3)^2\).
- Expliquer l’effet d’un pas plus petit sur la précision et le nombre de calculs.
- Garder
xmaxetymaxet les mettre à jour quand une valeur plus grande apparaît. - Le sommet est exactement sur la grille de pas 0,5.
- Développer \(10-(x-3)^2\).
- Diviser h par 10 multiplie environ par 10 le nombre de points testés.
(a)
def f(x):
return -x*x + 6*x + 1
def maximum_balayage(h):
if h <= 0:
return None
x = 0.0
xmax = 0.0
ymax = f(0.0)
while x <= 6 + 1e-12:
y = f(x)
if y > ymax:
xmax, ymax = x, y
x += h
return xmax, ymax(b)
Avec \(h=0{,}5\), la grille contient \(x=3\). On obtient \(f(3)=-9+18+1=10\), et aucun point de la grille ne donne davantage. Le résultat est donc (3.0, 10.0).
(c)
\(10-(x-3)^2=10-(x^2-6x+9)=-x^2+6x+1=f(x)\). Comme \((x-3)^2\ge0\), on a \(f(x)\le10\), avec égalité exactement pour \(x=3\). Le maximum exact est 10.
(d)
Un pas plus petit donne une grille plus fine et peut rapprocher davantage le point testé du véritable maximum. En contrepartie, le nombre d’évaluations augmente : avec un pas dix fois plus petit, on effectue environ dix fois plus de calculs.
Exercice 29 - Approximation géométrique - longueur d’une courbe
Ex. 29/30On approxime la longueur de la courbe \(y=x^2\) entre \(x=0\) et \(x=2\) par une ligne brisée reliant n points régulièrement espacés.
- Écrire une fonction
longueur(n)qui additionne les distances entre points consécutifs. - Pour \(n=4\) sous-intervalles, donner les cinq abscisses utilisées.
- Calculer la longueur approchée pour \(n=4\) à \(10^{-4}\) près.
- Expliquer pourquoi augmenter n améliore en général l’approximation.
- Le pas est \(h=2/n\) et les points sont \((kh,(kh)^2)\).
- Pour n=4, h=0,5.
- Additionner quatre distances avec
math.hypot(dx, dy). - Une ligne brisée plus fine suit plus étroitement la courbe.
(a)
from math import hypot
def longueur(n):
if n <= 0:
return None
h = 2/n
x0 = 0.0
y0 = 0.0
L = 0.0
for k in range(1, n + 1):
x1 = k*h
y1 = x1*x1
L += hypot(x1-x0, y1-y0)
x0, y0 = x1, y1
return L(b)
Avec \(h=0{,}5\), les abscisses sont \(0\), \(0{,}5\), \(1\), \(1{,}5\) et \(2\). Les points sont donc \((0;0)\), \((0{,}5;0{,}25)\), \((1;1)\), \((1{,}5;2{,}25)\) et \((2;4)\).
(c)
Les quatre longueurs sont calculées entre points successifs. Leur somme vaut environ \(4{,}6267\). Ainsi longueur(4) renvoie approximativement 4.6267.
(d)
Quand n augmente, les segments sont plus courts et la ligne brisée épouse davantage la variation locale de la courbe. L’approximation de sa longueur devient donc en général plus fine.
Exercice 30 - Simulation conditionnelle - arbre à deux étapes
Ex. 30/30Une population contient 40 % d’individus du groupe A et 60 % du groupe B. Un test est positif avec probabilité 0,7 dans A et 0,3 dans B.
- Écrire une simulation qui génère d’abord le groupe puis le résultat du test et estime \(P(A\mid T)\), où T signifie « test positif ».
- Calculer exactement \(P(T)\).
- Calculer exactement \(P(A\mid T)\).
- Expliquer pourquoi, dans la simulation, il faut diviser le nombre de cas « A et T » par le nombre total de cas T, et non par N.
- Premier tirage : A si
random.random() < 0.4. Deuxième tirage : le seuil dépend du groupe. - \(P(T)=P(A)P(T\mid A)+P(B)P(T\mid B)\).
- \(P(A\mid T)=\dfrac{P(A\cap T)}{P(T)}\).
- Une probabilité conditionnelle change l’univers de référence : on ne regarde que les cas où T est réalisé.
(a)
import random
def estime_A_sachant_T(N):
if N <= 0:
return None
nb_T = 0
nb_A_et_T = 0
for k in range(N):
est_A = random.random() < 0.4
if est_A:
positif = random.random() < 0.7
else:
positif = random.random() < 0.3
if positif:
nb_T += 1
if est_A:
nb_A_et_T += 1
if nb_T == 0:
return None
return nb_A_et_T / nb_T(b)
\(P(T)=0{,}4\times0{,}7+0{,}6\times0{,}3=0{,}28+0{,}18=0{,}46\).
(c)
\(P(A\cap T)=0{,}4\times0{,}7=0{,}28\). Donc \(P(A\mid T)=\dfrac{0{,}28}{0{,}46}=\dfrac{28}{46}=\dfrac{14}{23}\approx0{,}6087\).
(d)
Le conditionnement par T signifie que l’on se restreint aux expériences où le test est positif. Parmi ces nb_T expériences, on compte celles qui appartiennent aussi à A. L’estimateur correct est donc nb_A_et_T / nb_T. Diviser par N estimerait \(P(A\cap T)\), pas \(P(A\mid T)\).