Terminale → prépa scientifique

Cours de Python Prépa

Chaque programme peut être modifié puis exécuté directement dans la page.

Ce cours de Python s’adresse aux élèves de Terminale qui préparent une entrée en classe préparatoire scientifique ou commerciale — MPSI, PCSI, MP2I, PTSI, BCPST, TSI, ECG, ECT — ainsi qu’aux étudiants de maths sup et de première année de licence de mathématiques ou d’informatique.

CoursPython

11 sections

Cours

Python

1. Premiers pas : variables, types et opérations

Un programme Python manipule des valeurs rangées dans des variables. Les instructions s'exécutent dans l'ordre où elles sont écrites ; l'affectation s'écrit avec le signe =.

Exercice guidé

Déterminer la valeur affichée par le programme ci-dessous, puis cliquer sur « Exécuter » pour vérifier. Modifier ensuite la première ligne, et elle seule, pour que le programme affiche 13.

Code modifiable
SolutionVoir la solutionMasquer
Code modifiable

Avec a = 5, la deuxième ligne calcule 2×5+3=132\times5+3=13 et range cette valeur dans b.

Python évalue d'abord le membre de droite, avec les valeurs courantes des variables, puis range le résultat dans la variable écrite à gauche. L'instruction a=a+2 remplace ainsi la valeur de a par a+2 :

Code modifiable

Ce programme affiche 7, puis True : le test d'égalité s'écrit ==, à ne pas confondre avec l'affectation =. Le caractère # introduit un commentaire, ignoré à l'exécution.

Les types de base

Les types de base

  • int : les entiers, comme 3 ou -12 ;

  • float : les nombres à virgule flottante, comme 2.5 (attention : point décimal, jamais de virgule) ;

  • bool : les deux booléens True et False ;

  • str : les chaînes de caractères, comme 'Bonjour'.

La commande type(x) renvoie le type de x. Les conversions se font avec int(...) et float(...).

Les opérations arithmétiques sont +, -, *, / et ** (puissance).

Division, quotient et reste

La division / renvoie toujours un flottant : 6/3 vaut 2.0. On dispose aussi du quotient entier // et du reste % : 17//5 vaut 3 et 17%5 vaut 2, car 17=5×3+217=5\times3+2.

Une comparaison renvoie un booléen : par exemple 3==2+1 vaut True.

Comparaisons et opérateurs logiques

Une comparaison (==, !=, <, <=, >, >=) renvoie un booléen ; les booléens se combinent avec and, or et not. Le test d'égalité == ne doit pas être confondu avec l'affectation =.

2. Les listes

Une liste regroupe des valeurs numérotées à partir de 00 : dans une liste de longueur nn, les indices vont de 00 à n−1n-1.

Console Python

Indices, sous-listes et opérations sur les listes

  • L[-1] désigne le dernier élément, L[-2] l'avant-dernier ;

  • L[a:b] extrait la sous-liste des indices a à b-1 : la borne droite est exclue ;

  • L1+L2 concatène deux listes ; [0]*n crée une liste de nn zéros ;

  • list(range(n)) donne la liste [0,1,...,n-1] ;

  • x in L teste si x appartient à la liste ; L.index(x) renvoie l'indice de sa première occurrence lorsque x est présent.

Le piège de la copie

Le piège de la copie

L'affectation M=L ne crée pas une nouvelle liste : les deux noms désignent la même liste, et modifier l'une modifie l'autre. Pour obtenir une copie indépendante, on écrit M=list(L).

Remarque — listes en compréhension

L'écriture [k**2 for k in range(1,6)] construit directement la liste [1,4,9,16,25]. Cette syntaxe n'est pas exigible mais elle est très répandue dans les sujets ; il faut au moins savoir la lire.

3. Les tests : if, elif, else

L'instruction conditionnelle exécute un bloc seulement si une condition est vraie. Le bloc est délimité par l'indentation (un décalage de quatre espaces) et les deux-points sont obligatoires.

Exemple : afficher la valeur absolue d'un réel saisi au clavier.

Code modifiable

La première ligne lit une chaîne de caractères au clavier avec input(), puis la convertit en flottant avec float : c'est la forme habituelle pour saisir un nombre.

La clause else est facultative. Pour enchaîner plusieurs cas exclusifs, on utilise elif :

Code modifiable

4. Les boucles

La boucle for

La boucle for et range

for k in range(a,b): répète un bloc pour k allant de a à b-1 : comme pour les listes, la borne droite est exclue. range(n) équivaut à range(0,n).

Premier schéma fondamental, l'accumulateur : calculer ∑k=1100k2\displaystyle\sum_{k=1}^{100}k^2.

Code modifiable

Méthode — L'accumulateur

On initialise S à 00 avant la boucle, on l'enrichit à chaque tour, on l'exploite après la boucle. Pour un produit, on initialise à 11.

On peut aussi parcourir directement une liste ou une chaîne de caractères : for x in L: donne à x successivement chaque élément de L.

