\chapter{Tests et boucles}

Nous abordons ici des thèmes importants à l'aide desquels il nous sera possible de créer des programmes plus complets, toujours en relation avec les mathématiques.

\newpage

\section{Tests}

\subsection{Mots-clés \og if \fg, \og else \fg{} et \og elif \fg}
\index{Mot-cle@Mot-clé!if}
\index{Mot-cle@Mot-clé!else}

Penchons-nous dans un premier temps sur un programme élémentaire qui consiste à voir si un triangle est rectangle ou pas, à l'aide de la réciproque (ou de la contraposée) du théorème de\linebreak Pythagore. Un algorithme possible est le suivant:

\begin{center}
\fbox{
\begin{minipage}{0.5\linewidth}
\ttfamily
Si a*a + b*b = c*c alors:\\
\hspace*{5mm} Retourner Vrai\\
Sinon:\\
\hspace*{5mm} Retourner Faux
\end{minipage}
}
\end{center}
Un \textit{algorithme} est comme une recette de cuisine: on l'exécute pas à pas.

Cet algorithme traduit en Python donne:

\begin{python}
if a*a + b*b == c*c:
    return True
else:
    return False
\end{python}

Il arrive que certains tests ne soient pas binaires; par exemple, on peut effectuer un test sur le reste de la division euclidienne d'un nombre entier par 3, auquel cas le test est \textit{ternaire}. On peut alors imaginer un algorithme comme le suivant:

\begin{center}
\fbox{
\begin{minipage}{\linewidth}
\ttfamily
Si le reste de la division euclidienne de n par 3 est nul alors:\\
\hspace*{5mm} Retourner "Vrai"\\
Sinon:\\
\hspace*{5mm} Si le reste de la division euclidienne de n par 3 est 1 alors:\\
\hspace*{10mm} Retourner "Pas exactement"\\
\hspace*{5mm} Sinon:\\
\hspace*{10mm} Retourner "Pas du tout"\\
\end{minipage}
}
\end{center}
\enlargethispage*{3em}

On imbrique ici deux tests car on veut retourner trois résultats différents selon le reste de la division. En Python, cela donne :
\index{Mot-cle@Mot-clé!elif}

\begin{python}
if n % 3 == 0:
    return "Vrai"
elif n % 3 == 1:
    return "Pas exactement"
else:
    return "Pas du tout"
\end{python}

\begin{rem}
\texttt{elif} est la contraction de \og \texttt{else if} \fg.
\end{rem}

\subsection{Le mot-clé \og match \fg}
\index{Mot-cle@Mot-clé!match}
\index{Mot-cle@Mot-clé!case}

Depuis Python 3.10, il existe une autre façon de distinguer les divers cas possibles:

\begin{python}
def reste(n):
    match n%3:
        case 0: print('Ce nombre est divisible par 3.')
        case 1: print('Le reste de la division euclidienne de ce nombre par 3 vaut 1.')
        case 2: print('Le reste de la division euclidienne de ce nombre par 3 vaut 2.')
\end{python}

\begin{console}
>>> reste(5)
Le reste de la division euclidienne de ce nombre par 3 vaut 2.
>>> reste(4)
Le reste de la division euclidienne de ce nombre par 3 vaut 1.
>>> reste(12)
Ce nombre est divisible par 3.
\end{console}

Ce mot-clé, cette instruction, s'avèrera très utile dans les situations où plus de trois valeurs pourront être prises par la variables testée.

\begin{exemple}
\begin{python}
def init(mot):
    match mot[0]:
        case 'A': print('Ce mot commence par la lettre A.')
        case 'B': print('Ce mot commence par la lettre B.')
        case 'C': print('Ce mot commence par la lettre C.')
        case _: print('Ce mot ne commence ni par A, ni par B, ni par C.')
\end{python}

\begin{console}
>>> init('Toto')
Ce mot ne commence ni par A, ni par B, ni par C.
>>> init('Abracadabra')
Ce mot commence par la lettre A.
\end{console}
\end{exemple}

Notez dans ce dernier exemple la présente de l'underscore pour désigner \og tous les autres cas \fg: \texttt{case \_}. 

\newpage

\subsection{Opérateurs de comparaison}
\index{Operateurs@Opérateurs!Egalite@Égalité}
\index{Operateurs@Opérateurs!Superieur@Supérieur}
\index{Operateurs@Opérateurs!Inferieur@Inférieur}

Nous avons vu qu'il était possible de voir si deux variables étaient égales à l'aide de l'opérateur \og \texttt{==} \fg. On peut ainsi comparer deux variables de tout type.

Concernant les nombres, il est aussi possible de les comparer afin de voir si le premier est plus grand ou plus petit que le second.

