première opti

This commit is contained in:
2026-10-07 11:48:38 +02:00
parent b5ac7a3c89
commit 5f9c5eec33
58 changed files with 6391 additions and 25183 deletions
-203
View File
@@ -1,203 +0,0 @@
# TD R5.A.04 — Profiling avec gprof
## Objectif et environnement
Analyser l'analyseur de fréquence de mots, identifier les coûts, optimiser une
chose à la fois et conserver exactement les résultats. Travail réalisé le
7 octobre 2026 dans le fork local existant `couchot/2026_TD1_DEV51_Qualite_Algo`.
Les commits sont locaux ; aucun envoi au serveur n'a été effectué.
- Linux x86_64, Intel Core i7-8700 à 3,20 GHz, 12 processeurs logiques.
- GCC 16.2.1, outils GNU `time` et `gprof`.
- Même scénario : 250 000 mots, vocabulaire de 7 000 mots, graine `20261006UL`.
- Toutes les comparaisons utilisent `-O0 -g`, conformément au TD.
- Trois exécutions sans `-pg` par version ; médiane du temps réel retenue.
- Le pic mémoire est le maximum de mémoire résidente indiqué par GNU `time`
(`%M`, en Kio), et non une mesure des allocations totales.
La source initiale est conservée dans `mesures/analyseur_avant.c`. Les sorties,
mesures brutes et le rapport initial sont dans `mesures/`.
## 1. Mesurer avant d'optimiser
```sh
gcc -O0 -g -Wall -Wextra analyseur.c -o analyseur
/usr/bin/time -f 'reel=%e utilisateur=%U systeme=%S memoire_Kio=%M' ./analyseur
```
Avant modification : temps réels **3,14 / 3,01 / 2,91 s**, médiane **3,01 s** ;
temps utilisateur **3,09 / 2,99 / 2,89 s**, médiane **2,99 s**.
Pic mémoire médian : **6 668 Kio**.
Résultats de référence :
- 21 746 lignes, 250 000 mots, 5 866 mots distincts.
- Longueur moyenne : 6,712 ; écart-type : 1,873.
- Bigramme `me` : 17 607 occurrences, souvent suivi de `n`.
- Premier mot : `rane`, 287 occurrences.
- Empreinte : **`1d53de903efd2b7c`**.
## 2. Profiler
```sh
gcc -O0 -g -pg analyseur.c -o analyseur
/usr/bin/time ./analyseur
mv gmon.out gmon_avant.out
gprof -b ./analyseur gmon_avant.out > profil_avant.txt
```
Les binaires et `gmon` avant/après ont été conservés séparément pendant le travail
pour ne pas analyser un ancien profil avec un nouveau binaire. Les profils texte
sont versionnés ; les binaires et fichiers `gmon` sont reproductibles et ignorés.
Avec instrumentation, avant : **6,64 s réelles**, **6,58 s utilisateur**.
Le profil plat cumule **2,71 s échantillonnées**. Ces valeurs ne sont pas
interchangeables : instrumentation, échantillonnage, appels de bibliothèque
non instrumentés et attentes influencent les mesures. Le gain global est donc
calculé sur les exécutions sans instrumentation.
## 3. Analyser le profil plat et le graphe d'appels
| Fonction | Temps propre | Part du profil | Appels |
|---|---:|---:|---:|
| `longueur` | 0,92 s | 33,76 % | 36 009 819 |
| `egales` | 0,89 s | 32,84 % | 308 701 874 |
| `chercher_mot` | 0,37 s | 13,65 % | 150 182 |
| `comparer` | 0,12 s | 4,61 % | 12 172 087 |
| `longueur_moyenne` | 0,11 s | 4,06 % | 5 867 |
| `doit_echanger` | 0,05 s | 1,85 % | 17 202 045 |
Le graphe explique les appels :
1. `main → compter_mots_ligne → compter_mot → chercher_mot → egales`.
`chercher_mot` provoque **296 656 203** comparaisons, car il parcourt les
entrées déjà connues pour chaque mot retenu. Coût O(M × U), avec M le nombre
de mots non vides et U le nombre de mots distincts.
2. `main → ecart_type_longueur → longueur_moyenne → longueur`.
La moyenne est recalculée **5 866 fois** dans la boucle de variance :
**34 415 822** appels à `longueur` viennent du calcul de moyenne.
Les statistiques sont inutilement O(U²).
3. `main → trier_entrees → doit_echanger → comparer`.
Le tri à bulles effectue U(U−1)/2 = **17 202 045** comparaisons, même sans
nécessité d'échanger : O(U²).
4. `normaliser_ligne → longueur` : **1 561 330** appels.
La longueur est parcourue à chaque condition de boucle : O(L²) par ligne.
5. `construire_rapport → ajouter → longueur` : **5 867** appels à `ajouter`.
Chaque ajout reparcourt tout le rapport déjà construit. Pour une longueur
moyenne de ligne bornée, le coût devient O(U²).
Le graphe attribue environ 45,2 % du temps cumulé à `chercher_mot`, 36,3 % à la
variance et 7,6 % au tri. Ce sont des estimations : gprof répartit le temps d'un
appelé entre ses parents en proportion du nombre d'appels. Un appel à `longueur`
sur un rapport de milliers de caractères coûte bien davantage qu'un appel sur
un mot ; cette répartition peut donc sous-estimer la construction du rapport.
Un temps affiché à 0,00 s ne signifie pas un coût nul.
## 4. Pistes proposées, classées par gain attendu
1. Indexer les mots par hachage : supprimer les centaines de millions de
comparaisons linéaires. Gain attendu très élevé.
2. Calculer la moyenne une seule fois avant la boucle de variance : supprimer
un parcours complet par mot distinct. Gain attendu élevé.
3. Remplacer le tri à bulles par un tri en O(U log U). Gain attendu important.
4. Normaliser les lignes en un seul parcours. Gain attendu plus modéré.
5. Conserver la position d'écriture dans le rapport. Gain potentiellement
important malgré son faible poids apparent dans le graphe d'appels.
6. Ensuite, indexer les mots vides ou filtrer par longueur avant comparaison.
Piste laissée pour une seconde itération : le profil final permet d'en
évaluer la priorité. Compiler en `-O2` serait aussi utile pour un produit
livré, mais ferait varier un autre facteur que les algorithmes dans ce TD.
## 5. Optimisations réalisées et mesures intermédiaires
Chaque ligne ajoute une seule optimisation à la version précédente. Chaque
version a été compilée avec `-Wall -Wextra` sans avertissement et exécutée trois
fois. Le rapport et la sortie standard ont été comparés octet par octet à la
référence après chaque exécution.
| Version cumulative | Commit | Temps réels (s) | Médiane (s) | Gain sur l'étape précédente |
|---|---|---|---:|---:|
| Initiale | `6165b37` | 3,14 / 3,01 / 2,91 | 3,01 | — |
| Index de hachage | `2db740d` | 1,50 / 1,48 / 1,47 | 1,48 | 50,8 % |
| Moyenne hors boucle | `5d71287` | 0,88 / 0,90 / 0,86 | 0,88 | 40,5 % |
| Tri fusion | `dddcfd4` | 0,67 / 0,62 / 0,61 | 0,62 | 29,5 % |
| Normalisation linéaire | `6ab37d6` | 0,47 / 0,46 / 0,47 | 0,47 | 24,2 % |
| Position d'écriture du rapport | `1d07578` | 0,18 / 0,14 / 0,20 | 0,18 | 61,7 % |
Détails et compromis :
- **Hachage** : 65 536 cases, indices vers les entrées et sondage linéaire
pour résoudre les collisions. Une égalité de hachage ne suffit jamais : les
chaînes sont comparées. L'ordre d'insertion des entrées est conservé.
Charge de 9 % sur ce scénario, au plus 31 % pour 20 000 entrées ; environ
**256 Kio** supplémentaires. Recherche en O(1) en moyenne, O(U) au pire.
L'index sert au comptage et n'est plus consulté après le tri.
- **Variance** : la moyenne ne dépend pas de l'indice ; la calculer avant la
boucle ramène le calcul à O(U), en conservant l'ordre de sommation flottante.
- **Tri fusion** : même ordre, occurrences décroissantes puis mots croissants.
O(U log U) garanti, tampon temporaire O(U), soit **211 176 octets** ici.
- **Normalisation** : arrêt sur le caractère nul, O(L) sans parcours répétés.
- **Rapport** : écriture directe à l'offset courant avec `snprintf` et contrôle
de la capacité. Travail proportionnel à la taille produite, sans rescan du
préfixe et sans buffer de ligne intermédiaire.
## 6. Re-profiler et valider
Le profil final est dans `profil_apres.txt` :
| Indicateur gprof | Avant | Après |
|---|---:|---:|
| Appels à `egales` | 308 701 874 | 12 195 414 |
| Appels à `longueur` | 36 009 819 | 38 532 |
| Appels à `longueur_moyenne` | 5 867 | 2 |
| Appels à `doit_echanger` | 17 202 045 | 66 114 |
| Appels à `comparer` | 12 172 087 | 33 591 |
| Temps propre total échantillonné | 2,71 s | 0,14 s |
| Temps réel instrumenté | 6,64 s | 0,34 s |
Après optimisation, `egales` représente 60,71 % du profil, essentiellement
pour la recherche des mots vides : celle-ci conserve **12 045 671** appels.
L'index des mots ne provoque plus que **149 743** appels à `egales`.
`analyser_bigrammes` représente 14,29 %. Sur seulement environ 14 échantillons,
ces pourcentages sont peu précis ; les nombres d'appels restent plus utiles.
La récursion du tri fusion est présentée de manière spécifique par gprof :
le chiffre 1 du profil plat n'est pas le nombre total d'invocations récursives.
Sans instrumentation : **3,01 / 0,18 = 16,72**, soit un programme environ
**16,7 fois plus rapide** et une réduction du temps réel de **94,0 %**.
La médiane du temps utilisateur passe de **2,99 à 0,12 s** (réduction de 96,0 %).
Le pic mémoire médian passe de **6 668 à 6 980 Kio** (+312 Kio, soit +4,7 %).
Les pics mesurés reflètent les allocations touchées et l'allocateur ; ils ne
sont pas la somme des tailles théoriques des structures.
L'empreinte reste **`1d53de903efd2b7c`** à toutes les étapes. La comparaison
binaire confirme aussi l'identité du rapport complet et de toute la sortie,
notamment des statistiques que l'empreinte du rapport ne couvre pas.
AddressSanitizer et UndefinedBehaviorSanitizer n'ont signalé aucune erreur sur
le scénario du TD. LeakSanitizer ne fonctionne pas sous le traçage de cet
environnement ; la vérification a donc été relancée avec
`ASAN_OPTIONS=detect_leaks=0`. L'absence de fuite n'est pas certifiée par ce test.
## Reproduire
Depuis la racine du dépôt, avec GCC, GNU time, gprof et Python 3 :
```sh
python3 reproduire_mesures.py
```
Le script compile les sources avant/après, mesure trois exécutions de chacune,
compare rapports et sorties, puis produit les profils dans un nouveau dossier
`mesures_reproduction/`. Il refuse d'écraser un dossier existant ; utiliser
`--destination /tmp/autre_mesure` pour une nouvelle campagne. Il a également
été exécuté intégralement pour vérifier son fonctionnement : cette seconde
campagne donne des médianes de **2,88 s avant et 0,11 s après** (environ ×26,2).
Les fichiers texte correspondants sont conservés dans `mesures/verification/`.
La variation du gain confirme la sensibilité des mesures courtes ; le bilan
principal utilise les mesures de la première campagne, sans mélanger les deux.
Les chiffres dépendent de cette machine, de sa charge et de ce scénario.
Les versions finales étant courtes, les variations relatives sont plus fortes
(0,14 à 0,20 s). Une campagne plus longue et un scénario représentatif seraient
nécessaires pour généraliser ces gains à d'autres usages.
+10 -8
View File
@@ -22,7 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#define NB_MOTS_TEXTE 250000
#define NB_MOTS_TEXTE 2500000
#define NB_MOTS_VOCAB 7000
#define TAILLE_MOT 32
#define MAX_MOTS_UNIQUES 20000
@@ -32,6 +32,7 @@
/* Générateur pseudo-aléatoire (identique sur toutes les machines) */
/* ------------------------------------------------------------------------ */
static unsigned long etat_alea = GRAINE;
unsigned long alea(void)
@@ -224,6 +225,7 @@ void normaliser_ligne(char *ligne)
typedef struct {
char mot[TAILLE_MOT];
int occurrences;
int longueur_mot;
} Entree;
int est_mot_vide(const char *mot)
@@ -260,7 +262,7 @@ int chercher_mot(Entree *table, const char *mot, unsigned long *case_libre)
return -1;
}
void compter_mot(Entree *table, int *nb_entrees, const char *mot)
void compter_mot(Entree *table, int *nb_entrees, const char *mot, int longueur_mot)
{
/* Réinitialisation possible pour un nouveau comptage. */
if (*nb_entrees == 0)
@@ -277,6 +279,7 @@ void compter_mot(Entree *table, int *nb_entrees, const char *mot)
}
copier(table[*nb_entrees].mot, mot);
table[*nb_entrees].occurrences = 1;
table[*nb_entrees].longueur_mot = longueur_mot;
index_mots[position] = *nb_entrees + 1;
(*nb_entrees)++;
}
@@ -301,7 +304,7 @@ void compter_mots_ligne(Entree *table, int *nb_entrees, const char *ligne,
if (k > 0) {
(*nb_mots_total)++;
if (!est_mot_vide(mot))
compter_mot(table, nb_entrees, mot);
compter_mot(table, nb_entrees, mot, k);
}
}
}
@@ -358,16 +361,15 @@ double longueur_moyenne(const Entree *table, int n)
{
long total = 0;
for (int i = 0; i < n; i++)
total += longueur(table[i].mot);
total += table[i].longueur_mot;
return (double)total / n;
}
double ecart_type_longueur(const Entree *table, int n)
double ecart_type_longueur(const Entree *table, int n, double moyenne)
{
double somme = 0.0;
double moyenne = longueur_moyenne(table, n);
for (int i = 0; i < n; i++) {
double ecart = longueur(table[i].mot) - moyenne;
double ecart = table[i].longueur_mot - moyenne;
somme += ecart * ecart;
}
return somme / n; /* variance ; la racine est prise dans main */
@@ -474,7 +476,7 @@ int main(void)
trier_entrees(table, nb_entrees);
double moyenne = longueur_moyenne(table, nb_entrees);
double ecart_type = racine(ecart_type_longueur(table, nb_entrees));
double ecart_type = racine(ecart_type_longueur(table, nb_entrees, moyenne));
char trigramme[4];
int occ_trigramme;
-457
View File
@@ -1,457 +0,0 @@
/*
* R5.A.04 - Qualité Algorithmique
* TD Profiling : analyseur de fréquence de mots
*
* Le programme génère un texte pseudo-aléatoire (toujours le même, grâce
* à une graine fixe), puis :
* 1. découpe le texte en lignes et le normalise (minuscules, ponctuation)
* 2. compte les occurrences de chaque mot (hors mots vides)
* 3. trie les mots par fréquence
* 4. calcule des statistiques sur la longueur des mots
* 5. analyse les bigrammes de lettres
* 6. génère un rapport complet dans rapport.txt
*
* L'empreinte affichée à la fin doit rester IDENTIQUE après optimisation :
* elle prouve que le résultat du programme n'a pas changé.
*
* Compilation : gcc -O0 -g -pg analyseur.c -o analyseur
* Exécution : ./analyseur
* Profil : gprof ./analyseur gmon.out > profil.txt
*/
#include <stdio.h>
#include <stdlib.h>
#define NB_MOTS_TEXTE 250000
#define NB_MOTS_VOCAB 7000
#define TAILLE_MOT 32
#define MAX_MOTS_UNIQUES 20000
#define GRAINE 20261006UL
/* ------------------------------------------------------------------------ */
/* Générateur pseudo-aléatoire (identique sur toutes les machines) */
/* ------------------------------------------------------------------------ */
static unsigned long etat_alea = GRAINE;
unsigned long alea(void)
{
etat_alea = etat_alea * 6364136223846793005UL + 1442695040888963407UL;
return etat_alea >> 33;
}
/* ------------------------------------------------------------------------ */
/* Fonctions utilitaires sur les chaînes */
/* ------------------------------------------------------------------------ */
int longueur(const char *s)
{
int n = 0;
while (s[n] != '\0')
n++;
return n;
}
void copier(char *dest, const char *src)
{
int i = 0;
while (src[i] != '\0') {
dest[i] = src[i];
i++;
}
dest[i] = '\0';
}
int egales(const char *a, const char *b)
{
int i = 0;
while (a[i] != '\0' && b[i] != '\0') {
if (a[i] != b[i])
return 0;
i++;
}
return a[i] == b[i];
}
int comparer(const char *a, const char *b)
{
int i = 0;
while (a[i] != '\0' && a[i] == b[i])
i++;
return (unsigned char)a[i] - (unsigned char)b[i];
}
void ajouter(char *dest, const char *src)
{
copier(dest + longueur(dest), src);
}
char en_minuscule(char c)
{
if (c >= 'A' && c <= 'Z')
return c - 'A' + 'a';
return c;
}
int est_lettre(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
/* ------------------------------------------------------------------------ */
/* Génération du texte */
/* ------------------------------------------------------------------------ */
static const char *MOTS_VIDES[] = {
"le", "la", "les", "un", "une", "des", "du", "de", "et", "ou",
"mais", "donc", "or", "ni", "car", "que", "qui", "quoi", "dont", "ou",
"a", "au", "aux", "en", "dans", "par", "pour", "sur", "sous", "avec",
"sans", "chez", "vers", "entre", "il", "elle", "ils", "elles", "on", "nous",
"vous", "je", "tu", "se", "ce", "cet", "cette", "ces", "son", "sa",
"ses", "leur", "leurs", "mon", "ma", "mes", "ne", "pas", "plus", "est"
};
#define NB_MOTS_VIDES ((int)(sizeof(MOTS_VIDES) / sizeof(MOTS_VIDES[0])))
static const char *SYLLABES[] = {
"ba", "be", "bi", "bo", "ca", "co", "da", "de", "di", "fa", "fi", "ga",
"go", "la", "le", "li", "lo", "ma", "me", "mi", "mo", "na", "ne", "no",
"pa", "pe", "pi", "po", "ra", "re", "ri", "ro", "sa", "se", "si", "so",
"ta", "te", "ti", "to", "va", "ve", "vi", "vo", "tion", "ment", "eur", "ique"
};
#define NB_SYLLABES ((int)(sizeof(SYLLABES) / sizeof(SYLLABES[0])))
char **generer_vocabulaire(void)
{
char **vocab = malloc(NB_MOTS_VOCAB * sizeof(char *));
for (int i = 0; i < NB_MOTS_VOCAB; i++) {
vocab[i] = malloc(TAILLE_MOT);
vocab[i][0] = '\0';
int nb_syllabes = 2 + alea() % 3;
for (int j = 0; j < nb_syllabes; j++)
ajouter(vocab[i], SYLLABES[alea() % NB_SYLLABES]);
}
return vocab;
}
char *generer_texte(char **vocab, int nb_mots)
{
char *texte = malloc((size_t)nb_mots * (TAILLE_MOT + 2) + 1);
long pos = 0;
int debut_phrase = 1;
int mots_restants_phrase = 8 + alea() % 8;
for (int i = 0; i < nb_mots; i++) {
const char *mot;
if (alea() % 100 < 40) {
mot = MOTS_VIDES[alea() % NB_MOTS_VIDES];
} else {
/* distribution biaisée : certains mots sont bien plus fréquents */
unsigned long r1 = alea() % NB_MOTS_VOCAB;
unsigned long r2 = alea() % NB_MOTS_VOCAB;
mot = vocab[(r1 * r2) / NB_MOTS_VOCAB];
}
for (int j = 0; mot[j] != '\0'; j++) {
char c = mot[j];
if (debut_phrase && j == 0)
c = c - 'a' + 'A';
texte[pos++] = c;
}
debut_phrase = 0;
mots_restants_phrase--;
if (mots_restants_phrase == 0) {
texte[pos++] = '.';
texte[pos++] = '\n';
debut_phrase = 1;
mots_restants_phrase = 8 + alea() % 8;
} else if (alea() % 10 == 0) {
texte[pos++] = ',';
texte[pos++] = ' ';
} else {
texte[pos++] = ' ';
}
}
texte[pos++] = '\n';
texte[pos] = '\0';
return texte;
}
/* ------------------------------------------------------------------------ */
/* Découpage et normalisation */
/* ------------------------------------------------------------------------ */
char **decouper_lignes(const char *texte, int *nb_lignes)
{
int capacite = 1024;
char **lignes = malloc(capacite * sizeof(char *));
int n = 0;
int debut = 0;
for (int i = 0; texte[i] != '\0'; i++) {
if (texte[i] == '\n') {
int taille = i - debut;
if (n == capacite) {
capacite *= 2;
lignes = realloc(lignes, capacite * sizeof(char *));
}
lignes[n] = malloc(taille + 1);
for (int j = 0; j < taille; j++)
lignes[n][j] = texte[debut + j];
lignes[n][taille] = '\0';
n++;
debut = i + 1;
}
}
*nb_lignes = n;
return lignes;
}
void normaliser_ligne(char *ligne)
{
for (int i = 0; i < longueur(ligne); i++) {
if (est_lettre(ligne[i]))
ligne[i] = en_minuscule(ligne[i]);
else
ligne[i] = ' ';
}
}
/* ------------------------------------------------------------------------ */
/* Comptage des mots */
/* ------------------------------------------------------------------------ */
typedef struct {
char mot[TAILLE_MOT];
int occurrences;
} Entree;
int est_mot_vide(const char *mot)
{
for (int i = 0; i < NB_MOTS_VIDES; i++) {
if (egales(mot, MOTS_VIDES[i]))
return 1;
}
return 0;
}
int chercher_mot(Entree *table, int nb_entrees, const char *mot)
{
for (int i = 0; i < nb_entrees; i++) {
if (egales(table[i].mot, mot))
return i;
}
return -1;
}
void compter_mot(Entree *table, int *nb_entrees, const char *mot)
{
int indice = chercher_mot(table, *nb_entrees, mot);
if (indice >= 0) {
table[indice].occurrences++;
} else {
copier(table[*nb_entrees].mot, mot);
table[*nb_entrees].occurrences = 1;
(*nb_entrees)++;
}
}
void compter_mots_ligne(Entree *table, int *nb_entrees, const char *ligne,
long *nb_mots_total)
{
char mot[TAILLE_MOT];
int i = 0;
while (ligne[i] != '\0') {
while (ligne[i] == ' ')
i++;
int k = 0;
while (ligne[i] != '\0' && ligne[i] != ' ') {
if (k < TAILLE_MOT - 1)
mot[k++] = ligne[i];
i++;
}
mot[k] = '\0';
if (k > 0) {
(*nb_mots_total)++;
if (!est_mot_vide(mot))
compter_mot(table, nb_entrees, mot);
}
}
}
/* ------------------------------------------------------------------------ */
/* Tri : par nombre d'occurrences décroissant, puis ordre alphabétique */
/* ------------------------------------------------------------------------ */
int doit_echanger(const Entree *a, const Entree *b)
{
if (a->occurrences != b->occurrences)
return a->occurrences < b->occurrences;
return comparer(a->mot, b->mot) > 0;
}
void trier_entrees(Entree *table, int n)
{
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (doit_echanger(&table[j], &table[j + 1])) {
Entree tmp = table[j];
table[j] = table[j + 1];
table[j + 1] = tmp;
}
}
}
}
/* ------------------------------------------------------------------------ */
/* Statistiques */
/* ------------------------------------------------------------------------ */
double longueur_moyenne(const Entree *table, int n)
{
long total = 0;
for (int i = 0; i < n; i++)
total += longueur(table[i].mot);
return (double)total / n;
}
double ecart_type_longueur(const Entree *table, int n)
{
double somme = 0.0;
for (int i = 0; i < n; i++) {
double ecart = longueur(table[i].mot) - longueur_moyenne(table, n);
somme += ecart * ecart;
}
return somme / n; /* variance ; la racine est prise dans main */
}
/* Recherche du bigramme de lettres le plus fréquent, avec en bonus la
* troisième lettre qui le suit le plus souvent. */
void analyser_bigrammes(char **lignes, int nb_lignes,
char *meilleur, int *occ_meilleur)
{
static int trigrammes[26][26][26];
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']++;
}
}
*occ_meilleur = -1;
for (int a = 0; a < 26; a++) {
for (int b = 0; b < 26; b++) {
int total = 0;
for (int c = 0; c < 26; c++)
total += trigrammes[a][b][c];
if (total > *occ_meilleur) {
*occ_meilleur = total;
int meilleur_c = 0;
for (int c = 1; c < 26; c++)
if (trigrammes[a][b][c] > trigrammes[a][b][meilleur_c])
meilleur_c = c;
meilleur[0] = 'a' + a;
meilleur[1] = 'a' + b;
meilleur[2] = 'a' + meilleur_c;
meilleur[3] = '\0';
}
}
}
}
/* ------------------------------------------------------------------------ */
/* Rapport */
/* ------------------------------------------------------------------------ */
char *construire_rapport(const Entree *table, int n)
{
char *rapport = malloc((size_t)n * 64 + 256);
char ligne[128];
rapport[0] = '\0';
ajouter(rapport, "rang;mot;occurrences\n");
for (int i = 0; i < n; i++) {
snprintf(ligne, sizeof(ligne), "%d;%s;%d\n",
i + 1, table[i].mot, table[i].occurrences);
ajouter(rapport, ligne);
}
return rapport;
}
unsigned long empreinte(const char *s)
{
unsigned long h = 1469598103934665603UL;
for (int i = 0; s[i] != '\0'; i++) {
h ^= (unsigned char)s[i];
h *= 1099511628211UL;
}
return h;
}
/* ------------------------------------------------------------------------ */
double racine(double x)
{
double r = x > 1.0 ? x : 1.0;
for (int i = 0; i < 50; i++)
r = 0.5 * (r + x / r);
return r;
}
int main(void)
{
char **vocab = generer_vocabulaire();
char *texte = generer_texte(vocab, NB_MOTS_TEXTE);
int nb_lignes;
char **lignes = decouper_lignes(texte, &nb_lignes);
for (int i = 0; i < nb_lignes; i++)
normaliser_ligne(lignes[i]);
Entree *table = malloc(MAX_MOTS_UNIQUES * sizeof(Entree));
int nb_entrees = 0;
long nb_mots_total = 0;
for (int i = 0; i < nb_lignes; i++)
compter_mots_ligne(table, &nb_entrees, lignes[i], &nb_mots_total);
trier_entrees(table, nb_entrees);
double moyenne = longueur_moyenne(table, nb_entrees);
double ecart_type = racine(ecart_type_longueur(table, nb_entrees));
char trigramme[4];
int occ_trigramme;
analyser_bigrammes(lignes, nb_lignes, trigramme, &occ_trigramme);
char *rapport = construire_rapport(table, nb_entrees);
FILE *f = fopen("rapport.txt", "w");
if (f != NULL) {
fputs(rapport, f);
fclose(f);
}
printf("Lignes analysées : %d\n", nb_lignes);
printf("Mots au total : %ld\n", nb_mots_total);
printf("Mots distincts : %d\n", nb_entrees);
printf("Longueur moyenne : %.3f (écart-type %.3f)\n", moyenne, ecart_type);
printf("Bigramme le + courant : \"%c%c\" (%d fois, souvent suivi de '%c')\n",
trigramme[0], trigramme[1], occ_trigramme, trigramme[2]);
printf("\nTop 10 :\n");
for (int i = 0; i < 10 && i < nb_entrees; i++)
printf(" %2d. %-16s %d\n", i + 1, table[i].mot, table[i].occurrences);
printf("\nEmpreinte du rapport : %016lx\n", empreinte(rapport));
free(rapport);
free(table);
for (int i = 0; i < nb_lignes; i++)
free(lignes[i]);
free(lignes);
free(texte);
for (int i = 0; i < NB_MOTS_VOCAB; i++)
free(vocab[i]);
free(vocab);
return 0;
}
File diff suppressed because it is too large Load Diff
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-1
View File
@@ -1 +0,0 @@
reel=0.34 utilisateur=0.29 systeme=0.00 memoire_Kio=7028
-1
View File
@@ -1 +0,0 @@
reel=3.14 utilisateur=3.09 systeme=0.00 memoire_Kio=6668
-1
View File
@@ -1 +0,0 @@
reel=3.01 utilisateur=2.99 systeme=0.00 memoire_Kio=6692
-1
View File
@@ -1 +0,0 @@
reel=2.91 utilisateur=2.89 systeme=0.00 memoire_Kio=6548
-1
View File
@@ -1 +0,0 @@
reel=6.64 utilisateur=6.58 systeme=0.00 memoire_Kio=6580
-1
View File
@@ -1 +0,0 @@
reel=1.50 utilisateur=1.47 systeme=0.00 memoire_Kio=6940
-1
View File
@@ -1 +0,0 @@
reel=1.48 utilisateur=1.45 systeme=0.00 memoire_Kio=6940
-1
View File
@@ -1 +0,0 @@
reel=1.47 utilisateur=1.43 systeme=0.00 memoire_Kio=6932
-1
View File
@@ -1 +0,0 @@
reel=0.88 utilisateur=0.85 systeme=0.00 memoire_Kio=6948
-1
View File
@@ -1 +0,0 @@
reel=0.90 utilisateur=0.87 systeme=0.00 memoire_Kio=6948
-1
View File
@@ -1 +0,0 @@
reel=0.86 utilisateur=0.84 systeme=0.00 memoire_Kio=6948
-1
View File
@@ -1 +0,0 @@
reel=0.67 utilisateur=0.63 systeme=0.00 memoire_Kio=6988
-1
View File
@@ -1 +0,0 @@
reel=0.62 utilisateur=0.60 systeme=0.00 memoire_Kio=6872
-1
View File
@@ -1 +0,0 @@
reel=0.61 utilisateur=0.59 systeme=0.00 memoire_Kio=7004
-1
View File
@@ -1 +0,0 @@
reel=0.47 utilisateur=0.45 systeme=0.00 memoire_Kio=7008
-1
View File
@@ -1 +0,0 @@
reel=0.46 utilisateur=0.44 systeme=0.00 memoire_Kio=7008
-1
View File
@@ -1 +0,0 @@
reel=0.47 utilisateur=0.44 systeme=0.00 memoire_Kio=6992
-1
View File
@@ -1 +0,0 @@
reel=0.18 utilisateur=0.15 systeme=0.00 memoire_Kio=7004
-1
View File
@@ -1 +0,0 @@
reel=0.14 utilisateur=0.12 systeme=0.00 memoire_Kio=6940
-1
View File
@@ -1 +0,0 @@
reel=0.20 utilisateur=0.12 systeme=0.00 memoire_Kio=6980
File diff suppressed because it is too large Load Diff
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-1
View File
@@ -1 +0,0 @@
reel=0.11 utilisateur=0.11 systeme=0.00 memoire_Kio=6972
-1
View File
@@ -1 +0,0 @@
reel=0.11 utilisateur=0.11 systeme=0.00 memoire_Kio=6984
-1
View File
@@ -1 +0,0 @@
reel=0.11 utilisateur=0.10 systeme=0.00 memoire_Kio=6988
-1
View File
@@ -1 +0,0 @@
reel=0.26 utilisateur=0.26 systeme=0.00 memoire_Kio=6996
File diff suppressed because it is too large Load Diff
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-19
View File
@@ -1,19 +0,0 @@
Lignes analysées : 21746
Mots au total : 250000
Mots distincts : 5866
Longueur moyenne : 6.712 (écart-type 1.873)
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
Top 10 :
1. rane 287
2. fasi 241
3. tata 219
4. mopo 214
5. cofi 180
6. vesi 179
7. laganomo 177
8. boto 172
9. nopebo 169
10. rotion 165
Empreinte du rapport : 1d53de903efd2b7c
-1
View File
@@ -1 +0,0 @@
reel=2.90 utilisateur=2.89 systeme=0.00 memoire_Kio=6652
-1
View File
@@ -1 +0,0 @@
reel=2.88 utilisateur=2.87 systeme=0.00 memoire_Kio=6540
-1
View File
@@ -1 +0,0 @@
reel=2.84 utilisateur=2.81 systeme=0.01 memoire_Kio=6684

Some files were not shown because too many files have changed in this diff Show More