diff --git a/analyseur.c b/analyseur.c index 7081696..c4e1f23 100644 --- a/analyseur.c +++ b/analyseur.c @@ -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; } } diff --git a/notes.md b/notes.md index bf224f7..3160449 100644 --- a/notes.md +++ b/notes.md @@ -442,4 +442,72 @@ Empreinte du rapport : 1d53de903efd2b7c real 0m0.354s user 0m0.314s sys 0m0.008s -``` \ No newline at end of file +``` + +## 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) +``` diff --git a/out/analyseur b/out/analyseur index 3c0d275..e030422 100755 Binary files a/out/analyseur and b/out/analyseur differ