TD 4 : Des fonctions, des tests et de la documentation#
Notes aux enseignants
La notion d’appel de fonction vs définition de la fonction n’est pas
simple pour les débutants. Une erreur classique est d’indiquer le type
au moment de l’appel (ex : cout << int factorielle(3);).  Faire le
parallèle avec les variables : on déclare le type d’une variable une
fois pour toutes et ensuite on l’utilise sans le rappeler (ex : cout << x;) et c’est pareil avec les fonctions.
Une autre difficulté est de comprendre ce qu’est réellement un paramètre, et la différence entre paramètre et variable locale. Par exemple dans l’exercice 1 beaucoup d’élèves ont tendance à mettre pi en paramètre.
Exercice 1 : Premières fonctions
Voici une fonction qui calcule la surface d’un rectangle :
float surfaceRectangle(float longueur, float largeur) {
    return longueur * largeur;
}
- Définissez une fonction - surfaceDisquequi calcule la surface d’un disque de rayon donné. On prendra \(\pi=3,1415926\).- /// BEGIN SOLUTION - float surfaceDisque(float rayon) { return 3.1415926 * rayon * rayon; } - /// END SOLUTION 
- Définissez une fonction - surfaceTrianglequi calcule la surface d’un triangle de base et de hauteur données.- /// BEGIN SOLUTION - float surfaceTriangle(float base, float hauteur) { return base * hauteur / 2; } - /// END SOLUTION 
Exercice 2 : En route vers l’exponentielle
- Nous avons vu en cours et en TP une fonction - factorielle(n)qui calcule la factorielle d’un entier positif \(n\). Pour un exercice du TP à venir, et pour éviter les problèmes de dépassement de capacité, il est souhaitable que les calculs intermédiaires et le résultat soient des- double. Adaptez en conséquence la fonction- factorielle.- /// BEGIN SOLUTION - /** La fonction factorielle * @param n un nombre entier positif * @return n! comme un nombre à virgule flottante à double précision **/ double factorielle(int n) { double resultat = 1; for ( int k = 1; k <= n; k++ ) { resultat = resultat * k; } return resultat; }- /// END SOLUTION 
- On considère la fonction dont la documentation et l’entête sont donnés ci-dessous : - /** La fonction puissance * @param a un nombre à virgule flottante en double précision * @param n un nombre entier positif * @return la n-ième puissance a^n de a **/ - Quels sont les types de ses paramètres formels et de sa valeur de retour? - /// BEGIN SOLUTION - Le paramètre formel - aest de type- double, le paramètre formel- nest de type- int, la valeur de retour est de type- double.- /// END SOLUTION 
- Écrivez quelques exemples d’utilisation de la fonction - puissance. Éditez-les sous forme de tests, en vous inspirant du test suivant pour la fonction- surfaceRectangle:- CHECK( surfaceRectangle(4, 5) == 20 ); - /// BEGIN SOLUTION - CHECK( puissance(2.5, 0) == 1.0 ); CHECK( puissance( 35, 1) == 35.0 ); CHECK( puissance( -2, 4) == 16.0 ); CHECK( puissance( 10, 5) == 100000.0 ); - /// END SOLUTION 
- Définissez la fonction - puissance.- /// BEGIN SOLUTION - /** La fonction puissance * @param a un nombre à virgule flottante en double précision * @param n un nombre entier positif * @return la n-ième puissance a^n de a **/ - /// END SOLUTION 
- Cherchez dans les notes de cours la sémantique simplifiée de l’appel d’une fonction. 
- Exécutez pas à pas le programme suivant : - int k = 3; double x = 6; double a = 4; double resultat = puissance(x - a, k) / factorielle(k); cout << resultat << endl; - Quelle est la valeur de la variable - resultatà la fin?- /// BEGIN SOLUTION - Les trois premières lignes initialisent les variables - k,- xet- a. Ensuite on calcule- puissance(x - a, k) / factorielle(k), qu’on stocke dans- resultat.- Au moment du calcul, les expressions passées aux fonctions auxiliaires sont remplacées par leur valeur. Ainsi l’appel effectif est - puissance(2, 3) / factorielle(3).- Il ne reste plus qu’à exécuter pas à pas la fonction - puissanceavec \(2\) et \(3\) comme valeurs initiales pour ses paramètres formels- aet- n: on obtient \(8.0\) comme valeur de retour.- On fait de même avec - factorielleavec \(3\) comme valeur initiale pour le paramètre formel- n, ce qui donne \(6.0\).- Il ne reste qu’à faire la division - 8.0 / 6.0, ce qui donne environ \(1.333\), et c’est la valeur de- resultat.- /// END SOLUTION 
- \(\clubsuit\) Définissez les fonctions - factorielleet- puissanceen récursif cette fois, puis refaites l’exécution pas à pas. Qu’est-ce qui change?- /// BEGIN SOLUTION - /** La fonction factorielle récursive * @param n un nombre entier positif * @return n! comme un nombre à virgule flottante à double précision **/ double factorielle(int n) { double resultat = n; if ( n == 0 ) { resultat = 1; } else { resultat = resultat * factorielle(n-1); } return resultat; }- /// END SOLUTION - /// BEGIN SOLUTION - /** La fonction puissance récursive * @param a un nombre à virgule flottante en double précision * @param n un nombre entier positif * @return la n-ième puissance a^n de a **/ double puissance(double a, int n) { if ( n == 0 ) { return 1; } else { return a * puissance(a , n - 1); } } - /// END SOLUTION 
Notes aux enseignants
Les étudiants ont vu en cours la sémantique détaillée de l’appel de fonctions, mais c’est encore fragile. Dans l’exercice suivant, forcer les étudiants à suivre pas à pas les étapes décrites dans la sémantique de l’appel de fonction, en utilisant la même représentation de la pile que dans le poly. À corriger soigneusement au tableau, avec le même formalisme que dans le cours (donc pas comme la présentation compacte utilisée dans la correction ci-dessous).
Exercice 3 : Variables locales/globales, pile et exécution pas à pas
On considère les deux programmes suivants :
int k = 3;
int i = 5;
int f(int j) {
    i = i + j;
    return i;
}
int resultat = f(1) + f(2) + f(k);
int k = 3;
int f(int j) {
    int i = 5;
    i = i + j;
    return i;
}
int resultat = f(1) + f(2) + f(k);
- Mettez en évidence les différences entre les deux programmes (par exemple au surligneur). - BEGIN SOLUTION - Dans le premier programme, la variable - iest globale (comme- ket- resultat), alors qu’elle est locale à la fonction- fdans le second programme.- END SOLUTION 
- Cherchez dans les notes de cours la sémantique détaillée de l’appel d’une fonction (formalisation suivant le modèle d’exécution). - BEGIN SOLUTION - Voir ici. - END SOLUTION 
- Exécutez pas à pas les deux programmes en décrivant au fur et à mesure l’état de la mémoire (pile). Quelle est la valeur la variable - resultatà la fin de l’exécution?- BEGIN SOLUTION - Pour une meilleur compréhension nous allons mettre en parallèle l’état des piles lors de l’exécution des deux programmes (celui ou la variable - iest globale et celui ou elle est locale).- Les deux programmes pour rappel : - int k = 3; ││ int k = 3; int i = 5; ││ int f(int j) { int f(int j) { ││ int i = 5; i = i + j; ││ i = i + j; return i; ││ return i; } ││ } resultat = f(1) + f(2) + f(k); ││ resultat = f(1) + f(2) + f(k);- État de la pile juste avant l’instruction - resultat = f(1) + f(2) + f(k);:- portée │ variable │ valeur │ ││ portée │ variable │ valeur │ __________________________________ ││ __________________________________ ┌──────────────┬─────────┐ ││ globale │ int i │ 5 │ ││ ┌──────────────┬─────────┐ globale │ int k │ 3 │ ││ globale │ int k │ 3 │ ├──────────────┴─────────┤ ││ ├──────────────┴─────────┤ │ ... │ ││ │ ... │ └────────────────────────┘ ││ └────────────────────────┘ Pile ││ Pile- Dans le calcul de - f(1), juste avant l’instruction- i = i + j:- ┌──────────────┬─────────┐ ││ ┌──────────────┬─────────┐ f │ int j │ 1 │ ││ f │ int i │ 5 │ globale │ int resultat │ ? │ f(1)+f(2)+f(k) ││ f │ int j │ 1 │ f(1)+f(2)+f(k) globale │ int i │ 5 │ ││ globale │ int resultat │ ? │ globale │ int k │ 3 │ ││ globale │ int k │ 3 │ ├──────────────┴─────────┤ ││ ├──────────────┴─────────┤ │ ... │ ││ │ ... │ └────────────────────────┘ ││ └────────────────────────┘ Pile ││ Pile- Dans le calcul de f(1), juste avant l’instruction - return:- ┌──────────────┬─────────┐ ││ ┌──────────────┬─────────┐ f │ int j │ 1 │ ││ f │ int i │ 6 │ globale │ int resultat │ ? │ f(1)+f(2)+f(k) ││ f │ int j │ 1 │ globale │ int i │ 6 │ ││ globale │ int resultat │ ? │ f(1)+f(2)+f(k) globale │ int k │ 3 │ ││ globale │ int k │ 3 │ ├──────────────┴─────────┤ ││ ├──────────────┴─────────┤ │ ... │ ││ │ ... │ └────────────────────────┘ ││ └────────────────────────┘ Pile ││ Pile- Juste après le calcul de f(1) : - ┌──────────────┬─────────┐ ││ globale │ int resultat │ ? │ 6+f(2)+f(k) ││ ┌──────────────┬─────────┐ globale │ int i │ 6 │ ││ globale │ int resultat │ ? │ 6+f(2)+f(k) globale │ int k │ 3 │ ││ globale │ int k │ 3 │ ├──────────────┴─────────┤ ││ ├──────────────┴─────────┤ │ ... │ ││ │ ... │ └────────────────────────┘ ││ └────────────────────────┘ Pile ││ Pile- Dans le calcul de - f(2), juste avant l’instruction- i = i+j:- ┌──────────────┬─────────┐ ││ ┌──────────────┬─────────┐ f │ int j │ 2 │ ││ f │ int i │ 5 │ globale │ int resultat │ ? │ 6+f(2)+f(k) ││ f │ int j │ 2 │ 6+f(2)+f(k) globale │ int i │ 6 │ ││ globale │ int resultat │ ? │ globale │ int k │ 3 │ ││ globale │ int k │ 3 │ ├──────────────┴─────────┤ ││ ├──────────────┴─────────┤ │ ... │ ││ │ ... │ └────────────────────────┘ ││ └────────────────────────┘ Pile ││ Pile- Dans le calcul de f(1), juste avant l’instruction - return:- ┌──────────────┬─────────┐ ││ ┌──────────────┬─────────┐ f │ int j │ 2 │ ││ f │ int i │ 7 │ globale │ int resultat │ ? │ 6+f(2)+f(k) ││ f │ int j │ 2 │ globale │ int i │ 8 │ ││ globale │ int resultat │ ? │ 6+f(2)+f(k) globale │ int k │ 3 │ ││ globale │ int k │ 3 │ ├──────────────┴─────────┤ ││ ├──────────────┴─────────┤ │ ... │ ││ │ ... │ └────────────────────────┘ ││ └────────────────────────┘ Pile ││ Pile- Juste après le calcul de f(2) : - ┌──────────────┬─────────┐ ││ globale │ int resultat │ ? │ 6+8+f(k) ││ ┌──────────────┬─────────┐ globale │ int i │ 6 │ ││ globale │ int resultat │ ? │ 6+7+f(k) globale │ int k │ 3 │ ││ globale │ int k │ 3 │ ├──────────────┴─────────┤ ││ ├──────────────┴─────────┤ │ ... │ ││ │ ... │ └────────────────────────┘ ││ └────────────────────────┘ Pile ││ Pile- Dans le calcul de f(k), juste avant l’instruction - return:- ┌──────────────┬─────────┐ ││ ┌──────────────┬─────────┐ f │ int j │ 3 │ ││ f │ int i │ 8 │ globale │ int resultat │ ? │ 6+7+f(3) ││ f │ int j │ 3 │ globale │ int i │ 11 │ ││ globale │ int resultat │ ? │ 6+7+f(3) globale │ int k │ 3 │ ││ globale │ int k │ 3 │ ├──────────────┴─────────┤ ││ ├──────────────┴─────────┤ │ ... │ ││ │ ... │ └────────────────────────┘ ││ └────────────────────────┘ Pile ││ Pile- Juste après l’exécution de la dernière instruction : - ┌──────────────┬─────────┐ ││ globale │ int resultat │ 25 │ (=6+8+11) ││ ┌──────────────┬─────────┐ globale │ int i │ 6 │ ││ globale │ int resultat │ 21 │ (= 6+7+8) globale │ int k │ 3 │ ││ globale │ int k │ 3 │ ├──────────────┴─────────┤ ││ ├──────────────┴─────────┤ │ ... │ ││ │ ... │ └────────────────────────┘ ││ └────────────────────────┘ Pile ││ Pile- END SOLUTION 
- Décrivez la différence de comportement entre ces programmes, et retrouvez dans les notes de cours le commentaire à ce propos. - BEGIN SOLUTION - Dans le premiers programme, - ia une durée de vie sur l’ensemble de l’exécution du programme et n’est initialisée qu’une seule fois au début. Dans le deuxième programme,- iest recréée et réinitialisée à- 5à chaque appel de- f. Il est donc important de savoir déclarer ses variables avec la bonne portée : locales ou globales.- END SOLUTION 
Exercice 4 : La trilogie code, documentation, tests
Analysez la fonction volumePiscine suivante :
/** Calcule le volume d'une piscine parallélépipédique
 *  @param profondeur la profondeur de la piscine (en mètres)
 *  @param largeur la largeur de la piscine (en mètres)
 *  @param longueur la longueur de la piscine (en mètres)
 *  @return le volume de la piscine (en litres)
 **/
