Test de C++ n° 1 : (4 mars 2000 – durée : 2h)
© D. Mathieu
mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique
Créé le 04/03/2000 - Dernière mise à jour : 04/03/2000

Tout document autorisé
Sujet : L’objectif de ces exercices est de développer
une classe CRationnel. Un nombre rationnel est un nombre réel
qui peut être mis sous la forme d'une fraction d'entiers. Un objet
de la classe CRationnel est destiné à manipuler des
nombres rationnels.
Sommaire
Classe CRationnel
Opérateur <<
Opérateur <
Opérateur =
Opérateur +
Manipulateur setw ()
Fonction Simplifier()
- Placement
Fonction Simplifier()
- Ecriture
Remarque préliminaire : par souci de simplification, tout
le code sera écrit dans le même fichier, CRationnel.h,
supposé pouvoir être inclus dans d'autres fichiers (pas de
.hxx,
pas de .cxx). Ne perdez pas votre temps à faire l'entête
du fichier. N'oubliez cependant aucune des directives nécessaires
au préprocesseur.
Certains exercices (exercice 6 par exemple) proposent des modifications
de fonctions déjà écrites auparavant. Ne corrigez
pas la version précédente : vous devez IMPERATIVEMENT
rendre les différentes versions. Quand vous ajouterez de nouvelles
fonctions (ou opérateurs), contentez-vous d'écrire les profils
comme vous le feriez dans la déclaration de la classe, en les faisant
précéder de public : ou private :. En annexe
sont fournis, pour chaque exercice, des extraits d'un programme de test
correspondant, afin de vous montrer comment la classe doit pouvoir être
utilisée.
Classe CRationnel
Ecrire la déclaration de la classe CRationnel
qui doit posséder :
-
deux données membres m_Num et m_Denom représentant
le numérateur et le dénominateur de la fraction (entiers
signés),
-
deux constructeurs dont un par recopie,
-
la fonction membre Afficher(), de profil suivant :
void Afficher (void) throw (); |
qui, dans le flux standard de sortie, affiche le numérateur et
le dénominateur séparés par un '/' (sans
espace), -3/7 par exemple,
-
la fonction membre Simplifier(), locale à la classe, qui,
pour le moment, se contente de traiter les cas suivants :
-
les fractions comme -12/5 et 12/-5 par exemple sont mathématiquement
équivalentes, mais seule la première est acceptée
comme représentation interne,
-
les fractions comme 12/5 et -12/-5 par exemple sont mathématiquement
équivalentes, mais seule la première est acceptée
comme représentation interne.
Ecrire les corps de ces fonctions en-dehors de
la déclaration de la classe.
Ne pas se soucier (pour le moment) d'exceptions.
Voir annexe 1.
Voir corrigé
Opérateur <<
Ecrire la surcharge de l'opérateur <<
: voir annexe 2.
Voir corrigé.
Sommaire
Opérateur <
A la classe CRationnel, ajouter l'opérateur
<
(inférieur) : voir annexe 3.
Voir corrigé.
Sommaire
Opérateur =
A la classe CRationnel, ajouter l'opérateur
= (affectation) : voir annexe 4.
Voir corrigé.
Opérateur +
A la classe CRationnel, ajouter l'opérateur
+ (somme) : voir annexe 5.
Voir corrigé.
Sommaire
Manipulateur setw ()
Lorsque l'utilisateur écrit :
cout << "R2 = " << setw (10) << R2 << endl; |
on peut penser qu'il désire écrire la fraction cadrée
à droite sur une zone de 10 caractères. Ce n'est pas ce qui
se passe puisque, le manipulateur n'agissant que sur la prochaine édition,
c'est seulement le numérateur qui est cadré à droite
sur une zone de 10 caractères.
Réécrire l'opérateur <<
pour rendre cette présentation possible. Pour cela, il suffit de
remarquer que :
-
la largeur sur laquelle le numérateur doit être écrit
est la largeur totale désirée diminuée du nombre de
caractères nécessaire à l'édition du reste
de la fraction,
-
le nombre de chiffres nécessaires au dénominateur est le
nombre de fois qu'il faut le diviser par 10 jusqu'à ce qu'il soit
nul.
Il faut aussi savoir que :
-
le manipulateur setw (n) est ignoré si n est négatif,
nul ou trop petit pour afficher,
-
la fonction width(), de profil :
unsigned width (void) const; |
membre des classes de flux, renvoie sans la modifier la largeur courante
(d'édition pour les flux de sortie).
Voir annexe 6.
Voir corrigé.
Sommaire
Fonction Simplifier()
- Placement
La représentation interne des rationnels doit
être la plus simple possible. Pour cela, il est nécessaire
de simplifier la fraction. En supposant que la fonction Simplifier()
écrite précédemment fasse réellement cette
simplification, à quel(s) endroit(s) précisément faudrait-il
l'appeler dans ce qui a déjà été écrit
? (attention : trop ou pas assez de modifications = pas tout à fait
juste !)
Voir corrigé.
Sommaire
Fonction Simplifier()
- Ecriture
La représentation interne des rationnels doit
être la plus simple possible. Pour cela, il est nécessaire
de simplifier la fraction en divisant le numérateur et le dénominateur
par leur plus grand diviseur commun (PGDC). Il faut remarquer que :
-
- la fraction 0/b peut être "simplifiée" en 0/1
-
- le PGDC de deux nombres entiers est défini par :
-
PGDC (a, b) = PGDC (|a|, |b|) où | | représente
la valeur absolue,
-
Si a et b > 0, alors
-
PGDC (a, b) = a
si a = b
-
PGDC (a, b) = PGDC (a - b, a) si a > b
-
PGDC (a, b) = PGDC (b, b - a) si a < b
Ecrire une fonction PGDC(a,b), récursive
…, interne à la classe CRationnel, qui calcule le PGDC de
deux entiers positifs. Réécrire, en la complétant,
la fonction Simplifier(). La valeur absolue d'un numérique
peut être obtenue en utilisant la fonction standard de C++ abs().
Voir corrigé.
Sommaire
Traitement d'exception
En utilisant la classe d'exceptions standard exception,
quelle(s) modification(s) faudrait-il effectuer pour éviter une
division par 0 ? (attention : trop ou pas assez de modifications = toujours
un peu faux !!!!)
Voir corrigé.
Sommaire
Annexes
Annexe 1
CRationnel R1;
CRationnel R2 (12, 5);
CRationnel R3 ( 3, 5);
CRationnel R4 (12, 8);
CRationnel R5 (12, -8);
CRationnel R6 (R2);
cout << "R1 = ";
R1.Afficher ();
cout << endl; |
Sommaire
Annexe 2
cout << "R2 =
" << R2 << endl; |
Sommaire
Annexe 3
if (R2 < R3)
cout << R2 <<
" < " << R3 << endl;
else
cout << R2 <<
" >= " << R3 << endl;
cout << endl;
cout << R2 << (R2 < R2 ? " <
" : " >= ") << R2 << endl; |
Sommaire
Annexe 4
CRationnel R6;
CRationnel R7 (R1);
R6 = R7;
R7 = R7; |
Sommaire
Annexe 5
R6 = R2 + R3 + R4;
cout << "R6 = R2 + R3 + R4 = " <<
R6 << endl; |
Sommaire
Annexe 6
for (int i = 0; i < 10; ++i)
cout <<
setw (i) << R5 << endl; |
Sommaire

© D. Mathieu
mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique