Objectifs du cours d aujourd hui Informatique I : Cours d introduction à l informatique et à la programmation Révisions de la 1 re partie Jamila Sam Haroud Laboratoire d Intelligence Artificielle Faculté I&C Nous voici donc arrivés au terme de cette première partie du cours. L objectif de ces quelques transparents est de vous rafraîchir la mémoire en rappelant les principaux points. Nous avons abordé : 1. Introduction à l Informatique 2. Bases de programmation 3. Approfondissements : bases d algorithmique et de structures de données On va se focaliser ici sur les rappels de programmation. Informatique I Cours 13 : Révisions 1 Informatique I Cours 13 : Révisions 2 Qu avons nous vu en programmation? programmer c est décomposer une tâche à automatiser en une séquence d instructions (traitements) et des données Algorithme Traitements S.D.A. Données Variables Expressions & Opérateurs Structures de contrôle Fonctions Portée Chaînes de caractères Tableaux statiques Tableaux dynamiques Structures Pointeurs Entrées/Sorties il faut que vous soyez au clair sur chacune de ces notions : 1. qu est-ce que c est? 2. à quoi ça sert? 3. comment ça s utilise? Informatique I Cours 13 : Révisions 3 FONDAMENTAUX 1. déclarez avant d utiliser variables int i ; vector<double> v ; fonctions prototype double sin(double x) ; bool cherche_valeur(listechainee l, Valeur v) ; 2. modularisez / décomposez / pensez «atomique» (a) conception (qu est ce qu on veut?) (b) implémentation (comment ça se réalise?) (c) syntaxe (comment ça s écrit?) (d) tests (où sont mes fautes, comment pourrais-je les tester?) Informatique I Cours 13 : Révisions 4
"Modularisez" : exemple Exemple : affichage d une tour de Hanoï Je veux afficher le jeu c est-à-dire afficher 3 "piliers" c est-à-dire afficher de haut en bas soit vide soit un disque = c est-à-dire savoir afficher un disque afficher un disque c est-à-dire afficher n caractères similaires Informatique I Cours 13 : Révisions 5 Exemple d approche modulaire (2) Supposons qu on ait déjà les objets de base : // un disque sera représenté simplement par sa taille (rayon) typedef unsigned int Disque; // 0 signifiant pas de disque Disque const PAS DE DISQUE(0); typedef Disque Pilier[N]; // un pilier est une pile d au plus N d typedef Pilier Jeu[3]; // le jeu est constitué de 3 piliers On fait alors alors exactement ce qui est écrit plus haut : on commence par spécifier tour à tour ces fonctions void affiche(jeu jeu); void affiche(disque d); void affiche(char c, unsigned int n = 1); puis on écrit simplement ce qu on a conçu. C est simple car on a décomposé la tâche. Sinon c est beaucoup plus compliqué = on peut plus facilement faire des erreurs Informatique I Cours 13 : Révisions 6 Exemple d approche modulaire (3) afficher le jeu = afficher 3 "piliers" = afficher de haut en bas les 3 disques /* -------------------------------------------------------------- * Affiche un jeu * Entrée : le jeu à afficher * -------------------------------------------------------------- */ void affiche(jeu jeu) for (unsigned int i(0); i < N; ++i) // pour toutes les lignes affiche(jeu[0][i]); // affichage d un disque du premier pilier affiche(jeu[1][i]); // second affiche(jeu[2][i]); // troisième cout << endl; Exemple d approche modulaire (4) Afficher un disque soit vide soit n caractères identiques (n = taille du disque) /* -------------------------------------------------------------- * Affiche un disque * Entrée : le disque à afficher * -------------------------------------------------------------- */ void affiche(disque d) if (d == PAS DE DISQUE) affiche(, N-1); cout << ; affiche(, N); else affiche(, N-d); affiche( -, 2*d-1); affiche(, N-d+1); Informatique I Cours 13 : Révisions 7 Informatique I Cours 13 : Révisions 8
Exemple d approche modulaire (5) atome de notre décomposition : afficher n caractères /* -------------------------------------------------------------- * Affiche n fois un caractère * Entrée : le caractère à afficher et le nombre de fois * -------------------------------------------------------------- */ void affiche(char c, unsigned int n) for (unsigned int i(0); i < n; ++i) cout << c; Proposition de méthode de révision prendre le tableau synthétique du transparent 3 prendre les fiches résumé et pour chacun des points, se demander si on sait : de quoi ça parle? ce que ça veut dire? l utiliser? se focaliser sur les concepts. Les détails de syntaxe (comment ça s écrit) peuvent être ensuite rapidement retrouvés dans la fiche résumé, si on sait ce qu on cherche (c est-à-dire si on a le concept) Informatique I Cours 13 : Révisions 9 Informatique I Cours 13 : Révisions 10 Un exemple concret Positionnement du problème Supposons qu on nous demande de réaliser un programme qui permette d effectuer la division de polynômes Par exemple, la division de 5X 3 + 4X 2 2X + 3 par 2X 2 + 2X + 1 a pour quotient 2.5X 4.5 et pour reste 9.5X + 7.5 : 5X 3 + 4X 2 2X + 3 = ( 2.5X 4.5) ( 2X 2 + 2X + 1) + 9.5X + 7.5 On nous demande : implémenter la division de polynômes division algorithme fonction polynôme données nouveau type d où déjà : typedef???? Polynome ;??? division(???) ; COMMENT FAIRE? Informatique I Cours 13 : Révisions 11 Informatique I Cours 13 : Révisions 12
Structures de données Commençons par les données : c est quoi un polynôme? n + 1 coefficients, si n est le degré du polynôme. Choix de l implémentation? tableau (des coefficients) question : statique ou dynamique au choix prenons dynamique ici. (faîtes le avec des tableaux statiques en exercice) d où : typedef vector<double> Polynome ; Algorithme On passe ensuite à l algorithme. Entrées? 2 polynômes (numérateur et dénominateur)???? division(polynome numerateur, Polynome denominateur) ; Sorties? 2 (autres) polynômes (quotient et reste) Ahhh! comment faire pour avoir 2 sorties? 2 solutions : 1. soit créer une structure regroupant les deux solutions et renvoyer la structure 2. soit les passer en argument de la fonction. Mais comme il seront modifiés (puisque ce sont des résultats), il faut impérativement les passer par référence. Prenons ici le second choix : Polynome& quotient, Polynome& reste) ; Informatique I Cours 13 : Révisions 13 Informatique I Cours 13 : Révisions 14 Pause On arrive donc à (sans les commentaires!) : #include <iostream> #include <vector> using namespace std; typedef vector<double> Polynome; Polynome& quotient, Polynome& reste); int main() return 0; Polynome& quotient, Polynome& reste) Informatique I Cours 13 : Révisions 15 Et l algorithme lui-même? quotient 0 Algorithme (suite) reste numérateur δ degré du reste - degré du dénominateur Tant que δ 0 et reste 0 a coef. de plus haut degré du reste coef. de plus haut degré du dénominateur quotient quotient + a X δ reste reste a X δ dénominateur δ degré du reste - degré du dénominateur Implémentons maintenant l algorithme. C est ici où il faut utiliser à fond l approche modulaire et écrire l algorithme tel quel sans pour l instant se poser de question sur les sous-tâches à effectuer (les "modules") : Informatique I Cours 13 : Révisions 16
Implémentation de l algorithme Polynome& quotient, Polynome& reste) quotient = POLYNOME NUL; reste = num; int dq(degre(reste) - degre(denominateur)); while ((dq >= 0) && (reste!= POLYNOME NUL)) met coef(reste[degre(reste)] / denominateur[degre(denominateur)], dq, quotient); soustrait(reste, monomemult(quotient[dq], dq, denominateur)); dq = degre(reste) - degre(denominateur)); Approche modulaire Et seulement maintenant on se préoccupe des choses non encore définies. Qu est ce qui n est pas définit? Polynome& quotien, Polynome& reste) quotien = POLYNOME NUL; reste = num; int dq(degre(reste) - degre(denominateur)); while ((dq >= 0) && (reste!= POLYNOME NUL)) met coef(reste[degre(reste)] / denominateur[degre(denominateur)], dq, quotien); soustrait(reste, monome mult(quotien[dq], dq, denominateur)); dq = degre(reste) - degre(denominateur); Prenons les dans l ordre. Informatique I Cours 13 : Révisions 17 Informatique I Cours 13 : Révisions 18 Descente dans les modules Implémentation modulaire (suite) POLYNOME_NUL : il suffit d écrire ce qu est pour nous le polynôme nul un vector à 1 seul coefficient qui vaut 0 : Polynome const POLYNOME_NUL(1,0) ; void met_coef(double a, int n, Polynome& p) ; À quoi sert cette fonction? à mettre le coefficient a au degré n du polynôme p Heu... mais ne pourrait-on pas simplement écrire p[n]=a? void met coef(double a, int n, Polynome& p) while (degre(p) < n) p.push back(0.0); p[n] = a; int degre(polynome p) ; renvoit le degré du polynôme. Pas de difficulté particulière ici : int degre(polynome p) return p.size()-1 ; avec les tableaux statiques : oui (si n est compatible avec la taille max. des tableaux) mais avec les tableaux dynamique : non! car on n est pas sûr que la taille de p soit suffisante ( ) pour y mettre un élément en place n C est justement ce que cette fonction doit faire! Informatique I Cours 13 : Révisions 19 Informatique I Cours 13 : Révisions 20
Implémentation modulaire (suite) void soustrait(polynome& p, Polynome q) ; doit implémenter p = p - q pour les Polynomes Il s agit donc grosso-modo de soustraire les coefficients de q aux coefficients de p. Mais il faut faire attention au degrés des polynômes : être sûr que l on a effectivement des coefficients avant des les manipuler (comme pour met_coef) En remarquant qu après cette opération le degré de p sera au moins égal à celui de q, il suffit de faire while (degre(p) < degre(q)) p.push_back(0) ; qui ajoute les 0 nécessaires en "haut" du polynôme p Implémentation modulaire (suite) Par ailleurs, dans un polynôme, le coefficient de plus haut degré est par convention toujours non nul. On n écrit pas 0X 2 + 3X + 2 mais 3X + 2. Or ce genre de choses (coef. nul au plus haut degré) peut se produire lors d une soustraction. Il faut donc s assurer d enlever ces 0 inutiles. void simplifie(polynome& p) ; D où finalement le code : void soustrait(polynome& a, const Polynome& b) // a = a-b // garantit que le degré de a (résultat) est au moins le while (degre(a) < degre(b)) a.push back(0); for (int i(0); i <= degre(b); ++i) a[i] -= b[i]; Informatique I Cours 13 : Révisions 21 // garantit la bonne forme du polynome a simplifie(a); Informatique I Cours 13 : Révisions 22 Implémentation modulaire (suite) Implémentation modulaire (suite) void simplifie(polynome& p) ; garantit donc qu un polynôme est bien formé (pas de coefficient de plus haut degré nul) void simplifie(polynome& p) while ((!p.empty()) && (p[degre(p)] == 0.0)) p.pop back(); if (p.empty()) p.push back(0.0); Enfin pour finir, la fonction Polynome monome_mult(double a, int deg, Polynome p) ; multiple p par le monôme ax deg et retourne le résultat Polynome monomemult(double scal, int n, Polynome const& p) Polynome resultat(0); // prévoit la place pour augmenter de n le degré de p for (int i(0); i < n; ++i) resultat.push back(0); for (int i(0); i <= degre(p); ++i) resultat.push back(p[i] * scal); return resultat; Informatique I Cours 13 : Révisions 23 Informatique I Cours 13 : Révisions 24
Un exemple concret (ouf!) Bon je vais m arrêter là, car le plus dur est fait. Il reste à utiliser nos fonctions, par exemple en demandant à l utilisateur de rentrer des polynômes, Il faudrait aussi afficher les résultats. Je vous laisse faire cela en guise d exercice. Pour résumé, nous sommes arrivé au code suivant : #include <iostream> #include <vector> using namespace std; typedef vector<double> Polynome; Polynome const POLYNOME NUL(1,0); int degre(polynome p); Polynome monome mult(double coef, int deg, Polynome p); void simplifie(polynome& p); void met coef(double a, int n, Polynome& p); void soustrait(polynome& p, Polynome q); Polynome& quotient, Polynome& reste); int main() return 0; Informatique I Cours 13 : Révisions 25 void met coef(double a, int n, Polynome& p) while (degre(p) < n) p.push back(0.0); p[n] = a; Informatique I Cours 13 : Révisions 26 int degre(polynome p) return p.size()-1; void soustrait(polynome& a, Polynome const& b) // a = a-b // garantit que le degré de a (résultat) est au moins le degré while (degre(a) < degre(b)) a.push back(0); void simplifie(polynome& p) while ((!p.empty()) && (p[degre(p)] == 0.0)) p.pop back(); if (p.empty()) p.push back(0.0); Polynome monomemult(double scal, int n, Polynome const& p) Polynome resultat(0); for (int i(0); i < n; ++i) resultat.push back(0); for (int i(0); i <= degre(p); ++i) resultat.push back(p[i] * scal); return resultat; Informatique I Cours 13 : Révisions 27 for (int i(0); i <= degre(b); ++i) a[i] -= b[i]; // garantit la bonne forme du polynôme a simplifie(a); Polynome& quotient, Polynome& reste) quotient = POLYNOME NUL; reste = num; int dq(degre(reste) - degre(denominateur)); while ((dq >= 0) && (reste!= POLYNOME NUL)) met coef(reste[degre(reste)] / denominateur[degre(denominateur)], dq, quotient); soustrait(reste, monome mult(quotient[dq], dq, denominateur)) dq = degre(reste) - degre(denominateur)); Informatique I Cours 13 : Révisions 28
optimisations Remplacer les passages de Polynome par valeur par des Polynome const& Exemple : void division(polynome const& numerateur, Polynome const& denominateur, Polynome& quotient, Polynome& reste); Ceci évite la copie à chaque appel. On peut mettre degre() comme inline. (Rappel : cela se fait au niveau du prototype.) inline int degre(polynome const& p) return p.size()-1 ; Informatique I Cours 13 : Révisions 29