Le Cahier de Maths

Partie 4 · Algorithmique et programmation · Chapitre 21

Écrire des programmes simples

Variables, boucles, fonctions.

Le chapitre précédent a donné le vocabulaire. Celui-ci apprend à s’en servir pour construire les trois programmes qui reviennent dans tous les sujets : accumuler une somme, chercher un seuil, et fabriquer une fonction que l’on pourra appeler avec n’importe quelle valeur.

La boucle bornée

Définition : Boucle for

La boucle for\texttt{for} répète un bloc d’instructions un nombre de fois connu à l’avance. À chaque tour, la variable de boucle prend la valeur suivante de la séquence parcourue.

for i in range(4):    print(i)

Ce que le programme affiche

0
1
2
3
for i in range(4):i = 0corpsi = 1corpsi = 2corpsi = 3corps4 tours
Déroulement de for i in range(4) : le corps est exécuté quatre fois, avec i valant successivement 0, 1, 2 puis 3.

Remarque : la variable de boucle existe après la boucle

À la sortie de la boucle, i\texttt{i} conserve sa dernière valeur, ici 33. On évite toutefois de s’en servir : un programme lisible ne réutilise pas une variable de boucle en dehors de sa boucle.

$\texttt{range}$ en détail

C’est la source d’erreur numéro un des sujets de baccalauréat. La règle tient en une phrase : la borne de gauche est incluse, celle de droite est exclue.

ÉcritureValeurs parcouruesNombre de tours
range(5)\texttt{range(5)}0, 1, 2, 3, 40,\ 1,\ 2,\ 3,\ 455
range(2, 7)\texttt{range(2, 7)}2, 3, 4, 5, 62,\ 3,\ 4,\ 5,\ 655
range(1, n + 1)\texttt{range(1, n + 1)}1, 2, , n1,\ 2,\ \dots,\ nnn
range(0, 10, 3)\texttt{range(0, 10, 3)}0, 3, 6, 90,\ 3,\ 6,\ 944
range(5, 0, -1)\texttt{range(5, 0, -1)}5, 4, 3, 2, 15,\ 4,\ 3,\ 2,\ 155

Méthode : traduire un intervalle d’entiers

  • « pour kk allant de 11 à nn » s’écrit range(1, n + 1)\texttt{range(1, n + 1)} : sans le +1+1, on s’arrête à n1n - 1.
  • « nn répétitions » s’écrit range(n)\texttt{range(n)}, sans se préoccuper des valeurs prises.
  • Pour descendre, le troisième argument est le pas, ici négatif.

Exemple

for i in range(5, 0, -1):    print(i)

Ce que le programme affiche

5
4
3
2
1

Accumuler dans une variable

Le même schéma sert à calculer une somme, un produit ou un effectif : on prépare une variable avant la boucle, puis on la met à jour à chaque tour.

Méthode : le schéma d’accumulation

  • Initialiser avant la boucle : s = 0\texttt{s = 0} pour une somme, p = 1\texttt{p = 1} pour un produit, c = 0\texttt{c = 0} pour un compteur.
  • Mettre à jour dans la boucle, par une affectation du type s = s + ...\texttt{s = s + ...}.
  • Utiliser le résultat après la boucle, une fois tous les tours faits.

L’initialisation doit se trouver avant la boucle. Placée dedans, elle remettrait le total à zéro à chaque tour.

Exemple : une somme

Calcul de 1+2++101 + 2 + \dots + 10 :

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

Ce que le programme affiche

55

Exemple : un produit

Calcul de 5!5!, la factorielle rencontrée au chapitre du dénombrement :

p = 1for k in range(1, 6):    p = p * kprint(p)

Ce que le programme affiche

120

Un produit s’initialise à 11, jamais à 00 : sinon tout le calcul resterait nul.

Exemple : un compteur

Combien y a-t-il de multiples de 77 entre 11 et 100100 ?

compteur = 0for k in range(1, 101):    if k % 7 == 0:        compteur = compteur + 1print(compteur)

Ce que le programme affiche

14

On retrouve bien 1414, puisque les multiples cherchés vont de 7×17 \times 1 à 7×14=987 \times 14 = 98.

Chercher un seuil

