Adloun

Probleme – Le triangle : partitionner, puis éprouver les limites

Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 4 — Discipline de programmation, validation et test

Énoncé

Une fonction classe un triplet d'entiers en invalide, équilatéral, isocèle ou scalène.

Corrigé

1. La fonction.


typedef enum { INVALIDE, EQUILATERAL, ISOCELE, SCALENE } classe_t;

/* Classe le triplet (a, b, c) vu comme les longueurs des cotes d'un
   triangle. Rend INVALIDE si une longueur est <= 0 ou si l'inegalite
   triangulaire STRICTE n'est pas verifiee (un triangle plat est refuse).
   Precondition : aucune. */
classe_t classer(int a, int b, int c) {
    if (a <= 0 || b <= 0 || c <= 0) { return INVALIDE; }
    if (a + b <= c || a + c <= b || b + c <= a) { return INVALIDE; }
    if (a == b && b == c) { return EQUILATERAL; }
    if (a == b || b == c || a == c) { return ISOCELE; }
    return SCALENE;
}

La spécification tranche deux questions que l'énoncé laissait ouvertes : les longueurs nulles ou négatives, et le triangle plat (). Sans elles, on ne peut pas écrire un seul test — et c'est le sens de la règle « la spécification s'écrit avant le corps ».

2. Le partitionnement, et les limites.

ClasseCasAttenduRôle
équilatéraléquilatéralnominal
isocèle, , isocèleles trois positions
scalènescalènenominal
longueur nulleinvalidelimite basse
longueur négativeinvalidehors domaine
inégalité violéeinvalidenominal
triangle platinvalidela limite

Deux remarques de méthode. D'abord, il faut trois cas isocèles et non un : la condition est une disjonction de trois égalités, et une seule d'entre elles serait éprouvée par . C'est le test exhaustif d'une condition composée, appliqué. Ensuite, n'est pas un cas « bizarre » : c'est exactement la frontière entre valide et invalide, là où .

3. La version soumise, mesurée sur les onze cas :


  a  b  c | correct     | version soumise | divergence
  3  3  3 | equilateral | equilateral     |
  3  3  5 | isocele     | isocele         |
  3  4  5 | scalene     | scalene         |
  1  2  3 | invalide    | scalene         | OUI
  1  2  4 | invalide    | invalide        |
  0  1  1 | invalide    | invalide        |
 -1  2  2 | invalide    | invalide        |
  5  3  3 | isocele     | isocele         |
  3  5  3 | isocele     | isocele         |
  2  2  3 | isocele     | isocele         |
  5  5  8 | isocele     | isocele         |

Un seul test sur onze l'attrape, et c'est le triangle plat — celui qu'on aurait supprimé en le trouvant tordu. Les dix autres, y compris les trois cas isocèles et le cas négatif, sont muets.

4. Le balayage exhaustif. Sur les triplets de , séparent les deux versions, soit . Ce ne sont pas de triplets « au hasard » : ce sont exactement ceux où une des trois sommes égale le troisième côté. Un tirage aléatoire aurait donc une chance sur neuf de tomber dessus par essai — et il en faudrait une vingtaine pour être raisonnablement sûr. Un test aux limites, un seul, suffit.

ImportantPourquoi les fautes vivent aux frontières

Le programme officiel demande de sensibiliser « au test des limites ». La raison est mécanique : les fautes de programmation les plus fréquentes sont des erreurs d'un cran — écrit , écrit , écrit . Or une erreur d'un cran ne change le comportement que sur une valeur de chaque frontière. Au milieu d'une classe, les deux versions coïncident ; à la frontière, elles divergent.

Un jeu de tests qui ne visite que « des cas représentatifs » manque donc précisément la famille de fautes la plus probable. La bonne façon de construire un test n'est pas « quelle entrée typique ? » mais « quelle entrée séparerait ce code d'un code décalé d'un cran ? ».

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.