forked from menault/2026_TD1_DEV51_Qualite_Algo
Optimise la fonction d'analyse des bigrammes en réduisant les vérifications et en normalisant les lignes
This commit is contained in:
+14
-4
@@ -373,7 +373,8 @@ double ecart_type_longueur(const Entree *table, int n, double moyenne)
|
||||
}
|
||||
|
||||
/* Recherche du bigramme de lettres le plus fréquent, avec en bonus la
|
||||
* troisième lettre qui le suit le plus souvent. */
|
||||
* troisième lettre qui le suit le plus souvent.
|
||||
* Les lignes doivent être normalisées : lettres 'a' à 'z' ou espaces. */
|
||||
void analyser_bigrammes(char **lignes, int nb_lignes,
|
||||
char *meilleur, int *occ_meilleur)
|
||||
{
|
||||
@@ -381,9 +382,18 @@ void analyser_bigrammes(char **lignes, int nb_lignes,
|
||||
|
||||
for (int l = 0; l < nb_lignes; l++) {
|
||||
const char *s = lignes[l];
|
||||
for (int i = 0; s[i] != '\0' && s[i + 1] != '\0' && s[i + 2] != '\0'; i++) {
|
||||
if (est_lettre(s[i]) && est_lettre(s[i + 1]) && est_lettre(s[i + 2]))
|
||||
trigrammes[s[i] - 'a'][s[i + 1] - 'a'][s[i + 2] - 'a']++;
|
||||
int avant_dernier = -1;
|
||||
int dernier = -1;
|
||||
for (int i = 0; s[i] != '\0'; i++) {
|
||||
if (s[i] == ' ') {
|
||||
avant_dernier = dernier = -1;
|
||||
continue;
|
||||
}
|
||||
int lettre = s[i] - 'a';
|
||||
if (avant_dernier >= 0)
|
||||
trigrammes[avant_dernier][dernier][lettre]++;
|
||||
avant_dernier = dernier;
|
||||
dernier = lettre;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -442,4 +442,72 @@ Empreinte du rapport : 1d53de903efd2b7c
|
||||
real 0m0.354s
|
||||
user 0m0.314s
|
||||
sys 0m0.008s
|
||||
```
|
||||
```
|
||||
|
||||
## Réduction des vérifications dans `analyser_bigrammes`
|
||||
|
||||
L'ancienne boucle examinait des fenêtres de trois caractères et appelait
|
||||
`est_lettre` jusqu'à trois fois par fenêtre. Les caractères des fenêtres
|
||||
voisines étaient donc vérifiés plusieurs fois, pour un total de
|
||||
3 757 672 appels dans cette fonction.
|
||||
|
||||
Les lignes sont déjà normalisées avant l'analyse : elles ne contiennent
|
||||
que des lettres de `a` à `z` et des espaces. La nouvelle boucle utilise
|
||||
cette propriété, explicitée dans le commentaire de la fonction, et
|
||||
conserve les indices des deux lettres précédentes. Chaque nouvelle lettre
|
||||
complète un trigramme si deux lettres la précèdent. Un espace ou une
|
||||
nouvelle ligne réinitialise cet historique.
|
||||
|
||||
Les trigrammes qui se chevauchent sont conservés, sans compter à travers
|
||||
les séparateurs. Le calcul du meilleur bigramme et les règles de départage
|
||||
restent identiques. Les deux versions sont en O(nombre de caractères) :
|
||||
le gain vient des vérifications et des appels évités, sans tableau
|
||||
supplémentaire.
|
||||
|
||||
Profil enregistré dans [out/profil_apres_bigrammes.txt](out/profil_apres_bigrammes.txt).
|
||||
La comparaison porte sur la version précédente, décrite dans
|
||||
`out/profil_apres_tri.txt`.
|
||||
|
||||
| Mesure | Avant | Après |
|
||||
| --- | ---: | ---: |
|
||||
| Appels à `est_lettre` depuis `analyser_bigrammes` | 3 757 672 | 0 |
|
||||
| Appels à `est_lettre` dans tout le programme | 5 297 256 | 1 539 584 |
|
||||
| Temps réel médian sans profiling (`gcc -O0`, 10 exécutions par version) | 0,1252 s | 0,1123 s |
|
||||
|
||||
Le gain médian mesuré est de 10,3 %. Les exécutions sont courtes et les
|
||||
temps fluctuent ; cette valeur est indicative. Les mesures ont été faites
|
||||
en alternant les deux versions sur la même machine :
|
||||
|
||||
- Avant : 0,1339 / 0,1132 / 0,1220 / 0,1146 / 0,1403 / 0,1118 / 0,1268 /
|
||||
0,1235 / 0,1430 / 0,1373 s.
|
||||
- Après : 0,1332 / 0,1035 / 0,1077 / 0,1133 / 0,1178 / 0,1131 / 0,1095 /
|
||||
0,0994 / 0,1114 / 0,1193 s.
|
||||
|
||||
Validation : compilation sans avertissement avec `-Wall -Wextra -Wpedantic`,
|
||||
rapport et sortie console identiques octet par octet sur les vingt
|
||||
exécutions, avec `-pg` et sous AddressSanitizer et UndefinedBehaviorSanitizer.
|
||||
L'empreinte reste **`1d53de903efd2b7c`**. Le bigramme reste `me`, avec
|
||||
17 607 occurrences et `n` comme troisième lettre la plus fréquente.
|
||||
Un test temporaire a comparé 43 cas à l'ancienne fonction : entrées vides
|
||||
ou courtes, chevauchements, espaces, changements de ligne, égalités,
|
||||
normalisation et données pseudo-aléatoires.
|
||||
|
||||
Autres pistes, à mesurer séparément :
|
||||
|
||||
- `est_mot_vide` provoque encore 12 045 671 appels à `egales`. Réutiliser
|
||||
la longueur `k` pour exclure les mots plus longs que tous les mots vides,
|
||||
puis consulter un index de hachage séparé, reste la priorité. L'ordre
|
||||
du tableau `MOTS_VIDES`, utilisé pour générer le texte, doit être conservé.
|
||||
- `normaliser_ligne` pourrait utiliser une table de conversion des octets
|
||||
en minuscules ou espaces, pour regrouper classification et conversion.
|
||||
- `decouper_lignes` pourrait utiliser des pointeurs dans le texte et
|
||||
remplacer les sauts de ligne par `\0`, évitant les allocations et copies
|
||||
par ligne. La libération de la mémoire devrait être adaptée en conséquence.
|
||||
|
||||
Commandes pour reproduire ce profil :
|
||||
|
||||
```bash
|
||||
mkdir -p out/apres_bigrammes
|
||||
gcc -O0 -pg analyseur.c -o out/apres_bigrammes/analyseur
|
||||
(cd out/apres_bigrammes && ./analyseur && gprof -b ./analyseur gmon.out > ../profil_apres_bigrammes.txt)
|
||||
```
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user