TD 2 : affectations, instructions conditionnelles

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;
  1. 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 et n2.

    END SOLUTION

  2. Exécutez le fragment de programme pas à pas avec comme valeurs initiales 5 et 7 pour les variables n1 et n2 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

  3. 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.

  1. Spécifiez et écrivez un algorithme max2 qui, étant donnés deux variables réelles a et b (qu’on suppose déjà déclarées et initialisées), calcule le plus grand des deux et met le résultat dans une variable m.

    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

  2. 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 exemple max2(7,5).

    BEGIN SOLUTION

    float max2(float a, float b){
        if (a < b) {
            return b;
        } else {
            return a;
        }
    }
    

    END SOLUTION

  3. 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 fonction max2(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

  4. \(\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

  5. 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

  6. \(\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 et max3 commen renvoyant un float et non un int, 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.

  1. 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

  2. Écrivez un programme pour résoudre le problème. On pourra supposer que les variables prix et somme contiennent respectivement le prix et la somme donnée par le client. À la fin du programme, la variable npieces50 devra contenir le nombre de pièces de cinquante centimes à rendre, et de même pour les variables npieces20, npieces10 et npieces5.

    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

  3. \(\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.

  1. 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 et choix2 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 variable gagnant 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

  2. 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

  3. 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

  4. \(\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.