TD 2 : affectations, instructions conditionnelles#
Notes aux enseignants
À faire
Mettre à jour chaque année selon que les polys ont déjà été imprimés / distribués ou pas.
Indiquer à la reprographie d’imprimer la feuille de résumé séparément
Faire passer le message que le meilleur moyen de se préparer aux partiels/examens est de faire sérieusement par soi-même les exercices de TD (et d’écouter attentivement la correction).
Rappeler qu’ils doivent relire le cours avant chaque TD et amener leur poly en TD/TP. Ceux qui ne l’ont pas encore doivent le chercher au secrétariat d’ici le prochain cours.
Leur dire de conserver le résumé de syntaxe précieusement; ce sera le seul document autorisé au partiel et à l’examen; ils pourront le compléter au dos, à condition que ce soit écrit de leur main, de façon manuscrite: écrire cette fiche d’aide mémoire est une bonne manière d’apprendre et mémoriser le cours. Leur recommander aussi pour gagner du temps en TP de se faire une fiche mémoire sur les aspects techniques: commandes shell usuelles, …
Corriger ou faire corriger au tableau au moins les exercices 1, 2, 3.1 et 3.2, pour qu’ils aient des exemples écrits proprement. Bien expliquer ce que l’on entend par «spécifier», «implanter», …
Notes aux enseignants
Dans l’exercice suivant, insistez sur le tableau d’exécution pas à pas. C’est important pour les élèves débutants en informatique qui en général ne savent pas comment faire. Même les non débutants ne savent pas forcément le présenter bien proprement. Leur dire que ce sera important lorsqu’ils essaieront de débugger des programmes compliqués. Ne pas hésiter à refaire un tableau d’exécution pas à pas avec la version corrigée de la question 3 si vous sentez que c’est utile pour votre groupe.
Certains étudiants proposent de faire l’échange via une succession de soustractions et additions. Leur indiquer que c’est une solution astucieuse, mais qui ne se généralise pas à des valeurs ne permettant pas l’arithmétique (booléens, …).
Exercice 1 : affectations
Voici un fragment de programme Échange
. On suppose que les variables
entières n1
et n2
ont été préalablement déclarées et initialisées :
n1 = n2;
n2 = n1;
En première lecture, que fait ce fragment de programme?
BEGIN SOLUTION
D’après son nom, le fragment de programme devrait échanger les valeurs de
n1
etn2
.END SOLUTION
Exécutez le fragment de programme pas à pas avec comme valeurs initiales
5
et7
pour les variablesn1
etn2
respectivement. Obtient-on à la fin les valeurs attendues dans ces variables ?BEGIN SOLUTION
Exécution pas à pas : on note dans un tableau les valeurs des variables à chaque étape :
instruction
n1
n2
7
4
n1 = n2;
4
4
n2 = n1;
4
4
On n’obtient pas les valeurs que l’on souhaiterait.
END SOLUTION
Modifiez le programme pour qu’il réponde à ce qui est attendu. Seules des déclarations de variables et des affectations sont nécessaires pour cela.
BEGIN SOLUTION
temporaire = n2; n2 = n1; n1 = temporaire;
Exécution pas à pas :
instruction
n1
n2
temporaire
int n1, n2, temporaire;
?
?
?
n1 = 7;
7
?
?
n2 = 4;
7
4
?
temporaire = n2;
7
4
4
n2 = n1;
7
7
4
n1 = temporaire;
4
7
4
Cette fois on a bien échangé les valeurs de n1 et n2.
END SOLUTION
Notes aux enseignants
Le if
a été vu en cours, ce qui n’empêche pas de se référer à la
syntaxe en annexe du TD. Pour %
pointer sur la partie du cours d’info
évoquée dans la correction. Ne pas hésiter à faire un très rapide
rappel sur la division euclidienne (une partie des élèves a des
difficultés en mathématiques, et à vrai dire ce n’est peut-être même
plus au programme de terminale…). En profiter pour insister sur la
différence entre =
et ==
.
Exercice 2 : conditionnelles
En relisant votre cours après l’amphi, vous avez appris les opérations
sur les entiers ainsi que les opérations booléennes. Cela vous sera
utile dans cet exercice. On suppose que l’on a déjà déclaré et
initialisé une variable n
de type entier. On veut diviser \(n\) par
\(2\) s’il est pair et lui enlever \(1\) s’il est impair. Écrivez les
quelques lignes d’instructions correspondantes.
BEGIN SOLUTION
Rappel
En C++
, si n
et k
sont des entiers, alors n/k
est le quotient
de la division euclidienne de n
par k
, et n%k
est le reste de la
division euclidienne de n
par k
(voir le
cours).
Les instructions demandées sont donc :
if (n % 2 == 0) {
n = n/2;
} else {
n = n-1;
}
END SOLUTION
Notes aux enseignants
Exemple typique et intéressant de code écrit par les étudiants :
int n,k;
if (n = 2*k) {
n/2;
} else {
n-1;
}
On voit ici de nombreuses erreurs classiques de débutants en programmation :
Redéclarer une entrée du problème (
int n
).Utiliser une variable non initialisée (
k
).Confondre
=
et==
.Ne rien faire d’une expression (
n/2
seul sur sa ligne).
Notes aux enseignants
Les fonctions n’ont été qu’aperçues en cours. L’exercice suivant sera leur premier contact avec elles. Commencer à décrire les entrées et sorties de manière informelle, puis donner la réponse sous forme de fonction. Ils manipuleront d’autres exemples de fonctions en TP. Leur dire qu’ils auront une introduction détaillée sur les fonctions lors de l’amphi de la semaine 4.
Les questions 2 et suivantes peuvent être corrigées sans ou avec la fonction
max2
de la question précédente. Les deux façons de faire sont intéressantes : la première oblige à réfléchir à des conditionnelles propres (beaucoup d’élèves se trompent et écrivent des programmes qui ne sont pas justes pour toutes les valeurs de a,b,c). La seconde est importante pour donner une première intuition de la notion de valeur de retour et d’appel de fonction, pour montrer l’intérêt de réutiliser. Prenez le temps de faire les deux versions.
Exercice 3 : conditionnelles, fonctions
Dans cet exercice (et les suivants), vous préciserez le nom, l’entrée et la sortie de vos programmes comme dans l’exemple suivant :
// Programme produit
// Entrée: deux entiers a et b de type int
// Sortie: le produit de a et b stocké dans une variable p
int p;
p = a*b;
Si vous vous sentez à l’aise, ou lorsque cela est demandé, mettez votre programme sous la forme d’une fonction :
int produit(int a, int b) {
return a * b;
}
Lors de la fin d’un semestre dans une Université X, les enseignants sont amenés à calculer la moyenne générale des notes de physique et de mathématiques selon une règle précise : la meilleure note des trois épreuves de mathématiques est comptée coefficient 3, et la meilleure note des deux épreuves de physique est comptée coefficient 2; les autres notes ne comptent pas.
Un enseignant est chargé de concevoir un algorithme prenant en entrée les trois notes de mathématiques et les deux notes de physique, et donnant la moyenne générale suivant la règle énoncée ci-dessus.
Spécifiez et écrivez un algorithme
max2
qui, étant donnés deux variables réellesa
etb
(qu’on suppose déjà déclarées et initialisées), calcule le plus grand des deux et met le résultat dans une variablem
.BEGIN SOLUTION
// Programme max2 // Entrées: deux nombres réels a et b // Sortie: le maximum de a et b float m; if (a < b) { m = b; } else { m = a; }
END SOLUTION
Transformez cet algorithme en une fonction nommée
max2
pour pouvoir par la suite calculer le maximum de deux nombres avec un appel à la fonction, par exemplemax2(7,5)
.BEGIN SOLUTION
float max2(float a, float b){ if (a < b) { return b; } else { return a; } }
END SOLUTION
De même, étant donnés trois nombres réels, donnez un algorithme calculant le plus grand des trois (dans une variable
m
). On pourra utiliser la fonctionmax2(a,b)
.BEGIN SOLUTION
// Programme max3 // Entrées: trois nombres réels a, b et c // Sortie: le maximum de a, b et c float m; if (a <= c and b <= c) { m = c; } else if (a <= b) { // ici, on sait que c n'est pas le maximum m = b; } else { // ici, on sait que c n'est pas le maximum et a > b m = a; }
Variante en utilisant la fonction
max2
:// Entrées: trois nombres réels a, b et c // Sortie: le maximum de a, b et c float m = max2( a, max2(b, c) );
END SOLUTION
\(\clubsuit\) Transformez cet algorithme en fonction.
BEGIN SOLUTION
float max3(float a, float b, float c) { if (a <= c and b <= c) { return c; } else if (a <= b) { return b; } else { return a; } }
Variante en utilisant la fonction
max2
:float max3(float a, float b, float c) { return max2( a, max2(b, c) ); }
END SOLUTION
Spécifiez et donnez un algorithme qui prend en entrée trois notes de mathématiques puis deux notes de physique, et calcule la moyenne selon la règle spécifiée.
BEGIN SOLUTION
// Programme moyenne // Entrées: m1, m2, m3: les notes de math, // p1, p2: les notes de physique // Sortie: la moyenne float moyenne = (max3(m1, m2, m3) * 3 + max2(p1, p2) * 2) / 5;
END SOLUTION
\(\clubsuit\) Transformez cet algorithme en fonction.
BEGIN SOLUTION
float moyenne(float m1, float m2, float m3, float p1, float p2){ return (max3(m1, m2, m3) * 3 + max2(p1, p2) * 2) / 5; }
Si on a déclaré les fonctions
max2
etmax3
commen renvoyant unfloat
et non unint
, il faut écrire/5.0
ci-dessus, sinon on a une division entière (quotient) et pas un calcul exact de la moyenne.END SOLUTION
Exercice 4 : rendu de monnaie
On considère une machine qui distribue des sucreries. Le problème consiste à écrire le programme qu’elle exécute pour rendre la monnaie sur une somme, à l’aide de pièces de 50 centimes, 20 centimes, 10 centimes et 5 centimes d’euro, de façon à minimiser le nombre de pièces rendues sachant que l’on connaît le prix et la somme donnée par le client. On suppose que les sommes sont données en centimes d’euro, qu’il n’y a pas de risque de pénurie de pièces de monnaie, et que les prix sont un multiple de 5 centimes. Par exemple si le prix à payer est de 110 centimes et que le client a donné 200 centimes, il faut lui rendre 1 pièce de 50 centimes et 2 pièces de 20 centimes.
Quelles sont les entrées / sorties du problème ?
BEGIN SOLUTION
// Entrées : la somme due (prix) et la somme donnée (somme), // des entiers divisibles par 5 // Sorties : le nombre de pièces de 50, 20, 10 et 5 centimes // à rendre (npieces50, npieces20, npieces10, npieces5).
END SOLUTION
Écrivez un programme pour résoudre le problème. On pourra supposer que les variables
prix
etsomme
contiennent respectivement le prix et la somme donnée par le client. À la fin du programme, la variablenpieces50
devra contenir le nombre de pièces de cinquante centimes à rendre, et de même pour les variablesnpieces20
,npieces10
etnpieces5
.Note : avec ce que vous avez appris, vous ne pouvez pas encore écrire une fonction pour ce problème (pourquoi?).
BEGIN SOLUTION
int a_rendre; a_rendre = somme - prix; npieces50 = a_rendre / 50; a_rendre = a_rendre % 50; npieces20 = a_rendre / 20; a_rendre = a_rendre % 20; npieces10 = a_rendre / 10; a_rendre = a_rendre % 10; npieces5 = a_rendre / 5;
On remarque qu’on n’a pas calculé le reste par 5 : on sait qu’il est nul car d’après l’énoncé, les prix sont multiples de 5.
END SOLUTION
\(\clubsuit\) Comment gérer un nombre limité de pièces en réserve dans la caisse de la machine?
Exercice 5 : \(\clubsuit\) pierre-feuille-ciseaux
Héloïse et Gabriel veulent jouer à pierre-feuille-ciseaux, mais, têtes en l’air, ils ne se souviennent jamais de qui bat quoi.
On numérote les joueurs par \(1\) et \(2\), et on représente un choix par un entier: \(1\) pour une pierre, \(2\) pour une feuille, et \(3\) pour les ciseaux. On suppose que les variables
choix1
etchoix2
ont été déclarées et initialisées respectivement avec les choix du joueur \(1\) et \(2\). Écrivez un programme dont la sortie, stockée dans une variablegagnant
contienne le numéro du joueur gagnant (ou zéro si égalité).BEGIN SOLUTION
// Entrées : choix1 et choix2 int gagnant; if (choix1 == choix2) { gagnant = 0; } else if ( (choix1 == 1 and choix2 == 2) or (choix1 == 2 and choix2 == 3) or (choix1 == 3 and choix2 == 1) ) { gagnant = 2; } else { gagnant = 1; }
END SOLUTION
Transformez votre programme sous forme d’une fonction.
BEGIN SOLUTION
int gagnant (int c1, int c2) { if (c1 == c2) { return 0; } else if ( (c1 == 1 and c2 == 2) or (c1 == 2 and c2 == 3) or (c1 == 3 and c2 == 1) ) { return 2; } else { return 1; } }
END SOLUTION
Même chose en représentant un choix par un caractère (type
char
): “p” pour pierre, “f” pour feuille, “c” pour ciseaux.BEGIN SOLUTION
int gagnant_char (char c1, char c2) { if (c1 == c2) { return 0; } else if ( (c1 == 'p' and c2 == 'f') or (c1 == 'f' and c2 == 'c') or (c1 == 'c' and c2 == 'p') ) { return 2; } else { return 1; } }
END SOLUTION
\(\clubsuit\clubsuit\) Même chose en utilisant un type
enum
(hors programme).BEGIN SOLUTION
enum Choix {pierre, feuille, ciseaux}; int gagnant_enum (Choix c1, Choix c2) { if (c1 == c2) { return 0; } else if ( (c1 == pierre and c2 == feuille) or (c1 == feuille and c2 == ciseaux) or (c1 == ciseaux and c2 == pierre) ) { return 2; } else { return 1; } }
END SOLUTION
Vous avez fini la feuille? Regardez les exercices du Projet Euler[1], une série de défis, de difficulté croissante, mêlant mathématiques, algorithmique, et programmation. Chaque problème possède une unique solution qu’il s’agit de découvrir par soi-même. Le Problème 19 aborde les thématiques de cette semaine.