\begin{center}
\arrayrulecolor{exemple}
\begin{tabular}{|>{\ttfamily}Sc|Sc|}
\hline
\rowcolor{exemple}\color{white}\textbf{Opérateur} & \color{white}\textbf{Signification}\\
\hline
a == b & $a$ égal à $b$ ?\\
\hline
a < b & $a$ strictement inférieur à $b$ ?\\
\hline
a <= b & $a$ inférieur ou égal à $b$ ?\\
\hline
a > b & $a$ strictement supérieur à $b$ ?\\
\hline
a >= b & $a$ supérieur ou égal à $b$ ?\\
\hline
\end{tabular}
\end{center}

\begin{exemple}
\begin{console}
>>> 3 <= 3
True
>>> 5 > 10
False
\end{console}
\end{exemple}

\subsection{Opérateurs logiques : \og and \fg{}, \og or \fg }
\index{Mot-cle@Mot-clé!and}

\begin{enumerate}
\item Pour tester si deux conditions A et B sont vraies en même temps (A ET B), on utilise l'opérateur logique \og \texttt{and} \fg.

\begin{exemple}
\'Ecrivons une fonction qui retourne \texttt{True} si son argument est un nombre compris entre 3 et 10 :
\begin{python}
def fonction(x):
    if (x >= 3) and (x <=10):
        return True
    else:
        return False
\end{python}

que l'on peut aussi écrire:

\begin{python}
def fonction(x):
    return (x >= 3) and (x <=10)
\end{python}

\newpage

Cela donne par exemple:

\begin{console}
>>> fonction(5.5)
True
>>> fonction(1.2)
False
\end{console}

Notez que l'on peut aussi écrire:
\begin{python}
def fonction(x):
    return 3 <= x <= 10
\end{python}

Python arrive aussi à comprendre les encadrements!
\index{Encadrement}

\end{exemple}

\item Pour tester si l'une au moins des deux conditions est vraie, on utilise l'opérateur logique \og \texttt{or} \fg.
\index{Mot-cle@Mot-clé!or}

\begin{exemple}
\'Ecrivons une fonction qui retourne True si son argument est strictement inférieur à $-1$ ou supérieur ou égal à 7:

\begin{python}
def fonction(x):
    if (x < -1) or (x >= 7):
        return True
    else:
        return False
\end{python}

que l'on peut aussi écrire:

\begin{python}
def fonction(x):
    return (x < -1) or (x >= 7)
\end{python}

Cela donne par exemple:

\begin{console}
>>> fonction(2)
False
>>> Fonction(8)
True
\end{console}
\end{exemple}
\end{enumerate}

\newpage

\subsection{Mot-clé \og in \fg}
\index{Mot-cle@Mot-clé!in}
Le mot-clé \og in \fg{}  est puissant car il permet de vérifier si le contenu d'une variable est \textit{dans} une autre variable.

\medskip

\begin{exemple}
Testons si la chaîne de caractères \og ma \fg{} est contenu dans une autre:
\begin{python}
def verif(chaine):
    return "ma" in chaine
\end{python}
\newpage
qui est une manière concise de voir le programme suivant:
\begin{python}
def verif(chaine):
    if "ma" in chaine:
        return True
    else:
        return False
\end{python}
Cela donne:
\begin{console}
>>> verif("mathématiques")
True
>>> verif("cosinus")
False
\end{console}
\end{exemple}

\medskip

En mathématiques, ce mot-clé ne sera pas utilisé avec des chaînes de caractères, mais plutôt avec des nombres (pour vérifier par exemple s'ils sont dans une liste).

On verra des applications ultérieurement, quand on aura un peu plus de connaissances...

\section{Boucles}

\subsection{Boucles itératives : boucles \og for \fg{} }
\index{Mot-cle@Mot-clé!for}
\index{Boucles!itératives (for)}

Une boucle itérative est le fait d'exécuter une ou plusieurs instructions un certain nombre de fois, nombre que l'on connaît à l'avance.

Par exemple, si l'on souhaite calculer l'image de dix nombres par une fonction, on pourra utiliser une boucle itérative.

Une boucle itérative est de la forme : 
\begin{center}
\og Pour <variable> prenant ses valeurs de <valeur 1> à <valeur 2> \fg. 
\end{center}

\newpage

\subsubsection{La fonction \texttt{range}}
\index{range}

C'est une fonction native de Python, c'est-à-dire une fonction incluse dans le noyau: il n'est pas nécessaire de faire appel à un module externe pour pouvoir l'utiliser.

\medskip

Sa syntaxe est la suivante:

\begin{itemize}
\item \texttt{range(n)} représente les entiers de 0 à $n-1$ : il y a donc $n$ nombres.

\item \texttt{range(a,b)} représente les entiers de $a$ à $b-1$: il y a donc $b-a$ nombres.

\item \texttt{range(a,b,p)} représente les entiers de $a$ à $b-1$ par pas de $p$.

Par exemple, \texttt{range(5,50,10)} représente les nombres 5, 15, 25, 35 et 45.
\end{itemize}


\subsubsection{Syntaxe de la boucle \og for \fg}


\begin{attention}
La boucle \og for \fg{} est à utiliser quand on sait à l'avance combien de fois on souhaite\linebreak effectuer les instructions.
\end{attention}

On l'utilise donc pour \textit{parcourir} un \textit{itérable} (c'est-à-dire une liste ou une chaîne de caractères par exemple).