Deuxième schéma fondamental, la suite récurrente : si u0=1u_0=1 et un+1=12(un+2un)u_{n+1}=\dfrac12\left(u_n+\dfrac2{u_n}\right) (méthode de Héron, qui converge vers 2\sqrt2), le script suivant affiche u20u_{20} :

Code modifiable

Méthode — La suite récurrente

Partir de u=u0, puis répéter u=f(u) : après nn tours de boucle, u contient unu_n. Une seule variable suffit, chaque tour écrase la valeur précédente ; pour conserver tous les termes, on les range dans une liste (voir la section 7).

La boucle while

Quand le nombre d'itérations n'est pas connu à l'avance, on utilise while : le bloc est répété tant que la condition est vraie. C'est l'outil des recherches de rang d'arrêt, très fréquentes aux concours.

Exemple : pour un=0,8nu_n=0{,}8^n, afficher le plus petit entier nn tel que un<10−3u_n<10^{-3}.

Code modifiable

Méthode — Le rang d'arrêt

Pour trouver le plus petit rang où une condition cesse d'être vraie, on utilise une boucle while avec un compteur n=n+1. Attention : la condition du while est une condition de poursuite, pas d'arrêt, et il faut toujours s'assurer que la boucle termine — ici parce que (un)(u_n) tend vers 00.

Trois schémas à connaître

  • Accumulateur : initialiser S=0 (ou P=1) avant la boucle, enrichir à chaque tour, exploiter après.

  • Suite récurrente : partir de u=u0 puis répéter u=f(u) ; après nn tours, u contient unu_n.

  • Rang d'arrêt : boucle while avec un compteur n=n+1, pour trouver le rang minimal où une condition cesse d'être vraie (valeurs approchées de limites, sommes de séries).

5. Les fonctions

Une fonction reçoit des arguments et renvoie un résultat avec return :

Code modifiable

Après cette définition, f(3) vaut 10 et on peut composer : f(f(1)) vaut 5.

Un argument peut recevoir une valeur par défaut. Par exemple, def puissance(x,n=2): return x**n permet d'écrire puissance(3) pour obtenir 99, ou puissance(3,4) pour obtenir 8181. Cette commodité n'est pas exigible, mais sa lecture ne doit pas surprendre dans un sujet.

Une fonction peut prendre plusieurs arguments et renvoyer plusieurs valeurs :

Code modifiable

print, return et variables locales

  • print affiche, return renvoie : une fonction qui se contente d'afficher ne peut pas être réutilisée dans un calcul. Aux concours, on attend presque toujours un return.

  • Les variables créées à l'intérieur d'une fonction sont locales : elles n'existent que pendant son exécution.

6. Les bibliothèques : numpy, numpy.random et matplotlib

Python de base ne connaît ni la racine carrée ni le cosinus : ces outils vivent dans des bibliothèques à importer en tête de script.

Les imports du programme

Code modifiable

L'écriture import numpy as np importe la bibliothèque sous l'abréviation np ; l'écriture from math import * rend toutes les fonctions de math disponibles sans préfixe.

print(...) affiche une ou plusieurs valeurs. Le module math fournit cos, exp, log, atan, etc. ; numpy fournit les mêmes fonctions, utilisables sur des tableaux.

Tableaux numpy

La bibliothèque numpy manipule des vecteurs et des matrices sous forme de tableaux :

Créer et manipuler un tableau numpy

  • np.array([1,2,3]) crée un vecteur, np.array([[2,7],[5,3]]) une matrice 2×22\times2 donnée ligne par ligne ;

  • np.zeros((n,p)), np.ones((n,p)) et np.eye(n) créent la matrice nulle, la matrice de 11 et la matrice identité ;

  • np.arange(a,b,pas) et np.linspace(a,b,n) créent des subdivisions régulières (la première par pas fixé, la seconde par nombre de points fixé) ;

  • M[i,j] extrait le coefficient d'indices (i,j)(i,j) (numérotés depuis 00), M[i,:] la ligne ii, M[:,j] la colonne jj ;

  • n,p = np.shape(M) récupère la taille de M.

Opérations sur les tableaux et produit matriciel

Les opérations +, -, *, /, ** s'appliquent coefficient par coefficient. En particulier A*B n'est pas le produit matriciel : celui-ci s'obtient avec np.dot(A,B), et la transposée avec np.transpose(A).

Console Python

Enfin, np.sum, np.min, np.max, np.mean, np.median, np.var, np.std et np.cumsum s'appliquent à un tableau entier (somme, minimum, maximum, moyenne, médiane, variance, écart-type et sommes cumulées). Les fonctions usuelles np.exp, np.log, np.sin, np.cos, np.sqrt, np.abs, np.floor agissent élément par élément, et les constantes ee et π\pi s'écrivent np.e et np.pi.

La bibliothèque numpy.linalg (résolution de systèmes, inverse, rang) est détaillée dans la section 11, et numpy.random (échantillons de lois usuelles) dans la section 8.

7. Tracer une courbe, représenter une suite