Quand le nombre de tours dépend du résultat, la boucle bornée ne convient plus : on ne peut pas écrire dans le range\texttt{range} un nombre que l’on cherche justement à déterminer.

Méthode : le schéma de recherche de seuil

  • Initialiser le terme au premier de la suite, et le compteur de rang à 00.
  • Écrire la condition de poursuite, c’est-à-dire la négation de ce que l’on cherche.
  • Dans le corps, calculer le terme suivant puis incrémenter le rang.
  • Après la boucle, le compteur contient le premier rang qui vérifie la condition cherchée.
débuti < 5 ?ouii = i + 1nonfin
Organigramme d’une boucle non bornée : après le corps, la flèche rouge revient AVANT le test, qui est donc réévalué à chaque tour.

Exemple

Cherchons le plus petit entier nn tel que 3n>10003^{\,n} > 1000. On part de 30=13^0 = 1 et on multiplie par 33 à chaque tour :

u = 1n = 0while u <= 1000:    u = 3 * u    n = n + 1print(n, u)

Ce que le programme affiche

7 2187

Le programme affiche 77 et 21872187 : en effet 36=72910003^6 = 729 \leqslant 1000 alors que 37=2187>10003^7 = 2187 > 1000.

s = 3246810n
Termes de la suite définie par u(n) = 10 × 0,7ⁿ et seuil s = 3 : le premier terme sous le seuil, en rouge, est celui de rang 4.

Exemple

Pour la suite un=10×0,7nu_n = 10 \times 0{,}7^{\,n} représentée ci-dessus, on cherche le premier rang où elle passe sous 33 :

u = 10n = 0while u >= 3:    u = 0.7 * u    n = n + 1print(n)

Ce que le programme affiche

4

Remarque : poursuite ou arrêt

La condition écrite après while\texttt{while} est celle qui fait continuer, pas celle que l’on cherche. Pour trouver le premier terme strictement inférieur à 33, on écrit donc while u >= 3:\texttt{while u >= 3:}, c’est-à-dire la négation de u < 3\texttt{u < 3}. Se tromper de sens est l’erreur la plus fréquente de ce type d’exercice.

Écrire une fonction

Définition : Fonction

Une fonction est un bloc d’instructions nommé, que l’on peut exécuter autant de fois qu’on veut avec des valeurs différentes. On la définit par def\texttt{def}, on lui donne des paramètres, et elle renvoie un résultat par return\texttt{return}.

def carre(x):    return x * xprint(carre(3))print(carre(-5))

Ce que le programme affiche

9
25
3argumentcarrereturn x * x9valeur renvoyée
Une fonction se comporte comme une boîte : l’argument entre par le paramètre, le résultat sort par return.

Méthode : anatomie d’une fonction

  • def\texttt{def} suivi du nom, des paramètres entre parenthèses, et d’un deux-points.
  • Le corps est indenté, comme tout bloc.
  • return\texttt{return} renvoie le résultat et termine immédiatement la fonction : les lignes suivantes ne sont pas exécutées.
  • L’appel s’écrit carre(3)\texttt{carre(3)} : la valeur 33, appelée argument, est rangée dans le paramètre x\texttt{x}.

Exemple

Une fonction peut contenir une boucle. Celle-ci calcule 12+22++n21^2 + 2^2 + \dots + n^2 pour n’importe quel nn :

def somme_carres(n):    s = 0    for k in range(1, n + 1):        s = s + k * k    return sprint(somme_carres(10))

Ce que le programme affiche

385

Le même programme écrit sans fonction ne servirait qu’une fois, pour la seule valeur n=10n = 10.

$\texttt{return}$ n’est pas $\texttt{print}$

C’est la confusion la plus coûteuse du chapitre, car le programme semble marcher : quelque chose s’affiche bien à l’écran.

Propriété : Deux rôles à ne pas confondre

  • print\texttt{print} affiche une valeur pour l’utilisateur. Le programme, lui, n’en récupère rien.
  • return\texttt{return} renvoie une valeur au programme, qui peut la stocker, la réutiliser ou la recalculer.
  • Une fonction sans return\texttt{return} renvoie la valeur spéciale None\texttt{None}, qui signifie « rien ».

Exemple

def double_affiche(x):    print(2 * x)def double_renvoie(x):    return 2 * xa = double_affiche(5)b = double_renvoie(5)print(a, b)