L'exemple suivant nous montre comment parcourir la liste \texttt{[1,2,3,4,5,6,7,8,9,10]} pour afficher tous les carrés de 1 à 10.


\begin{exemple}
\index{Mot-cle@Mot-clé!in}
On souhaite faire une boucle itérative pour afficher le carrés des nombres entiers de 1 à 10 :
\begin{console}
>>> for n in range(1,11):
		print(n**2)
1
4
9
16
25
36
49
64
81
100
\end{console}
\end{exemple}


\subsection{Boucles conditionnelles : boucles \og while \fg{} }
\index{Mot-cle@Mot-clé!while}
\index{Boucles!conditionnelles (while)}

Les boucles conditionnelles sont utilisées quand une ou plusieurs instructions doivent être\linebreak exécutées plusieurs fois, tant qu'une condition est vraie.

Une boucle conditionnelle est de la forme : 
\begin{center}
\og Tant que <condition> est vraie \fg{} 
\end{center}

\begin{exemple}
\begin{python}
i = 0
while (i*i < 15):
    i = i + 1

print(i)
\end{python}

Dans cet exemple, la condition porte sur une variable qui change de valeur à chaque itération (la variable \texttt{i}). L'instruction \og \texttt{i = i+1} \fg{} est exécutée tant que la condition \og $i^2 < 15$ \fg{}  est vraie.
\newpage
Quand on exécute le programme pas à pas, on met les valeurs successives des variables dans un tableau:

\begin{center}
\begin{tabular}{|>{\bfseries\arraybackslash}Sl|*6{Sc|}}
\hline
Condition \og $\pmb{i^2<15}$ \fg{}  & \diagbox{}{} & vraie & vraie & vraie & vraie & Fausse\\\hline
Valeur de $\pmb{i}$                 & 0            & 1     & 2     & 3     & 4&\diagbox{}{}\\\hline
Valeur de $\pmb{i^2}$                         & 0            & 1     & 4     & 9     & 16&\diagbox{}{}\\\hline
\end{tabular}
\end{center}
\end{exemple}

\begin{attention}
La boucle \og while \fg{} est à utiliser quand on ne  sait pas à l'avance combien d'itérations on souhaite effectuer.
\end{attention}
















\exercices %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section*{Tests}

\begin{exocor}{fonction divisible(n)}[1]
\'Ecrire une fonction \texttt{divisible(n)} qui admet pour argument un entier naturel $n$ et qui\linebreak affiche :
\begin{itemize}
\item \og divisible par 2 \fg{} si $n$ est pair,
\item \og divisible par 3 \fg{} si $n$ est divisible par 3,
\item \og divisible par 5 \fg{} si $n$ est divisible par 5,
\item \og divisible par 7 \fg{} si $n$ est divisible par 7.
\end{itemize}

\tcblower

\'Ecrivons une fonction \texttt{divisible(n)} qui admet pour argument un entier naturel $n$ et qui affiche :
\begin{itemize}
\item \og divisible par 2 \fg{} si $n$ est pair,
\item \og divisible par 3 \fg{} si $n$ est divisible par 3,
\item \og divisible par 5 \fg{} si $n$ est divisible par 5,
\item \og divisible par 7 \fg{} si $n$ est divisible par 7.
\end{itemize}

Dans un premier temps, on serait tentés d'écrire :

\begin{python}
def divisible(n):
    if n % 2 == 0:
        return "Divisible par 2"
    if n % 3 == 0:
        return "Divisible par 3"
    if n % 5 == 0:
        return "Divisible par 5"
    if n % 7 == 0:
        return "Divisible par 7"
\end{python}

mais cette fonction ne convient pas. En effet, un nombre $n$ peut être divisible par plusieurs autres nombres (par exemple, 21 est divisible par 3 et par 7). Or, quand on demande à une fonction de retourner un résultat, elle cesse de fonctionner une fois que le résultat est retourné.

Ainsi, dans ce code, pour $n=21$, la fonction retourne \og Divisible par 3 \fg, car 3 est le premier diviseur de 21, mais n'exécute pas les tests suivants; donc \og Divisible par 7 \fg{} ne s'affiche pas.

