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; 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; 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); 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; } /* ====================================================================== * * ====================================================================== */ 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. */ 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; 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); 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 ! 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; /* -------------------------------------------------------------- * si b < a. * 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) else cout << "compris entre " << a << " et " << b; cout << " : "; cin >> res; if (cin.fail()) { << "pas du charabia !" << endl; 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
:
/* ---------------------------------------------------------------------- * Sortie : n! * ---------------------------------------------------------------------- */ int factorielle(int n) { int fact(1); for (int i(2); i <= n; ++i) { fact *= i; } return fact; }
factorielleRecursive.cc
:
/* ---------------------------------------------------------------------- * 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