Exercice 1 | Exercice 2 |
Assez naturellement la structure de donnée à utiliser est une struct
contenant un entier pour le numérateur
(p
) et un entier non signé pour le dénominateur
(q
) :
struct Rationnel { int p; unsigned int q; };
La fonction affiche ne présente aucune difficulté, si ce n'est une attention spéciale au cas particulier où le dénominateur vaut 1 :
void affiche(const Rationnel& r) { cout << r.p; if (r.q != 1) cout << '/' << r.q; }
La première version du programme est donc :
#include <iostream> using namespace std; // --- structure de données pour représenter les rationnels struct Rationnel { int p; unsigned int q; }; void affiche(const Rationnel& r); int main() { Rationnel r1 = { 1, 2 }, r2 = {-3, 5 }, r3 = { 2, 1 }; affiche(r1); cout << endl; affiche(r2); cout << endl; affiche(r3); cout << endl; return 0; } // ====================================================================== void affiche(const Rationnel& r) { cout << r.p; if (r.q != 1) cout << '/' << r.q; }
Il nous faut ensuite coder les opérations.
Concentrons nous avant tout sur la réduction d'un nombre rationnel.
Assez facilement nous avons :
void reduction(Rationnel& r) { unsigned int s(pgdc(r.p, r.q)); if (s != 1) { r.p /= s; r.q /= s; } }
Mais il faut juste faire attention au signe de p
:
void reduction(Rationnel& r) { unsigned int s; if (r.p < 0) s = pgdc(-r.p, r.q); else s = pgdc( r.p, r.q); if (s != 1) { r.p /= s; r.q /= s; } }
L'addition vient ensuite très facilement :
Rationnel addition(const Rationnel& r1, const Rationnel& r2) { Rationnel rez = { r1.p*r2.q + r2.p*r1.q, r1.q*r2.q }; reduction(rez); return rez; }
On arrive donc à ce stade à quelque chose comme :
#include <iostream> #include <string> // pour le message d'erreur using namespace std; // --- structure de données pour représenter les rationnels struct Rationnel { int p; unsigned int q; }; void affiche(const Rationnel& r); Rationnel addition(const Rationnel& r1, const Rationnel& r2); void reduction(Rationnel& r); unsigned int pgdc(unsigned int a, unsigned int b); /* fonctions en extra pour faciliter l'écriture du main() * * pas du tout nécessaires pour le corrigé. */ void afficheNL(const Rationnel& r) { affiche(r); cout << endl; } void afficheADD(const Rationnel& r1, const Rationnel& r2) { affiche(r1); cout << " + "; affiche(r2); cout << " = "; afficheNL(addition(r1, r2)); } int main() { Rationnel r1 = { 1, 2 }, r2 = { -3, 5 }, r3 = { 2, 1 }; afficheNL(r1); afficheNL(r2); afficheNL(r3); afficheADD(r1, r2); afficheADD(r3, r2); afficheADD(r3, r3); return 0; } // ====================================================================== void affiche(const Rationnel& r) { cout << r.p; if (r.q != 1) cout << '/' << r.q; } /* ====================================================================== * * Version simplifiée par rapport à la série 11. * * Mais la version donnée dans le corrigé de cette série va aussi bien. * * ====================================================================== */ unsigned int pgdc(unsigned int a, unsigned int b) { unsigned int r; while (b != 0) { r = a % b; a = b; b = r; } return a; } // ====================================================================== void reduction(Rationnel& r) { unsigned int s; if (r.p < 0) s = pgdc(-r.p, r.q); else s = pgdc( r.p, r.q); if (s != 1) { r.p /= s; r.q /= s; } } // ====================================================================== Rationnel addition(const Rationnel& r1, const Rationnel& r2) { Rationnel rez = { r1.p*r2.q + r2.p*r1.q, r1.q*r2.q }; reduction(rez); return rez; }
La soustraction et la multiplication ne posent aucun problème particulier :
Rationnel soustraction(const Rationnel& r1, const Rationnel& r2) { Rationnel rez = { r1.p*r2.q - r2.p*r1.q, r1.q*r2.q }; reduction(rez); return rez; } Rationnel multiplication(const Rationnel& r1, const Rationnel& r2) { Rationnel rez = { r1.p*r2.p, r1.q*r2.q }; reduction(rez); return rez; }
Quant à la division, il faut juste faire attention au signe de
p2
comme indiqué dans l'énoncé :
Rationnel division(const Rationnel& r1, const Rationnel& r2) { Rationnel rez; if (r2.p < 0) { rez.p = (-r1.p) * r2.q; rez.q = (-r2.p) * r1.q; } else if (r2.p > 0) { rez.p = r1.p * r2.q; rez.q = r2.p * r1.q; } else { /* Il faudrait normalement lancer une exception ici, * * mais ce n'est pas le sujet de ce chapitre. */ cout << "Erreur: division par zéro." << endl; rez.p = 0; rez.q = 1; // arbitraire } reduction(rez); return rez; }
On aboutit donc finalement au code :
#include <iostream> #include <string> // pour le message d'erreur using namespace std; // --- structure de données pour représenter les rationnels struct Rationnel { int p; unsigned int q; }; void affiche(const Rationnel& r); Rationnel addition (const Rationnel& r1, const Rationnel& r2); Rationnel soustraction (const Rationnel& r1, const Rationnel& r2); Rationnel multiplication(const Rationnel& r1, const Rationnel& r2); Rationnel division (const Rationnel& r1, const Rationnel& r2); void reduction(Rationnel& r); unsigned int pgdc(unsigned int a, unsigned int b); /* fonctions en extra pour faciliter l'écriture du main(); * * pas du tout nécéssaires pour le corrigé. */ void afficheNL(const Rationnel& r) { affiche(r); cout << endl; } void afficheADD(const Rationnel& r1, const Rationnel& r2) { affiche(r1); cout << " + "; affiche(r2); cout << " = "; afficheNL(addition(r1, r2)); } void afficheSOUS(const Rationnel& r1, const Rationnel& r2) { affiche(r1); cout << " - "; affiche(r2); cout << " = "; afficheNL(soustraction(r1, r2)); } void afficheMULT(const Rationnel& r1, const Rationnel& r2) { affiche(r1); cout << " * "; affiche(r2); cout << " = "; afficheNL(multiplication(r1, r2)); } void afficheDIV(const Rationnel& r1, const Rationnel& r2) { affiche(r1); cout << " / ("; affiche(r2); cout << ") = "; afficheNL(division(r1, r2)); } int main() { Rationnel r1 = { 1, 2 }, r2 = {-3, 5 }, r3 = { 2, 1 }; afficheNL(r1); afficheNL(r2); afficheNL(r3); afficheADD(r1, r2); afficheADD(r3, r2); afficheADD(r3, r3); afficheSOUS(r1, r2); afficheSOUS(r3, r2); afficheSOUS(r2, r2); afficheMULT(r1, r2); afficheMULT(r3, r2); afficheMULT(r2, r2); afficheDIV(r1, r2); afficheDIV(r3, r2); afficheDIV(r2, r2); return 0; } // ====================================================================== void affiche(const Rationnel& r) { cout << r.p; if (r.q != 1) cout << "/" << r.q; } // ====================================================================== unsigned int pgdc(unsigned int a, unsigned int b) { unsigned int r; while (b != 0) { r = a % b; a = b; b = r; } return a; } // ====================================================================== void reduction(Rationnel& r) { unsigned int s; if (r.p < 0) s = pgdc(-r.p, r.q); else s = pgdc( r.p, r.q); if (s != 1) { r.p /= s; r.q /= s; } } // ====================================================================== Rationnel addition(const Rationnel& r1, const Rationnel& r2) { Rationnel rez = { r1.p*r2.q + r2.p*r1.q, r1.q*r2.q }; reduction(rez); return rez; } // ====================================================================== Rationnel soustraction(const Rationnel& r1, const Rationnel& r2) { Rationnel rez = { r1.p*r2.q - r2.p*r1.q, r1.q*r2.q }; reduction(rez); return rez; } // ====================================================================== Rationnel multiplication(const Rationnel& r1, const Rationnel& r2) { Rationnel rez = { r1.p*r2.p, r1.q*r2.q }; reduction(rez); return rez; } // ====================================================================== Rationnel division(const Rationnel& r1, const Rationnel& r2) { Rationnel rez; if (r2.p < 0) { rez.p = (-r1.p) * r2.q; rez.q = (-r2.p) * r1.q; } else if (r2.p > 0) { rez.p = r1.p * r2.q; rez.q = r2.p * r1.q; } else { // Il faudrait normalement lancer une exception ici ! cerr << "Erreur: division par zéro.") << endl; rez.p = 0; rez.q = 1; // arbitraire } reduction(rez); return rez; }
Makefile
)Voici tous les fichiers :
demander_nombre.h
:
int demander_nombre(int a, int b);
demander_nombre.cc
:
#include <iostream> #include <limits> using namespace std; /* -------------------------------------------------------------- * fonction demandant à l'utilisateur un nombre compris * dans un intervalle [a, b], ou supérieur ou égal à a * si b < a. * Entrée : les deux nombres a et b définissant l'intervalle * Sortie : le nombre saisi par l'utilisateur * -------------------------------------------------------------- */ int demander_nombre(int a, int b) { int res; do { cout << "Entrez un nombre entier "; if (a >= b) cout << "supérieur ou égal à " << a; else cout << "compris entre " << a << " et " << b; cout << " : "; cin >> res; if (cin.fail()) { cout << "Je vous ai demandé d'entrer un nombre, " << "pas du charabia !" << endl; // remet cin dans un état lisible cin.clear(); // "jette" toute la ligne cin.ignore(numeric_limits<streamsize>::max(), '\n'); res = a-1; } } while ((res < a) or ((a < b) and (res > b))); return res; }
factorielle.h
:
int factorielle(int n);
factorielleIterative.cc
:
/* ---------------------------------------------------------------------- * Calcule de façon itérative la factorielle d'un nombre entier positif. * Entrée : le nombre n dont on veut calculer la factorielle * Sortie : n! * ---------------------------------------------------------------------- */ int factorielle(int n) { int fact(1); for (int i(2); i <= n; ++i) { fact *= i; } return fact; }
factorielleRecursive.cc
:
/* ---------------------------------------------------------------------- * Calcule de façon récursive la factorielle d'un nombre entier positif. * Entrée : le nombre n dont on veut calculer la factorielle * Sortie : n! * ---------------------------------------------------------------------- */ int factorielle(int n) { if (n <= 1) return 1; else return (n * factorielle(n-1)); }
factmain.cc
:
#include <iostream> #include "demander_nombre.h" #include "factorielle.h" using namespace std; int main() { char rep; do { const int n(demander_nombre(0,12)); cout << n << "! = " << factorielle(n) << endl; do { cout << "Voulez-vous recommencer [o/n] ? "; cin >> rep; } while ((rep != 'o') and (rep != 'n')); } while (rep == 'o'); return 0; }
Makefile
:
CC = $(CXX) CXXFLAGS = -std=c++11 -pedantic -Wall all: factorielleRecursive factorielleIterative factorielleRecursive: factmain.o factorielleRecursive.o demander_nombre.o factorielleIterative: factmain.o factorielleIterative.o demander_nombre.o