5.1 KiB
Compte rendu – TD Complexité cyclomatique (R5.A.04)
Partie 1 – Graphes de flot de contrôle
Pour chaque fonction demandée dans l'énnoncé, on construit le graphe de flot de contrôle, puis on applique :
M = E − N + 2P (E = arêtes, N = nœuds, P = 1 pour une fonction)
On vérifie ensuite le résultat avec la règle pratique M = décisions + 1.
C2 – moyenne (C)
- N = 8, E = 9, P = 1
- M = 9 − 8 + 2 × 1 = 3
C4 – nom_jour (C)
- N = 10, E = 16 (8 arêtes du
switchvers chaque branche + 8 arêtes des branches vers la sortie), P = 1 - M = 16 − 10 + 2 × 1 = 8
J2 – estDisponible (Java)
La méthode ne contient aucun if, mais les && sont évalués paresseusement : chaque opérande est une décision (si livre.emprunte est vrai, on sort directement sans évaluer la suite).
- N = 4, E = 5, P = 1
- M = 5 − 4 + 2 × 1 = 3
J6 – importer (Java)
Les nœuds de décision sont en jaune, et la condition de la boucle for est en bleu.
- N = 15, E = 21, P = 1
- M = 21 − 15 + 2 × 1 = 8
P2 – signe (Python)
- N = 6, E = 7, P = 1
- M = 7 − 6 + 2 × 1 = 3
P3 – notes_valides (Python)
La compréhension de liste cache une boucle et un filtre : elle se lit comme un for contenant un if.
- N = 5, E = 6, P = 1
- M = 6 − 5 + 2 × 1 = 3
Récapitulatif
| Fonction | N | E | M | Classe |
|---|---|---|---|---|
C2 moyenne |
8 | 9 | 3 | Simple |
C4 nom_jour |
10 | 16 | 8 | Simple |
J2 estDisponible |
4 | 5 | 3 | Simple |
J6 importer |
15 | 21 | 8 | Simple |
P2 signe |
6 | 7 | 3 | Simple |
P3 notes_valides |
5 | 6 | 3 | Simple |
Partie 2 – Comptage des décisions (M = décisions + 1)
C (exercices.c)
| Fonction | Décisions | M | Classe |
|---|---|---|---|
C1 carre |
aucune | 1 | Simple |
C2 moyenne |
1 for, 1 ternaire ?: |
3 | Simple |
C3 est_bissextile |
1 &&, 1 || |
3 | Simple |
C4 nom_jour |
7 case |
8 | Simple |
C5 compter_mots |
1 while, 4 ||, 1 if, 1 else if |
8 | Simple |
C6 date_valide |
4 if/else if, 6 || |
11 | Modéré |
Détail de C3 : il n'y a aucun if, mais && et || sont évalués paresseusement : chacun crée un branchement (si annee % 4 == 0 est faux, annee % 100 != 0 n'est pas évalué). 2 décisions + 1 = 3, ce qui correspond au graphe vu en cours (N = 4, E = 5).
Détail de C4 : le default ne compte pas (c'est le « sinon » du switch) et les return non plus. 7 + 1 = 8, comme avec le graphe (16 − 10 + 2).
Détail de C5 :
| Ligne | Décision | +1 |
|---|---|---|
while (texte[i] != '\0') |
while |
1 |
c == ' ' || c == '\t' || c == '\n' || c == ',' || c == '.' |
4 || |
5 |
if (separateur) |
if |
6 |
else if (!dans_mot) |
else if |
7 |
M = 7 + 1 = 8. Ici aussi les || comptent sans if : ils sont dans une affectation (int separateur = ...), mais restent des branchements.
Détail de C6 :
| Ligne | Décision | +1 |
|---|---|---|
if (annee < 1 || mois < 1 || mois > 12 || jour < 1) |
if + 3 || |
4 |
if (mois == 2) |
if |
5 |
if (est_bissextile(annee)) |
if |
6 |
else if (mois == 4 || mois == 6 || mois == 9 || mois == 11) |
else if + 3 || |
10 |
M = 10 + 1 = 11, soit juste au-dessus du seuil de 10 (McCabe, PMD) : c'est la fonction C la plus complexe. L'appel à est_bissextile ne compte pas : ses décisions appartiennent à est_bissextile (M calculé par fonction).
Python (exercices.py)
| Fonction | Décisions | M | Classe |
|---|---|---|---|
P1 celsius_vers_fahrenheit |
aucune | 1 | Simple |
P2 signe |
1 if, 1 elif |
3 | Simple |
P3 notes_valides |
1 for, 1 if (dans la compréhension) |
3 | Simple |
P4 mention |
1 for, 1 if |
3 | Simple |
P5 analyser_mot_de_passe |
2 for, 8 if, 2 elif, 2 and, 1 ternaire |
16 | Modéré |
Détail de P5 :
| Ligne | Décision | +1 |
|---|---|---|
if len(mdp) < 12 |
if |
1 |
for c in mdp |
for |
2 |
if c.isupper() |
if |
3 |
elif c.islower() |
elif |
4 |
elif c.isdigit() |
elif |
5 |
if not (majuscule and minuscule) |
if + and |
7 |
if not chiffre |
if |
8 |
if not special |
if |
9 |
if login and login.lower() in mdp.lower() |
if + and |
11 |
for i in range(len(mdp) - 2) |
for |
12 |
if mdp[i] == mdp[i + 1] == mdp[i + 2] |
if |
13 |
if not problemes |
if |
14 |
"moyen" if len(problemes) <= 2 else "faible" |
ternaire | 15 |
M = 15 + 1 = 16. Le else final de la cascade if/elif/else et le break ne comptent pas. Comme pour P3, la comparaison chaînée mdp[i] == mdp[i + 1] == mdp[i + 2] est comptée comme une seule condition.
P4 a le même M que la version refactorisée de mention vue en cours : le dictionnaire remplace la cascade de if/elif (qui aurait donné M = 5).