En Python, pour représenter une fonction ff sur un segment [a,b][a,b], on place un nombre fini de points de sa courbe, puis on relie chaque point au suivant par un segment. On choisit pour cela des abscisses x0<x1<⋯<xN−1x_0<x_1<\cdots<x_{N-1} dans [a,b][a,b] et on calcule leurs images f(x0),…,f(xN−1)f(x_0),\dots,f(x_{N-1}). Lorsque les abscisses sont assez rapprochées, la ligne brisée obtenue ne se distingue pas à l'œil de la courbe représentative de ff.

Méthode — Tracer la courbe d'une fonction

  • On construit le tableau des abscisses, par exemple x=np.linspace(a,b,N), qui contient NN réels régulièrement espacés de aa à bb, les deux bornes comprises.

  • On calcule le tableau des ordonnées en une seule instruction, comme y=np.exp(x) : les fonctions de numpy agissent élément par élément.

  • On appelle plt.plot(x,y), une fois pour chaque courbe à superposer, puis plt.show() pour afficher la figure.

Python donne à chaque courbe sa propre couleur. Les commandes plt.grid() et plt.title('...') ajoutent un quadrillage et un titre ; l'option 'o' trace des points isolés, sans les relier.

Exemple : comparer sur [−2,2][-2,2] la courbe de la fonction exponentielle et sa tangente au point d'abscisse 00. Cette tangente passe par le point (0,1)(0,1), et son coefficient directeur vaut exp⁡′(0)=e0=1\exp'(0)=e^0=1 : son équation est y=1+xy=1+x.

Code modifiable

La première ligne construit 201201 abscisses de −2-2 à 22 : deux abscisses consécutives sont distantes de 2−(−2)200=0,02\dfrac{2-(-2)}{200}=0{,}02. La deuxième ligne calcule d'un coup les 201201 ordonnées np.exp(x) et trace la courbe de l'exponentielle. La troisième trace la tangente sans écrire de boucle, car 1+x est lui-même un tableau, calculé élément par élément. Avec np.arange(-2,2,0.02), on obtiendrait des abscisses espacées de 0,020{,}02 elles aussi, mais de −2-2 à 1,981{,}98 seulement, car la borne droite de np.arange est exclue, comme celle de range.

La courbe de l’exponentielle et sa tangente y = 1 + x au point d’abscisse 0.

On remarque que la courbe de l'exponentielle reste au-dessus de sa tangente. Le graphique illustre ainsi l'inégalité ex≥1+xe^x\geq1+x, vraie pour tout réel xx, mais il ne la démontre pas. Pour la démontrer, on étudie la fonction g:x↦ex−1−xg:x\mapsto e^x-1-x. Sa dérivée g′:x↦ex−1g':x\mapsto e^x-1 est négative sur ]−∞,0]]-\infty,0] et positive sur [0,+∞[[0,+\infty[, donc gg atteint en 00 son minimum, qui vaut g(0)=0g(0)=0. La fonction gg est donc positive sur R\R, ce qui donne l'inégalité ex≥1+xe^x\geq1+x quel que soit le réel xx.

Représenter les termes d'une suite

Pour une suite, le programme demande de savoir représenter les points (n,un)(n,u_n). On range les termes dans une liste, puis on les trace avec l'option 'o' (points isolés, sans ligne). Avec la suite de Héron de la section 4 :

Code modifiable

Le graphique rend la convergence vers 2\sqrt2 visible dès les premiers rangs.

Les itérés de Héron se stabilisent rapidement autour de √2.

8. Simuler une expérience aléatoire et étudier un échantillon

rd.random, rd.randint et la borne exclue