Ce que le programme affiche

10
None 10

La première fonction affiche 1010, mais ne renvoie rien : a\texttt{a} vaut None\texttt{None}. La seconde n’affiche rien, mais b\texttt{b} vaut 1010 et pourra servir dans un calcul. Dès qu’un résultat doit être réutilisé, il faut un return\texttt{return}.

Application aux suites

Voici l’usage le plus fréquent au baccalauréat : une suite définie par récurrence, dont on veut un terme quelconque ou un rang de dépassement.

Exemple : calculer un terme

Pour la suite définie par u0=50u_0 = 50 et un+1=0,8un+1u_{n+1} = 0{,}8\,u_n + 1, on part du premier terme et on applique nn fois la relation :

def terme(n):    u = 50    for i in range(n):        u = 0.8 * u + 1    return uprint(terme(1))print(round(terme(2), 3))

Ce que le programme affiche

41.0
33.8

La boucle tourne exactement nn fois, ce qui fait passer de u0u_0 à unu_n. Pour n=0n = 0, elle ne tourne pas et la fonction renvoie bien u0=50u_0 = 50.

Exemple : trouver un rang

Avec un paramètre, la même idée donne le rang de franchissement pour n’importe quel seuil :

def seuil(limite):    u = 50    n = 0    while u >= limite:        u = 0.8 * u + 1        n = n + 1    return nprint(seuil(10))print(seuil(6))

Ce que le programme affiche

10
18

Plus le seuil est proche de la limite de la suite, ici 55, plus il faut de termes pour l’atteindre.

Remarque : les décimaux ne sont pas exacts

print(0.1 + 0.2)

Ce que le programme affiche

0.30000000000000004

La machine ne stocke qu’une valeur approchée des nombres décimaux. Deux conséquences : on affiche les résultats avec round(x, 2)\texttt{round(x, 2)}, et l’on ne teste jamais l’égalité de deux décimaux par ==\texttt{==}. Pour les entiers, en revanche, Python est exact, quelle que soit leur taille.

Erreurs classiques à éviter

  • Écrire range(1, n)\texttt{range(1, n)} pour aller de 11 à nn.

    La borne de droite est exclue : il faut range(1, n + 1)\texttt{range(1, n + 1)}. Sinon le dernier terme manque, et la somme est fausse d’exactement nn.

  • Initialiser l’accumulateur à l’intérieur de la boucle.

    s = 0\texttt{s = 0} doit être avant la boucle. Placée dedans, cette ligne remet le total à zéro à chaque tour, et le résultat final est le dernier terme seul.

  • Initialiser un produit à 00.

    Un produit s’initialise à 11, élément neutre de la multiplication. À partir de 00, tout produit reste nul.

  • Écrire dans le while\texttt{while} la condition d’arrêt au lieu de celle de poursuite.

    Après while\texttt{while} figure la condition qui fait continuer. Pour trouver le premier terme inférieur à 33, on écrit while u >= 3:\texttt{while u >= 3:}, la négation de ce que l’on cherche.

  • Confondre return\texttt{return} et print\texttt{print}.

    print\texttt{print} affiche pour l’utilisateur, return\texttt{return} renvoie au programme. Une fonction sans return\texttt{return} renvoie None\texttt{None}, et son résultat est inutilisable dans un calcul.

  • Placer des instructions après le return\texttt{return}.

    return\texttt{return} termine la fonction sur-le-champ. Toute ligne écrite après, au même niveau d’indentation, ne sera jamais exécutée.

  • Oublier d’appeler la fonction.

    Définir une fonction n’exécute rien : def\texttt{def} ne fait que la mémoriser. Il faut ensuite l’appeler, par exemple print(carre(3))\texttt{print(carre(3))}.

  • Tester l’égalité de deux nombres décimaux.

    Les décimaux sont stockés de façon approchée : 0.1 + 0.2 == 0.3\texttt{0.1 + 0.2 == 0.3} est faux en Python. On compare avec <\texttt{<} ou >\texttt{>}, ou l’on arrondit avant.

Et maintenant

Le cours est lu ? Vérifie qu’il est acquis : le QCM repère les trous, les exercices confirment en conditions réelles, les flashcards ancrent les formules.