\medskip

Il faut donc préférer \textit{afficher} le texte plutôt que le \textit{retourner}:

\begin{python}
def divisible(n):
    if n % 2 == 0:
        print( "Divisible par 2" )
    if n % 3 == 0:
        print( "Divisible par 3" )
    if n % 5 == 0:
        print( "Divisible par 5" )
    if n % 7 == 0:
        print( "Divisible par 7" )
\end{python}

L'énoncé disait d'ailleurs que la fonction devait \textit{afficher} quelque chose et non \textit{retourner} quelque chose.
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{fonction aime(n)}[2]
\'Ecrire une fonction \texttt{aime(n)} qui admet pour argument un entier $n$ et qui retourne :
\begin{itemize}
\item \og Un peu \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 1,
\item \og Beaucoup \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 2,
\item \og Passionnément \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 3,
\item \og À la folie \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 4,
\item \og Pas du tout \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 0.
\end{itemize}

\tcblower

Une fonction \texttt{aime(n)} qui admet pour argument un entier $n$ et qui retourne :
\begin{itemize}
\item \og Un peu \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 1,
\item \og Beaucoup \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 2,
\item \og Passionnément \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 3,
\item \og À la folie \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 4,
\item \og Pas du tout \fg{} si le reste de la division euclidienne de $n$ par 5 est égal à 0.
\end{itemize}
est par exemple la suivante :
\begin{python}
def aime(n):
    if n % 5 == 1: return "Un peu"
    elif n % 5 == 2: return "Beaucoup"
    elif n % 5 == 3: return "Passionnément"
    elif n % 5 == 4: return "À la folie"
    else: return "Pas du tout"
\end{python}

\medskip

Notez qu'il n'est pas nécessaire d'aller à la ligne après un \og : \fg{}; en effet, quand il n'y a qu'une instruction, on peut rester sur la même ligne. Cela rend le code plus concis.

\medskip
 
Ici, nous ne sommes pas en mode \og console \fg{} mais en mode \og fenêtre \fg, fenêtre dans laquelle nous avons écrit notre programme. Quand on lance ce programme, il ne se passe rien. C'est en mode \og console \fg{} que l'on peut faire appel à cette fonction:
\begin{console}
>>> aime(3)
'Passionnément'
>>> aime(16)
'Un peu'
\end{console}

Depuis Python 3.10, on peut utiliser le mot-clé \og match \fg{}:
\begin{python}
def aime(n):
    match n%5:
        case 1: return "Un peu"
        case 2: return "Beaucoup"
        case 3: return "Passionnément"
        case 4: return "À la folie"
        case 0: return "Pas du tout"
\end{python}

\medskip

Notez ici que cette dernière proposition n'est pas plus courte que la première.

\vspace*{2cm}~
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{fonction inegalite\_triangulaire(a,b,c)}[1]
\'Ecrire une fonction \texttt{inegalite\_triangulaire(a,b,c)}, dont les arguments $a$, $b$ et $c$ sont rangés dans l'ordre croissant, qui retourne \og \texttt{True} \fg{} si un triangle de mesures $a$, $b$, $c$ est constructible, et \og \texttt{False} \fg{} dans le cas contraire.

On rappelle qu'un triangle de mesures $a$, $b$, $c$ (avec $a<b<c$) est constructible si $c < a+b$.

\tcblower

Voici une fonction \texttt{inegalite\_triangulaire(a,b,c)}, avec $a<b<c$, qui retourne \og \texttt{True} \fg{} si un triangle de mesures $a$, $b$, $c$ est constructible, et \og \texttt{False} \fg{} dans le cas contraire :

\begin{python}
def inegalite_triangulaire(a,b,c):
    if c < a + b:
        return True
    else:
        return False
\end{python}

que l'on peut aussi écrire :

\begin{python}
def inegalite_triangulaire(a,b,c):
    return c < a + b
\end{python}
\end{exocor}

\newpage

\section*{Boucles itératives}

\begin{exocor}{une somme}[1]
On considère la fonction \texttt{somme(n)} définie comme suit :
\begin{python}
def somme(n):
    S = 0 
    for k in range(1,n+1): 
        S = S + k
        
    return S
\end{python}

Compléter le tableau suivant pour $n=4$. Que fait cette fonction pour $n$ quelconque?

\begin{center}
\begin{tabular}{|Sl|*5{Sc|}}
\hline
Valeurs de $k$ & \diagbox{}{} &  &  &  & \\
\hline
Valeurs de $S$ & 0  &  &   &  &  \\
\hline
\end{tabular}
\end{center}
\vspace*{-2em}

\tcblower

Il s'agit ici d'inspecter la valeur des variables $k$ et $S$ à chaque itération, c'est-à-dire à chaque passage dans la boucle.