double volumePiscine(double profondeur, double largeur, double longueur) {
    return 100 * profondeur * largeur * longueur;
}
Munie des tests :
    CHECK( volumePiscine(5, 12, 5) == 30000 );
    CHECK( volumePiscine(1,  1, 5) == 500   );
- Est-ce que les tests passent? - /// BEGIN SOLUTION - Oui! - /// END SOLUTION 
- La documentation, le code et les tests sont-ils cohérents? - /// BEGIN SOLUTION - Les tests et l’implantation ne sont pas cohérents avec la documentation, car cette dernière spécifié que le résultat doit être exprimé en litres, alors que dans le test et l’implantation le résultat calculé est exprimé en décalitres. - /// END SOLUTION 
- Corrigez les anomalies éventuelles. - /// BEGIN SOLUTION - Le facteur de conversion devrait être de \(10^3=1000\) et pas de \(100\). - /// END SOLUTION 
Exercice 5 : \(\clubsuit\)
Analysez la fonction mystere suivante :
string mystere(int blop) {
    string schtroumpf = "";
    for ( int hip = 1; hip <= blop; hip++ ) {
        for ( int hop = 1; hop <= hip; hop++ ) {
            schtroumpf += "*";
        }
        schtroumpf += "\n";
    }
    return schtroumpf;
}
Munie des tests :
    CHECK( mystere(0) == ""             );
    CHECK( mystere(1) == "*\n"          );
    CHECK( mystere(2) == "*\n**\n"      );
    CHECK( mystere(3) == "*\n**\n***\n" );
