Choisissez votre style : style 1,    style 2,    sans commentaire,    impression,    ancien.

Correction
Remise en route, Makefiles.

Exercice 1 Exercice 2

Exercice 1 : arithmétique rationnelle

Exercice n°40 (pages 93 et 276) de l'ouvrage C++ par la pratique.

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;
}
 

Exercice 2 : factorielles revisitées (Makefile)

Voici tous les fichiers :


Dernière mise à jour : $Date: 2014-02-17 15:10:57 +0100 (lun 17 fév 2014) $  ($Revision: 212 $)