\begin{itemize}
\item Avant d'entrer dans la boucle, $S = 0$ et $k$ n'existe pas (d'où la case barrée pour $k$ en première colonne).
\item Quand on entre dans la boucle, $k=1$ et $S$ vaut le nombre qu'il y avait dans $S$ (c'est-à-dire 0) auquel on ajoute $k$. Donc $S = 0 + 1 = 1$.
\begin{center}
\begin{tabular}{|Sl|*5{Sc|}}
\hline
Valeurs de $k$ & \diagbox{}{} & 1 &  &  & \\
\hline
Valeurs de $S$ & 0  & 1 &   &  &  \\
\hline
\end{tabular}
\end{center}

\item Au deuxième passage dans la boucle, $k = 2$ et on affecte à $S$ la valeur 1 (ce que valait $S$ jusqu'à présent) plus 2 (la valeur de $k$). Donc $S = 1+2 = 3$.
\begin{center}
\begin{tabular}{|Sl|*5{Sc|}}
\hline
Valeurs de $k$ & \diagbox{}{} & 1 & 2 &  & \\
\hline
Valeurs de $S$ & 0  & 1 & 3  &  &  \\
\hline
\end{tabular}
\end{center}

\item Au passage suivant dans la boucle, $k=3$ et $S = 3+3=6$.
\begin{center}
\begin{tabular}{|Sl|*5{Sc|}}
\hline
Valeurs de $k$ & \diagbox{}{} & 1 & 2 & 3 & \\
\hline
Valeurs de $S$ & 0  & 1 & 3  & 6 &  \\
\hline
\end{tabular}
\end{center}

\item Nous sommes alors au niveau du dernier passage dans la boucle car maintenant,\linebreak $k=4$. $S$ vaut alors ce qu'il y avait dans $S$ (à savoir 6) auquel on ajoute la valeur de $k$ : $S = 6+4 = 10$.
\begin{center}
\begin{tabular}{|Sl|*5{Sc|}}
\hline
Valeurs de $k$ & \diagbox{}{} & 1 & 2 & 3 & 4 \\
\hline
Valeurs de $S$ & 0  & 1 & 3  & 6 & 10 \\
\hline
\end{tabular}
\end{center}
\end{itemize}

On constate alors que pour un $n$ quelconque, S est la somme de tous les entiers de 1 à $n$:
\[
S = 1+2+3+4+\cdots+ n.
\]
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{somme des inverses}[2]
Sur le modèle de l'exercice précédent, écrire une fonction \texttt{somme\_inverses(n)}, avec $n$ entier non nul, qui retourne la valeur de la somme:
\[
S = 1 + \frac{1}{2} + \frac{1}{3} + \frac{1}{4} + \cdots + \frac{1}{n-1} + \frac{1}{n}.
\]
\vspace*{-3em}

\tcblower

La structure de la fonction demandée est identique à celle de la fonction de l'exercice précédent. Seule la formule à l'intérieure de la boucle change :

\begin{python}
def somme_inverses(n):
    S = 0
    for k in range(1,n+1):
        S = S + 1/k  
    return S
\end{python}

À chaque itération (pour chaque passage dans la boucle), on ajoute à la valeur de $S$  l'inverse de $k$ quand $k$ varie de 1 à $n$.

$S$ vaut donc successivement : 0, $(0)+1$, $(0+1)+\frac{1}{2}$, $\left(0+1+\frac{1}{2}\right)+\frac{1}{3}$, etc.
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{tableau de valeurs d'une fonction}[1]
On considère la fonction $f\;:\;x\mapsto3x+5$.

Proposer une fonction \texttt{tableau\_valeurs(a,b)} qui affiche les images de tous les nombres entiers compris entre $a$ et $b$ (compris), où $a$ et $b$ doivent être entiers.

\vspace*{-1em}

\tcblower

Une fonction possible est la suivante :

\begin{python}
def tableau_valeurs(a,b):
    for x in range(a,b+1):
        print('f(',x,') = ',3*x+5)
\end{python}
qui donne en mode \og console \fg{}:
\begin{console}
>>> tableau_valeurs(-2,5)
f( -2 ) =  -1
f( -1 ) =  2
f( 0 ) =  5
f( 1 ) =  8
f( 2 ) =  11
f( 3 ) =  14
f( 4 ) =  17
f( 5 ) =  20
\end{console} 
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\enlargethispage*{4em}
\begin{exocor}{signe d'une fonction}[1]
Expliquer le programme suivant:
\begin{python}
def f(x):
    return x**2 - 6*x + 5
for x in range(10):
    if f(x) > 0:
        print('f(',x,') > 0')
    elif f(x) < 0:
        print('f(',x,') < 0')
    else:
        print('f(',x,') = 0')
\end{python}

\tcblower

Le programme est composé de deux parties.

\begin{itemize}
\item La première partie (lignes 1 et 2) définit une fonction \texttt{f(x)} qui correspond à la fonction mathématique $f\;:\;x\mapsto x^2-6x+5$. Cette fonction Python retourne donc l'image d'un nombre $x$ par la fonction $f$.

\item La seconde partie (lignes 4 à 10) est une boucle itérative sur la variable \texttt{x}, qui prend pour valeurs 0, 1, 2, 3, ... , 8 et 9.

À chaque itération (pour chaque passage dans la boucle), on effectue un test sur le signe de $f(x)$ et on affiche le résultat. 
\end{itemize}
Cela donne:

\bigskip

\begin{minipage}{0.25\linewidth}
\begin{console}
f( 0 ) > 0
f( 1 ) = 0
f( 2 ) < 0
\end{console}
\end{minipage}
\hfill
\begin{minipage}{0.25\linewidth}
\begin{console}
f( 3 ) < 0
f( 4 ) < 0
f( 5 ) = 0
\end{console}
\end{minipage}
\hfill
\begin{minipage}{0.25\linewidth}
\begin{console}
f( 6 ) > 0
f( 7 ) > 0
f( 8 ) > 0
f( 9 ) > 0
\end{console}
\end{minipage}

\bigskip

On peut alors déduire un tableau de signes de la fonction $f$ sur \intervFF{0}{9}:
\begin{center}
\begin{tikzpicture}
\node[inner sep = 0pt, outer sep = 0pt] (tab) {
\begin{tikzpicture}
\tkzTabInit[color,colorC=numpagecorrige!20,colorV=numpagecorrige!20,colorL=numpagecorrige!20]{$x$/0.5,$f(x)$/0.75}{0,1,5,9}
\tkzTabLine{,+,z,-,z,+}
\end{tikzpicture}};
\drawshadow{tab}{black}
\end{tikzpicture}
\end{center}
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{triangle d'étoiles}|1]
\'Ecrire une fonction Python \texttt{etoiles(n)} de sorte que l'on ait le résultat suivant:
\begin{console}
>>> etoiles(5)
*
**
***
****
*****
>>> etoiles(3)
*
**
***
\end{console}

\tcblower

Voici une première solution:
\begin{python}
def etoiles(n):
    for k in range(n+1):
        ligne = ''
        for _ in range(k): ligne = ligne + '*'
        print( ligne )
\end{python}
Dans cette solution, on utilise le fait que l'on peut \og ajouter \fg{} des chaînes de caractères.

Une autre solution est la suivante:
\begin{python}
def etoiles(n):
    for k in range(1,n+1):
        print( k * '*' )
\end{python}
Dans cette dernière solution, on utilise le fait que \texttt{k * '*'} affiche $k$ fois le symbole \og \texttt{*} \fg.  
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{une somme}[2]
\'Ecrire une fonction \texttt{somme(n)} qui renvoie, pour toute valeur de $n\geqslant1$, la valeur de la somme:
\[
S(n) = 1 + \frac{1}{1\times2} + \frac{1}{1\times2\times3} + \cdots + \frac{1}{1\times2\times3\times\cdots\times n}.
\]
Tester cette fonction et vérifier que l'on a:
\begin{console}
>>> somme(100)
1.7182818284590455
\end{console}

\tcblower

Voici une proposition de fonction:
\begin{python}
def somme(n):
    s = 0
    for k in range(1,n+1):
        produit = 1
        for p in range(1,k+1): produit = produit * p
        s = s + 1 / produit
    
    return s
\end{python}
%On commence par définir la somme qu'il faudra renvoyer: on lui attribue la valeur 0 au départ.
%
%\medskip
%
%Ensuite (ligne 3), on fait une boucle (de variable \texttt{k}) pour exécuter $n$ fois des instructions pour calculer chaque terme (car dans la somme demandée, il y a $n$ termes).
%
%\medskip
%
%Quand on entre dans cette boucle, on commence (ligne 4) par affecter la valeur \og 1 \fg{} à la variable \texttt{produit} (qui désignera le produit $1\times2\times\cdots\times k$, c'est-à-dire le dénominateur du\linebreak $k$-ième terme de la somme). Pour calculer ce produit, on fait une autre boucle (de variable~\texttt{p}, ligne 5); dans cette boucle, on prend la valeur stockée dans \texttt{produit} et on la multiplie par \texttt{p}, nombre variant de 1 à $k$. Au final, on obtient bien que \texttt{produit} contient le produit souhaité.
%
%\medskip
%
%Cette dernière boucle étant finie, on ajoute (ligne 7) à la valeur de \texttt{s} la fraction \texttt{1/produit}, c'est-à-dire la fraction $\dfrac{1}{1\times2\times\cdots\times k}$, qui est le $k$-ième terme de la somme demandée.
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


\newpage

\section*{Boucles conditionnelles}

\begin{exocor}{lecture d'un programme}[1]
On donne le programme suivant :
\begin{python}
a = 20
b = 4
while a*a + b*b > a * b + (a+1)*(b+1):
    a = a - 1
    b = b + 2
    
print ( a , b )
\end{python}

Compléter le tableau suivant en exécutant pas à pas ce programme:
\begin{center}
\begin{tabular}{|Sl|Sc|Sc|Sc}
\hline
Valeurs de $A = a^2+b^2$ : & \diagbox{}{} &  & $\ldots$ \\
\hline
Valeurs de $B = ab + (a+1)(b+1)$ : &\diagbox{}{} &  & $\ldots$ \\
\hline
Test $A > B$ : &\diagbox{}{} &  & $\ldots$ \\
\hline
Valeurs de $a$ : &20 & & $\ldots$ \\
\hline
Valeurs de $b$ :& 4 & & $\ldots$\\
\hline
\end{tabular}
\end{center}

Quelles sont les deux valeurs affichées par ce programme ?

\tcblower

Le tableau complété est le suivant :

\begin{center}
\begin{tabular}{|Sl|*6{Sc|}}
\hline
Valeurs de $A = a^2+b^2$ : & \diagbox{}{} & 416 & 397&388 &389& 400\\
\hline
Valeurs de $B = ab + (a+1)(b+1)$ : &\diagbox{}{} & 185 & 254 &315&368&413\\
\hline
Test $A > B$ : &\diagbox{}{} & vrai & vrai & vrai & vrai & faux\\
\hline
Valeurs de $a$ : &20 &19 & 18&17& 16 & \diagbox{}{} \\
\hline
Valeurs de $b$ :& 4 & 6& 8 &10& 12 & \diagbox{}{}\\
\hline
\end{tabular}
\end{center}

Les deux valeurs affichées sont donc : \og 16 \fg{} et \og 12 \fg.
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{argent de poche}[2]
Théo reçoit de sa grand-même 5 \euro. Celle-ci lui dit :

\og Je doublerai ton argent de poche chaque mois jusqu'à ce que la somme totale que je t'aurai donnée dépasse \numprint{1000} \euro. \fg{} 

\medskip

\'Ecrire un programme Python, en utilisant une boucle conditionnelle, permettant de trouver le nombre de mois pendant lesquels la grand-même de Théo compte lui donner de l'argent de poche, ainsi que la somme totale obtenue.

\tcblower

Pour résumer la situation,
\begin{itemize}
\item ce mois-ci, la grand-même de Théo lui donne 5 \euro;
\item le mois prochain, elle lui donnera le double donc 10 \euro. Il possèdera donc en tout\linebreak 15 \euro;
\item dans deux mois, elle lui donnera le double de ce qu'elle lui aura donné le mois précédent, donc 20 \euro; il possèdera donc en tout $15+20=35$ \euro.
\item etc.
\end{itemize}

Il faut donc ajouter le double de l'argent de poche reçu le mois précédent \textit{tant que} la somme ne dépasse pas \numprint{1000} \euro. On peut alors écrire le programme suivant :

\begin{python}
S = 0 # total de l'argent de poche reçu
a = 5 # argent de poche initialement reçu
n = 1 # nombre de mois

while S <= 1000:
    a = a * 2 # on double l'argent de poche
    S = S + a # on ajoute l'argent obtenu à la somme totale précédente
    n = n + 1 # on ajoute 1 mois
    
print(n,'mois,',S,'euros en tout.')
\end{python}
\begin{console}
8 mois, 1270 euros en tout.
\end{console}
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{le retour de la mamie}[2]
La grand-même de Théo est aussi celle de Théa, sa cousine. 

Théa est un peu plus joueuse que son cousin, et sa mamie le sait. C'est la raison pour laquelle elle donne à Théa 5 \euro{} d'argent de poche tout en lui disant :

\og Chaque mois, je multiplierai ce que je t'ai donné le mois précédent par 1,1 et j'ajouterai\linebreak 20 \euro, jusqu'à ce que la somme totale que je t'aurai donnée dépasse \numprint{1000} \euro.  \fg{} 

\medskip

\'Ecrire un programme Python, en utilisant une boucle conditionnelle, permettant de trouver le nombre de mois pendant lesquels la grand-même de Théa compte lui donner de l'argent de poche, ainsi que la somme totale obtenue.

\vspace*{-1em}

\tcblower

Pour résumer la situation,
\begin{itemize}
\item ce mois-ci, la grand-même de Théa lui donne 5 \euro;
\item le mois prochain, elle lui donnera $1,1\times5+10=25,5$ \euro. Théa possèdera donc en tout 30,5 \euro;
\newpage
\item dans deux mois, elle lui donnera $1,1\times 25,5+2=48,05$ \euro; Théa possèdera donc en tout $30,5+48,05=78,55$ \euro.
\item etc.
\end{itemize}

Un programme possible est donc le suivant :

\begin{python}
S = 0 # total de l'argent de poche reçu
a = 5.0 # argent de poche initialement reçu
n = 1 # nombre de mois

while S <= 1000:
    a = a * 1.1 + 20
    S = S + a
    n = n + 1
    
print(n,'mois,',S,'euros en tout.')
\end{python}
\begin{console}
10 mois, 1262.1720432050001 euros en tout.
\end{console}

\end{exocor}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{carré d'étoiles}[3]
\'Ecrire une fonction Python \texttt{carre(n)} de sorte que l'on ait:
\begin{console}
>>> carre(3)
***
* *
***
>>> carre(5)
*****
*   *
*   *
*   *
*****
\end{console}

\tcblower

Voici une fonction possible :
\begin{python}
def carre(n):
    for y in range(1,n+1):
        if y == 1 or y == n:
            print( '*' * n )
        else:
            motif = '*' + ' '*(n-2) + '*'
            print( motif )
\end{python}
Sur la première et dernière ligne, on souhaite écrire un motif rempli d'étoiles.

Entre ces lignes, il faut que le motif soit constitué d'une étoile, puis d'une espace vide sur $(n-2)$ caractères, puis terminer avec une étoile.

La ligne 2 définit une boucle itérative sur le numéro de ligne (que j'ai désigné par la variable \texttt{y}): je vais de la ligne 1 à la ligne $n$.

Ensuite, j'effectue un test pour savoir si la ligne est la première ou la dernière (ligne 3), auquel cas j'affiche $n$ étoiles). Dans le cas contraire, je construis le motif comme précédemment défini, et je l'affiche.
\end{exocor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{exocor}{triangle d'étoiles}[3]
\'Ecrire une fonction Python \texttt{triangle(n)} de sorte que l'on ait:
\begin{console}
>>> triangle(4)
   *   
  * *  
 * * * 
* * * *
>>> triangle(2)
 * 
* *
\end{console}

\textbf{Aide:} on pourra voir la disposition des étoiles comme ci-dessous:

\begin{center}
\begin{tabular}{|Sc|Sc|Sc|Sc|Sc|}
\hline
&& * && \\
\hline
&* &  & *&\\
\hline
* &  & * &  & *\\
\hline
\end{tabular}
\end{center}

\tcblower

C'est un exercice plutôt compliqué car il y a du travail mathématique à faire avant le travail de programmation.

Il faut observer ce qui se passe ligne par ligne.

Si $n=2$, il faut deux lignes comme ceci :
\begin{center}
\begin{tabular}{|Sc|Sc|Sc|}
\hline
& * & \\
\hline
* &  & *\\
\hline
\end{tabular}

\medskip

Le nombre de colonnes est $c = 3 = 2\times2 - 1$.
\end{center}

\newpage

Si $n=3$, il faut afficher:

\begin{center}
\begin{tabular}{|Sc|Sc|Sc|Sc|Sc|}
\hline
&& * && \\
\hline
&* &  & *&\\
\hline
* &  & * &  & *\\
\hline
\end{tabular}

\medskip

Le nombre de colonnes est $c = 5 = 2\times3 - 1$.
\end{center}

On peut alors conjecturer que le nombre de colonnes nécessaires est :
\[
c = 2n - 1.
\]
Le motif central est \og * \fg{} sur la première ligne, et pour obtenir le motif central de la ligne suivante, on y \og ajoute \fg{} le motif \og \tikz\draw(0,0.1)--(0,0)--(0.25,0)--(0.25,0.1); *\fg{} (une espace vide suivie d'une étoile). On peut donc imaginer une variable \texttt{motif\_central} se formant en prenant ce qu'il y avait avant et en lui ajoutant \texttt{' *'}.

Ensuite, il faut penser aux espaces vides à droite et à gauche qui tiennent sur $\frac{c-m}{2}$ colonnes, où $m$ est la longueur du motif central.

Au final, une fonction possible est la suivante:
\begin{python}
def triangle(n):
    colonnes = 2 * n - 1
    for ligne in range(1,n+1):
        if ligne == 1:
            motif_central = '*'
        else:
            motif_central = motif_central + ' *'
        
        vide = (colonnes - len( motif_central)) // 2
        motif = vide * ' ' + motif_central + vide * ' '
        print( motif )
\end{python} 
Bien entendu, cette solution n'est pas unique.
\end{exocor}
\corriges