- Comment fait-on appel à cette fonction (quelle est sa syntaxe)? - /// BEGIN SOLUTION - La signature de la fonction : - string mystere(int blop); - nous indique que la fonction attend un seul paramètre entier ( - blop). On écrit donc- mystere(x)où- xest un entier pour appeler la fonction.- /// END SOLUTION 
- Que fait cette fonction (quelle est sa sémantique)? Indications : pour les chaînes de caractères, l’opérateur - +représente la concaténation (par exemple- "Cou" + "cou"a pour valeur- "Coucou"); comme pour les entiers,- x += expressionest un raccourci pour- x = x + expression; enfin, dans une chaîne de caractères, «- \n» représente un saut de ligne.- /// BEGIN SOLUTION - La fonction crée une chaîne de caractères représentant un triangle d’étoiles ayant - bloplignes et la renvoie. La boucle externe se charge des lignes, tandis que la boucle imbriquée se charge des colonnes.- Ainsi, - mystere(4)renvoie la chaîne de caractères :- * ** *** **** - /// END SOLUTION 
- Ré-écrivez la fonction en choisissant des noms pertinents pour la fonction et ses variables et en la faisant précéder de sa documentation. - /// BEGIN SOLUTION - /** Triangle d'étoiles * @param nbLignes un nombre entier positif * @return une chaîne de caractère représentant un triangle d'étoiles * ayant nbLignes lignes **/ string triangleEtoiles(int nbLignes) { string resultat = ""; for ( int ligne = 1; ligne <= nbLignes; ligne++ ) { for ( int etoile = 1; etoile <= ligne; etoile++ ) { resultat += "*"; } resultat += "\n"; } return resultat; } - /// END SOLUTION 
Exercice 6 : \(\clubsuit\)
Le but de cet exercice est de coder une fonction point_de_chute qui
calcule l’abscisse \(x_c\) à laquelle tombe un projectile lancé en \(x =
0\) avec une vitesse \(v\) suivant un angle \(\alpha\) (exprimé en degrés
par rapport à l’horizontale). Définissez la fonction
point_de_chute. On commencera par écrire sa documentation ainsi que
des tests (voir TD 1).
Rappels :
- l’abscisse est donnée par la formule : \(x_c=(2v_xv_y)/g\) où \(v_x = v\cos(\alpha)\), \(v_y = v\sin(\alpha)\) et \(g\) est l’accélération gravitationnelle (environ \(\SI{9,8}{\meter\per\second\squared}\) sur la planète Terre). 
- en C - ++, les fonctions mathématiques sinus et cosinus sont implantées par les fonctions prédéfinies- sin(arg)et- cos(arg)dans- <cmath>, où l’angle- argest exprimé en radians.
/// BEGIN SOLUTION
/** Fonction qui calcule le point de chute d'un objet lancé
 *  @param v la vitesse de lancer en m/s
 *  @param angle l'angle de lancer en degrés, entre 0 et 180
 *  @return l'abscisse du point de chute comme un nombre à virgule flottante
 *          à double precision
 **/
