Optimise la fonction d'analyse des bigrammes en réduisant les vérifications et en normalisant les lignes

This commit is contained in:
rabot
2026-10-07 13:49:42 +02:00
parent 2878461ebd
commit e3076e46aa
3 changed files with 83 additions and 5 deletions
+14 -4
View File
@@ -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;
}
}
+69 -1
View File
@@ -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)
```
BIN
View File
Binary file not shown.