rd.random() renvoie un réel uniforme dans [0,1[[0,1[ et rd.randint(a,b) un entier uniforme dans ⟦a,b−1⟧\llbracket a,b-1\rrbracket : contrairement à la fonction homonyme du module standard random, la borne droite est exclue. rd.choice(liste) effectue un tirage uniforme dans une liste et rd.shuffle(liste) mélange la liste sur place.

Le module numpy.random, abrégé en rd, fournit ainsi les briques de base :

Simuler une expérience élémentaire

  • un lancer de dé équilibré : rd.randint(1,7) ;

  • une épreuve de Bernoulli de paramètre pp : le test rd.random()<p vaut True avec probabilité pp ;

  • un tirage uniforme dans une liste : rd.choice(L).

Estimer une probabilité par simulation

Si P(A)P(A) est difficile à calculer, on simule NN fois l'expérience (avec NN grand) et on assimile P(A)P(A) à la fréquence de réalisation de AA. Cette approche, dite de Monte-Carlo, est confortée par la loi faible des grands nombres.

Exemple : estimer la probabilité d'obtenir au moins un 66 en quatre lancers d'un dé équilibré.

Code modifiable

La valeur exacte est 1−(56)4≈0,51771-\left(\dfrac56\right)^4\approx0{,}5177 ; le script affiche une fréquence proche de cette valeur.

Échantillons avec numpy.random

Échantillons de lois usuelles

Pour simuler d'un coup un échantillon d'une loi usuelle, rd.binomial(n,p,N), rd.geometric(p,N), rd.poisson(lam,N) et rd.randint(a,b,N) renvoient un tableau de NN simulations, et rd.random(N) un tableau de NN réels uniformes dans [0,1[[0,1[.

La commande plt.hist(ech) trace l'histogramme d'un échantillon ech : on peut ainsi comparer les fréquences observées à la loi théorique, par exemple confronter un échantillon de loi B(n,λn)\mathcal{B}\left(n,\frac{\lambda}{n}\right) à un échantillon de loi de Poisson P(λ)\mathcal{P}(\lambda).

Indicateurs empiriques

Indicateurs empiriques d'un échantillon

Pour un échantillon ech, les commandes np.mean(ech), np.median(ech), np.var(ech) et np.std(ech) donnent respectivement la moyenne, la médiane, la variance et l'écart-type empiriques. Lorsque la taille de l'échantillon augmente, la loi des grands nombres explique le rapprochement entre moyenne empirique et espérance.

Code modifiable

Ici, la moyenne et la variance empiriques sont proches des valeurs théoriques np=6np=6 et np(1−p)=4,2np(1-p)=4{,}2.

Approche expérimentale de la loi de Gauss

Si X∼B(n,p)X\sim\mathcal{B}(n,p) avec nn grand et pp éloigné de 00 et de 11, la variable centrée réduite

Z=X−npnp(1−p)Z=\frac{X-np}{\sqrt{np(1-p)}}

présente un histogramme proche de la courbe de densité x↦12πe−x2/2x\mapsto\dfrac{1}{\sqrt{2\pi}}e^{-x^2/2}. Cette comparaison est expérimentale : elle sert à visualiser l'approximation gaussienne, pas à la démontrer.

Code modifiable
La loi binomiale centrée réduite se rapproche de la densité gaussienne.

9. La méthode de dichotomie

On cherche une valeur approchée d'une solution de l'équation f(x)=0f(x)=0, lorsque l'on ne sait pas la résoudre de façon exacte. La méthode de dichotomie s'applique à une fonction ff continue sur un segment, à condition que ff prenne aux deux extrémités de ce segment des valeurs de signes contraires.

Principe de la méthode

Soit ff continue sur [a,b][a,b], avec f(a)f(b)≤0f(a)f(b)\leq0. Cette condition signifie que l'un des nombres f(a)f(a) et f(b)f(b) est nul, ou qu'ils ont des signes contraires. Le théorème des valeurs intermédiaires assure alors l'existence d'au moins un zéro de ff dans [a,b][a,b].

On note m=a+b2m=\dfrac{a+b}{2} le milieu de [a,b][a,b], et on examine le signe de f(a)f(m)f(a)f(m) :

  • si f(a)f(m)≤0f(a)f(m)\leq0, le théorème des valeurs intermédiaires, appliqué sur [a,m][a,m], montre que ff s'annule sur [a,m][a,m] ; on remplace alors bb par mm ;

  • sinon, f(a)f(m)>0f(a)f(m)>0, donc f(a)f(a) et f(m)f(m) sont non nuls et de même signe. Comme f(a)f(b)≤0f(a)f(b)\leq0, le réel f(b)f(b) est nul ou de signe contraire à celui de f(a)f(a), donc à celui de f(m)f(m). Ainsi f(m)f(b)≤0f(m)f(b)\leq0 et ff s'annule sur [m,b][m,b] ; on remplace alors aa par mm.

Dans les deux cas, le nouveau segment [a,b][a,b] vérifie encore f(a)f(b)≤0f(a)f(b)\leq0 : il contient encore une solution, et sa longueur a été divisée par 22. On répète cette étape. Notons [an,bn][a_n,b_n] le segment obtenu après nn étapes, avec [a0,b0]=[a,b][a_0,b_0]=[a,b]. Pour tout n∈Nn\in\N, le segment [an,bn][a_n,b_n] contient une solution α\alpha de l'équation et a pour longueur b−a2n\dfrac{b-a}{2^n}. Comme an≤α≤bna_n\leq\alpha\leq b_n, chacune des bornes ana_n et bnb_n est une valeur approchée de α\alpha à b−a2n\dfrac{b-a}{2^n} près.

Critère d'arrêt et nombre d'étapes

On fixe une précision ε>0\varepsilon>0, et on arrête les étapes dès que la longueur bn−anb_n-a_n est inférieure ou égale à ε\varepsilon. Comme bn−an=b−a2nb_n-a_n=\dfrac{b-a}{2^n}, cette condition équivaut à 2n≥b−aε2^n\geq\dfrac{b-a}{\varepsilon}, c'est-à-dire à

n≥ln⁡(b−aε)ln⁡2.n\geq\frac{\ln\left(\frac{b-a}{\varepsilon}\right)}{\ln2}.

Le nombre d'étapes est donc connu avant même de lancer le calcul, et la boucle se termine toujours. Ce nombre dépend seulement de la longueur du segment de départ et de la précision demandée, et non de la fonction ff.

Programme

En Python, une fonction peut recevoir une autre fonction en argument. La fonction dichotomie ci-dessous reçoit ainsi la fonction f dont on cherche un zéro, les bornes a et b du segment de départ et la précision eps. Elle renvoie les bornes du segment final et le nombre n d'étapes effectuées. Le programme l'applique ensuite à deux équations.

Code modifiable

Exemple 1. La fonction f:x↦x3+x−1f:x\mapsto x^3+x-1 est dérivable sur R\R, et f′(x)=3x2+1>0f'(x)=3x^2+1>0 pour tout réel xx : ff est strictement croissante. Elle est aussi continue, et ses valeurs f(0)=−1f(0)=-1 et f(1)=1f(1)=1 encadrent 00. Le théorème de la bijection montre alors que l'équation x3+x−1=0x^3+x-1=0 a exactement une solution α\alpha dans [0,1][0,1]. Pour la précision ε=10−4\varepsilon=10^{-4}, il faut n≥ln⁡(104)ln⁡2≈13,3n\geq\dfrac{\ln\left(10^4\right)}{\ln2}\approx13{,}3, soit 1414 étapes. Le programme affiche en effet (0.68231201171875, 0.682373046875, 14). Les bornes affichées encadrent α\alpha : 0,68231≤α≤0,682380{,}68231\leq\alpha\leq0{,}68238. Le réel 0,68230{,}6823 approche donc α\alpha à 10−410^{-4} près.

La dichotomie resserre un intervalle qui contient l’unique zéro.

Exemple 2. On prend g=sin⁡g=\sin, dont la dérivée est cos⁡\cos. Pour tout x∈[3,4]x\in[3,4], on a π2<x<3π2\dfrac{\pi}{2}<x<\dfrac{3\pi}{2}, donc cos⁡x<0\cos x<0 : gg est strictement décroissante sur [3,4][3,4]. De plus, sin⁡3>0\sin3>0 car 0<3<π0<3<\pi, et sin⁡4<0\sin4<0 car π<4<2π\pi<4<2\pi. La fonction sin⁡\sin s'annule donc une seule fois sur [3,4][3,4], en π\pi, et la dichotomie fournit des valeurs approchées de π\pi. Cette fois, la fonction est positive en 33 et négative en 44. Le programme s'applique sans modification, car le test f(a)*f(m)<=0 porte sur le signe du produit, et non sur le signe de chacun des deux facteurs. Pour ε=10−5\varepsilon=10^{-5}, il faut n≥ln⁡(105)ln⁡2≈16,6n\geq\dfrac{\ln\left(10^5\right)}{\ln2}\approx16{,}6, soit 1717 étapes, et le programme affiche (3.1415863037109375, 3.1415939331054688, 17). Le réel 3,141593{,}14159 est compris entre ces deux bornes, donc il approche π\pi à 10−510^{-5} près.

Limites de la méthode

  • Lorsque l'équation admet plusieurs solutions dans [a,b][a,b], la méthode en approche une seule, et elle ne dit pas laquelle. Pour approcher une solution précise, on l'isole d'abord dans un segment sur lequel ff est strictement monotone, comme dans les deux exemples.

  • La méthode exige un changement de signe. La fonction h:x↦1−cos⁡xh:x\mapsto1-\cos x s'annule en 00, mais elle ne prend aucune valeur strictement négative, car cos⁡x≤1\cos x\leq1 pour tout réel xx. Pour un segment [a,b][a,b], la condition h(a)h(b)≤0h(a)h(b)\leq0 n'est donc vérifiée que si aa ou bb annule hh, c'est-à-dire si l'on connaît déjà un zéro de hh : la méthode ne sert pas à trouver les zéros de cette fonction.

  • Chaque étape divise la longueur du segment par 22 seulement. Comme 210=1024≈1032^{10}=1024\approx10^3, dix étapes font gagner environ trois décimales.

10. La méthode des rectangles

La fonction ln⁡\ln est la primitive sur ]0,+∞[]0,+\infty[ de la fonction t↦1tt\mapsto\dfrac1t qui s'annule en 11. Par conséquent, ln⁡2=∫12dtt\ln2=\displaystyle\int_1^2\frac{dt}{t} : le nombre ln⁡2\ln2 est l'aire du domaine situé sous la courbe de t↦1tt\mapsto\dfrac1t, au-dessus de l'axe des abscisses, pour tt allant de 11 à 22. La méthode des rectangles approche une telle aire par une somme d'aires de rectangles, que l'on calcule avec des additions et des multiplications seulement. Cette section majore l'erreur commise, puis elle confronte cette majoration à la valeur de ln⁡2\ln2 que donne Python.

On fixe un segment [a,b][a,b], une fonction ff de classe C1\mathcal{C}^1 sur [a,b][a,b] et un entier n≥1n\geq1. On partage [a,b][a,b] en nn segments de même longueur h=b−anh=\dfrac{b-a}{n}, d'extrémités xk=a+khx_k=a+kh pour k∈⟦0,n⟧k\in\llbracket0,n\rrbracket. Sur chaque segment [xk,xk+1][x_k,x_{k+1}], on remplace ff par la constante f(xk)f(x_k), sa valeur en l'extrémité gauche du segment. On obtient la somme des rectangles à gauche

Rn=h∑k=0n−1f(xk).R_n=h\sum_{k=0}^{n-1}f(x_k).

Majoration de l'erreur

La dérivée f′f' est continue sur le segment [a,b][a,b] ; on note MM le maximum de ∣f′∣|f'| sur ce segment. On fixe k∈⟦0,n−1⟧k\in\llbracket0,n-1\rrbracket, et on note

ek=∫xkxk+1f(t) dt−hf(xk)e_k=\int_{x_k}^{x_{k+1}}f(t)\,dt-hf(x_k)

l'écart, sur le segment [xk,xk+1][x_k,x_{k+1}], entre l'intégrale de ff et la contribution du rectangle. Le nombre hf(xk)hf(x_k) est l'intégrale sur ce segment de la fonction constante égale à f(xk)f(x_k). La valeur absolue de eke_k est donc au plus l'aire du domaine compris, pour tt allant de xkx_k à xk+1x_{k+1}, entre la droite horizontale d'équation y=f(xk)y=f(x_k) et la courbe de ff.

À l'abscisse tt, ce domaine a pour hauteur ∣f(t)−f(xk)∣|f(t)-f(x_k)|. D'après l'inégalité des accroissements finis, vue au chapitre Dérivation, cette hauteur est au plus égale à MM fois la distance de tt à xkx_k. Or, à la même abscisse tt, le triangle rectangle de sommets (xk,0)(x_k,0), (xk+1,0)(x_{k+1},0) et (xk+1,Mh)(x_{k+1},Mh) a précisément pour hauteur M(t−xk)M(t-x_k). L'aire du domaine est donc au plus celle de ce triangle, dont les côtés de l'angle droit mesurent hh et MhMh :

∣ek∣≤h×Mh2=Mh22.|e_k|\leq\frac{h\times Mh}{2}=\frac{Mh^2}{2}.

D'après la relation de Chasles, l'erreur totale ∫abf(t) dt−Rn\displaystyle\int_a^bf(t)\,dt-R_n est la somme des nn écarts e0,…,en−1e_0,\dots,e_{n-1}. L'inégalité triangulaire donne alors

∣∫abf(t) dt−Rn∣≤n×Mh22=M(b−a)22n.\left|\int_a^bf(t)\,dt-R_n\right|\leq n\times\frac{Mh^2}{2}=\frac{M(b-a)^2}{2n}.

Le majorant devient aussi petit que l'on veut lorsque nn grandit. La somme RnR_n approche ainsi l'intégrale de ff sur [a,b][a,b], et l'inégalité indique combien de rectangles prendre pour garantir une précision donnée.

Huit rectangles à gauche pour la fonction 1/t : leur aire totale dépasse ln 2.
ExempleVoir l’exempleMasquer

On applique la méthode à la fonction f:t↦1tf:t\mapsto\dfrac1t sur [1,2][1,2], pour obtenir ln⁡2\ln2 à 10−310^{-3} près. La fonction ff est dérivable sur [1,2][1,2], et sa dérivée f′:t↦−1t2f':t\mapsto-\dfrac1{t^2} y est continue. Pour tout t∈[1,2]t\in[1,2], on a t2≥1t^2\geq1, donc ∣f′(t)∣=1t2≤1|f'(t)|=\dfrac1{t^2}\leq1. On peut donc prendre M=1M=1, et comme b−a=1b-a=1, la majoration de l'erreur devient

∣ln⁡2−Rn∣≤12n.\left|\ln2-R_n\right|\leq\frac{1}{2n}.

Il suffit que 12n≤10−3\dfrac{1}{2n}\leq10^{-3}, c'est-à-dire que n≥500n\geq500.

Code modifiable

Le programme affiche 0.6936474305598199, puis 0.0005002499998746357. La somme R500≈0,69365R_{500}\approx0{,}69365 est donc bien une valeur approchée de ln⁡2\ln2 à 10−310^{-3} près, et l'erreur réelle, environ 5×10−45\times10^{-4}, vaut la moitié de la majoration. Cette erreur est positive. En effet, ff est décroissante sur [1,2][1,2], donc sur chaque segment [xk,xk+1][x_k,x_{k+1}] le rectangle de hauteur f(xk)f(x_k) contient le domaine situé sous la courbe : la somme RnR_n dépasse ln⁡2\ln2.

La boucle peut aussi s'écrire avec numpy : le tableau a+h*np.arange(n) contient les abscisses x0,…,xn−1x_0,\dots,x_{n-1}, donc h*np.sum(f(a+h*np.arange(n))) calcule la même somme RnR_n.

11. Résolution des systèmes linéaires

Un système de nn équations linéaires à nn inconnues s'écrit sous la forme matricielle AX=BAX=B, où A∈Mn(R)A\in\mathcal{M}_n(\R) est la matrice des coefficients, XX la colonne des inconnues et BB la colonne des seconds membres. Lorsque AA est inversible, on multiplie à gauche par A−1A^{-1} : X=A−1BX=A^{-1}B est alors la seule solution. La commande al.solve(A,B) de la bibliothèque numpy.linalg, importée sous l'abréviation al (section 6), calcule cette solution.

ExempleVoir l’exempleMasquer

Le système

{2x+y=7y+z=3x+3z=9\left\{ \begin{array}{rcl} 2x+y&=&7\\ y+z&=&3\\ x+3z&=&9 \end{array} \right.

s'écrit AX=BAX=B avec

A=(210011103)etB=(739).A=\begin{pmatrix}2&1&0\\0&1&1\\1&0&3\end{pmatrix} \quad\text{et}\quad B=\begin{pmatrix}7\\3\\9\end{pmatrix}.

On donne BB à Python comme un simple tableau à une dimension :

Console Python

Le triplet (3,1,2)(3,1,2) est bien solution, car 2×3+1=72\times3+1=7, 1+2=31+2=3 et 3+3×2=93+3\times2=9 ; la dernière commande fait la même vérification en calculant le produit AXAX.

Remarque

  • Le résultat array([3., 1., 2.]) est un tableau de flottants, comme l'indiquent les points, bien que les coefficients de AA et de BB soient entiers. La commande al.solve calcule en effet en virgule flottante : la solution qu'elle affiche est en général une valeur approchée de la solution exacte.

  • Pour mesurer cette approximation, on calcule le vecteur AX−BAX-B, c'est-à-dire np.dot(A,X)-B. Gardons la matrice AA et prenons pour second membre B=(1,0,0)B=(1,0,0). La solution exacte est alors (37,17,−17)\left(\dfrac37,\dfrac17,-\dfrac17\right), et al.solve renvoie array([0.42857143, 0.14285714, -0.14285714]). Pour cette solution affichée XX, les coefficients de AX−BAX-B valent 00, 00 et environ 5,6×10−175{,}6\times10^{-17} : l'écart est de l'ordre de la précision des flottants.

  • L'équation AX=BAX=B a une solution et une seule exactement lorsque AA est inversible, c'est-à-dire lorsque le rang de AA vaut nn. La commande al.matrix_rank(A) donne ce rang ; ici, elle renvoie 3. La commande al.solve est réservée à ce cas.

  • La bibliothèque numpy.linalg fournit aussi al.inv(A), qui calcule l'inverse de AA, et al.matrix_power(A,n), qui calcule la puissance nn-ième de AA.

Savoir-faire exigibles en première année (programme officiel)

  • Tracer la représentation graphique d'une fonction ou d'une suite (section 7).

  • Calculer une valeur approchée de la limite d'une suite ou de la somme d'une série, par un rang d'arrêt (section 4 et exercice « Boucle while et premier rang » du TD).

  • Calculer une valeur approchée de la racine d'une équation f(x)=0f(x)=0 (dichotomie, section 9).

  • Calculer une valeur approchée d'une intégrale par la méthode des rectangles (section 10).

  • Simuler des expériences aléatoires, des échantillons de lois usuelles, et estimer une probabilité par une fréquence (section 8).

  • Calculer les indicateurs empiriques d'un échantillon, tracer un histogramme et mettre en évidence expérimentalement une approximation gaussienne (section 8).

  • Résoudre un système linéaire AX=BAX=B avec al.solve (section 11).

TDExercices corrigés

8 exercices

TD

Exercices corrigés

Exercice 1

Affectations et types

On considère le script suivant.

Code modifiable
  1. Donner les valeurs affichées et le type des variables a, b et c à la fin du script.

  2. Remplacer la dernière ligne par print(a == b, a > b and c < 4) et prévoir l'affichage.

Votre programme
Voir le corrigé
  1. Python exécute les affectations dans l'ordre : b reçoit 77 avant que a ne soit modifiée. La division / renvoie un flottant.

    Sortie
    8 7 3.5

    Ainsi, a et b sont de type int, tandis que c est de type float.

  2. Les comparaisons a == b et c < 4 valent respectivement False et True. Comme a > b vaut True, l'affichage est :

    Sortie
    False True

Exercice 2

Listes, indices et copies

On exécute les instructions suivantes.

Code modifiable
  1. Donner les listes L, M et N obtenues.

  2. Expliquer pourquoi la modification de M a aussi modifié L, alors que l'ajout dans N n'a pas modifié L.

  3. Écrire une instruction qui affiche l'indice de la valeur 4 dans L, puis une instruction qui teste si 5 appartient à L.

Votre programme
Voir le corrigé
  1. À la fin du script,

    L = [3,8,4],M = [3,8,4],N = [3,1,4,5].\boxed{\texttt{L = [3,8,4]},\quad \texttt{M = [3,8,4]},\quad \texttt{N = [3,1,4,5]}}.
  2. L'affectation M=L donne deux noms à la même liste. Modifier un élément par l'un des noms modifie donc l'objet commun. En revanche, N=list(L) construit une nouvelle liste : son évolution est indépendante.

  3. Les deux instructions demandées sont :

    Code modifiable

    Elles affichent respectivement 2 et False.

Exercice 3

Fonction définie par morceaux

Écrire une fonction ecart(x) qui renvoie

{x−2si x≥2,2−xsi x<2.\begin{cases} x-2 & \text{si }x\geq 2,\\ 2-x & \text{si }x<2. \end{cases}

Sans utiliser la fonction abs, vérifier ensuite que ecart(-1), ecart(2) et ecart(5) renvoient respectivement 33, 00 et 33.

Votre programme
Voir le corrigé

Le test sépare les deux expressions de la fonction.

Code modifiable

Le script affiche 3 0 3.

Exercice 4

Boucle for et bornes de range

  1. Écrire un script qui calcule S=∑k=120k2S=\displaystyle\sum_{k=1}^{20}k^2 avec une boucle for, puis affiche S.

  2. Le script suivant prétend calculer la même somme. Repérer l'erreur et la corriger.

Code modifiable
Votre programme
Voir le corrigé
  1. Un accumulateur initialisé à 00 convient pour une somme.

    Code modifiable

    Le script affiche

    2870.\boxed{2870}.
  2. Dans range(1,20), la borne droite est exclue : la dernière valeur de k est 1919. Il faut remplacer range(1,20) par range(1,21).

Exercice 5

Boucle while et premier rang

On définit u0=10u_0=10 et, pour tout n∈Nn\in\N,

un+1=0,75un.u_{n+1}=0{,}75u_n.

Écrire un script qui affiche le plus petit entier nn tel que un<10−2u_n<10^{-2}. Le script calculera les termes successifs de la suite, sans utiliser directement la formule explicite de unu_n.

Votre programme
Voir le corrigé
Code modifiable

Le script affiche

25.\boxed{25}.

À la sortie, un<10−2u_n<10^{-2}, tandis que la condition était encore fausse au rang précédent : 2525 est donc le plus petit rang convenable.

Exercice 6

Écrire une fonction moyenne

  1. Écrire une fonction moyenne(L) qui reçoit une liste non vide de nombres et renvoie sa moyenne. Utiliser une boucle et un accumulateur, sans appeler sum ni np.mean.

  2. Tester la fonction sur [12, 15, 9, 14].

  3. Expliquer pourquoi remplacer return m par print(m) empêcherait d'utiliser ensuite le résultat dans un calcul.

Votre programme
Voir le corrigé
  1. Un accumulateur parcourt la liste, puis on divise par sa longueur.

    Code modifiable
  2. Code modifiable

    Le total vaut 5050 et la liste contient quatre valeurs, donc la fonction renvoie 12,512{,}5.

  3. return transmet une valeur à l'expression qui appelle la fonction. print se contente de l'afficher : un résultat seulement affiché ne peut pas être réutilisé dans un calcul.

Exercice 7

Tableaux NumPy et produit matriciel

On pose

A=(1234)etB=(0110).A=\begin{pmatrix}1&2\\3&4\end{pmatrix} \qquad\text{et}\qquad B=\begin{pmatrix}0&1\\1&0\end{pmatrix}.
  1. Créer les tableaux A et B avec np.array, puis afficher le coefficient situé sur la deuxième ligne et la première colonne de A.

  2. Prévoir les tableaux renvoyés par A*B et np.dot(A,B), puis vérifier avec Python.

  3. Modifier le coefficient inférieur droit de A pour lui donner la valeur −1-1.

Votre programme
Voir le corrigé
  1. Les indices commencent à 00, donc le coefficient de la deuxième ligne et de la première colonne est A[1,0].

    Code modifiable

    Le script affiche 33.

  2. Le symbole * agit coefficient par coefficient, tandis que np.dot effectue le produit matriciel :

    A*B=(0230),np.dot(A,B)=(2143).\boxed{ \texttt{A*B}=\begin{pmatrix}0&2\\3&0\end{pmatrix}, \qquad \texttt{np.dot(A,B)}=\begin{pmatrix}2&1\\4&3\end{pmatrix} }.
  3. L'instruction demandée est A[1,1]=-1.

Exercice 8

Déboguer une fonction

Le script suivant doit renvoyer le nombre de valeurs strictement positives d'une liste. Il contient trois erreurs de syntaxe ou de structure.

Python
def nombre_positifs(L)
compteur = 0
for x in L:
    if x > 0:
        compteur = compteur + 1
    return compteur

Corriger le script, puis vérifier que nombre_positifs([-2,0,5,3,-1]) renvoie 22.

Votre programme
Voir le corrigé

Il manque le deux-points après la signature de la fonction. Son bloc d'instructions doit être indenté, et return doit être exécuté après la boucle.

Code modifiable

Seuls 55 et 33 sont strictement positifs, donc la fonction renvoie 22.