double pointDeChute(int v, int angle) {
    double angleRadians = angle * 3.141592 / 180;
    return 2 * v * cos(angleRadians) * v * sin(angleRadians) / 9.8;
}
void pointDeChuteTest() {
    CHECK(pointDeChute(3, 0) == 0);
    CHECK(pointDeChute(3, 90) == 0);
    CHECK(pointDeChute(0, 45) == 0);
    CHECK(pointDeChute(3, 30) + pointDeChute(3, 150) == 0);
}
/// END SOLUTION
Exercice 7 : \(\clubsuit\)
Le but de cet exercice est de calculer la hauteur en fonction du temps \(z(t)\) à laquelle se trouve un pot de fleur (\(m=\SI{3}{\kilogram}\)) lâché à \(t=0\) depuis le 10ème étage (\(h_0=\SI{27}{\meter}\)), en chute libre avec résistance de l’air; puis de calculer le temps de chute.
- Définissez une fonction - chute_libre(t)calculant \(z(t)\) pour un \(V_0\) donné (\(V_0=\SI{80}{\meter\per\second}\)). Indications :- La hauteur s’exprime en fonction du temps par :::{math} z(t)=h_0-(V_0t+\frac{V_0^2}{g} \ln\left(\frac{1}{2}\left(1+e^{-2tg/V_0}\right)\right),, ::: où \(V_0\) est la vitesse limite de chute de l’objet et \(g=\SI{9.81}{\meter\per\second\squared}\). 
- La fonction logarithme népérien est prédéfinie sous la forme - log(arg)dans- <cmath>.
 - /// BEGIN SOLUTION - /** Calcul de la hauteur d'un objet en chute libre * @param time: le temps de chute * @return la hauteur de l'objet au temps time **/ double chute_libre_simple(double t) { double g = 9.81; double Vo=80; double ho=27; return ho - Vo*t - Vo*Vo/g*log( (1 + exp(-2*t*g/Vo)) / 2 ); } - /// END SOLUTION 
- Que se passe-t-il si on varie \(h_0\) et \(V_0\)? Généralisez votre fonction pour prendre en paramètres additionnels la hauteur initiale \(h_0\) et la vitesse limite de chute \(V_0\). Pour la gravité, définir une variable globale \(g\). Bonus : définir cette variable globale comme une constante (nous irons sur Mars une autre fois). - /// BEGIN SOLUTION - double g = 9.81; /** Calcul de la hauteur d'un objet en chute libre * @param time: le temps de chute * @param h0: le hauteur au début de la chute * @param V0: la vitesse limite * @return la hauteur de l'objet au temps time **/ double chute_libre(double t, double ho, double Vo) { return ho - Vo*t - Vo*Vo/g*log( (1 + exp(-2*t*g/Vo)) / 2 ); } - /// END SOLUTION - Écrivez les appels à la fonction précédente pour calculer \(z(t)\) pour \(t=\SI{2}{s}\) et pour différentes valeur de \(V_0\): \(10\), \(40\), \(60\), \(120\), \(\SI{180}{\meter\per\second}\). - /// BEGIN SOLUTION - chute_libre(2,27,10); chute_libre(2,27,40); chute_libre(2,27,60); chute_libre(2,27,120); chute_libre(2,27,180);/// END SOLUTION
- Écrivez une fonction - temps_de_chutequi prend les même paramètres que précédemment et utilise- chute_librede façon répétée pour déterminer une approximation de la durée \(t_c\) de la chute du pot de fleur jusqu’au sol.- /// BEGIN SOLUTION - /** Calcul d'une approximation du temps de chute * @param precision: la precision attendue, un reel strictement positif * @param h0: le hauteur au début de la chute * @param V0: la vitesse limite * @return une approximation du temps de chute **/ double temps_de_chute(double precision, double ho, double Vo) { double t1=0; double t2=1; double t3; //on commence par chercher un temps t2 qui soit plus grand que //le temps de chute, //le temps t1 doit lui rester plus petit que le temps de chute while (chute_libre(t2,ho,Vo)>0){ t1=t2; t2=2*t2; } //on cherche ensuite t par dichotomie while (t2-t1>precision){ t3=(t1+t2)/2; if (chute_libre(t3,ho,Vo)<0){ t2=t3; } else { t1=t3; } } return t1; } - /// END SOLUTION 
- La vitesse limite peut être obtenue en fonction de la masse volumique de l’air \(\rho\), du coefficient de résistance aérodynamique \(C_x\) et de la section de l’objet \(S\) à l’aide de la formule \(V_0=\sqrt{\frac{2mg}{C_x \rho S}}\). Définissez une fonction - vitesse_limitepour calculer cette formule. Puis implantez de nouvelles fonctions utilisant les précédentes pour calculer \(z(t)\) et le temps de chute \(t_c\) en fonction des paramètres \(C_x\), \(S\), et \(m\). On suppose que \(\rho\) est une variable globale déjà définie.- /// BEGIN SOLUTION - double vitesse_limite(double Cx, double S, double m){ return sqrt(2*m*g/(Cx*rho*S)); } - /// END SOLUTION 
Exercice 8 : \(\clubsuit\) Triangles rectangles à côtés entiers
Inspiré du problème 39 du Projet Euler, Integer right triangles
Pour un périmètre \(p=120\) donné, il n’existe que trois configurations pour un triangle rectangle dont les côté sont de longueurs entières : \(\{20, 48, 52\}, \{24, 45, 51\}, \{30, 40, 50\}\).
Documentez et écrivez une fonction nombreTrianglesRectanglesEntiers
qui prend en entrée un entier, le périmètre fixé, et renvoie le nombre
de configurations possibles de triangles rectangles à côtés de
longueurs entières.
Indications : On pensera à écrire des fonctions intermédiaires utiles, par exemple une fonction qui vérifie que la longueur de l’hypothénuse d’un triangle rectangle est entière et renvoie sa valeur à partir des longueurs de ses deux autres côtés, ou une fonction qui vérifie si la somme des longueurs des trois côtés vaut bien le périmètre fixé. Ne pas oublier de prévoir des tests automatiques pour chaque fonction qui le permet.
/// BEGIN SOLUTION
/** Une fonction qui calcule la longueur de l'hypothénuse d'un triangle 
 *  rectangle à partir des longueurs de ses deux autres côtés
 * @param x un entier, longueur d'un côté du triangle
 * @param y un entier, longueur d'un côté du triangle
 * @return la longueur de l'hypothénuse si elle est entière, -1 sinon
 * */
int longueurHypothenuse(int x, int y) {
    int carreHypothenuse = x*x + y*y;
    int racine = 1;
    while (racine * racine < carreHypothenuse) {
        racine++;
    }
    if (racine * racine == carreHypothenuse) {
        return racine;
    } else {
        return -1;
    }
}
/** Une fonction qui calcule le paramètre d'un triangle à partir des longueurs 
 *  de ses côtés
 * @param x un entier, longueur d'un côté du triangle
 * @param y un entier, longueur d'un côté du triangle
 * @param z un entier, longueur d'un côté du triangle
 * @return le périmètre du triangle
 * */
int perimetre(int x, int y, int z) {
    return x + y + z;
}
/** Une fonction qui renvoie le nombre de triangles rectangles entiers de 
 *  périmètre donné
 * @param p un entier positif, le périmètre donné
 * @return le nombre de triangles rectangles de côtés entiers de périmètre p
 * */
int nombreTrianglesRectanglesEntiers(int p) {
    int c;
    int nombre = 0;
    for ( int b = 1; b <= p / 2; b++ ) {
        for ( int a = 1; a <= b; a ++ ){ 
            c = longueurHypothenuse(a, b);
            if ((c > 0) && (perimetre(a, b, c) == p)){
                nombre++;
            }
        }
    }
    return nombre;
}
Avec les tests :
    CHECK( perimetre(1, 2, 3) == 6 );
    CHECK( perimetre(15, 5, 3) == 23 );
    CHECK( longueurHypothenuse(20, 48) == 52 );
    CHECK( longueurHypothenuse(24, 45) == 51 );
    CHECK( nombreTrianglesRectanglesEntiers(120) == 3 );
/// END SOLUTION