diff --git a/COMPTE_RENDU.md b/COMPTE_RENDU.md new file mode 100644 index 0000000..a80b68b --- /dev/null +++ b/COMPTE_RENDU.md @@ -0,0 +1,72 @@ +Compte-rendu TD1 : + +Nom Binome : Luka PLOUVIER et Jimmy COLOMB-RAVAT + +##1 Mesurer + +Empreinte du rapport : 1d53de903efd2b7c + +real 0m2.638s +user 0m2.613s +sys 0m0.004s + +##3 Analyser + +#profil plat : + + % cumulative self self total + time seconds seconds calls ms/call ms/call name + 39.12 0.84 0.84 308701874 0.00 0.00 egales + 32.41 1.54 0.70 36009819 0.00 0.00 longueur + 12.04 1.80 0.26 150182 0.00 0.01 chercher_mot + + La plupart du temps d'éxecution se passe par ces fonctions. + En observant le code, on se rend compte qu'il est difficile d'optimiser les fonctions 'egales' et 'longueur'. + + #Graphe d'appels + + Dans 'ecart_type_longueur' on voit qu'elle appel 'longueur_moyenne' pour chaque mots unique alors que la moyenne est déjà calculer dans le 'main'. + + 0.00 0.00 1/5867 main [1] + 0.07 0.67 5866/5867 ecart_type_longueur [7] +[6] 34.2 0.07 0.67 5867 longueur_moyenne [6] + 0.67 0.00 34415822/36009819 longueur [8] + +'longueur_moyenne' appel 34.4 millions de fois 'longueur' soit 95% des 36 millions d'appels pour 34.2% du temps total. + +'chercher_mot' fait une rechercher linéaire pour chacune des 150 182 occurences. Comme la table grandit jusqu'à 5866 entrées, c'est un comptage de mots x mots_uniques soit 296,6 millions d'appels à 'égales' sur les 308,7 millions d'appels au total. + +##4 Proposer + +Faire une table de hachage pour le comptage des mots dans 'chercher_mot'. +Calculer la moyenne une seule fois dans 'ecart_type_longueur'. + +##5 Optimiser + +39.12 0.84 0.84 308701874 0.00 0.00 egales +2.25 1.03 0.03 12195414 0.00 0.00 egales + +On peut voir que le nombre d'appels de 'egales' a diminué de 200 millions. + +real 0m1.867s +user 0m1.829s +sys 0m0.000s + +Le temps d'éxecution a diminué de 0,8 secondes. + +63.06 0.70 0.70 36009819 0.00 0.00 longueur +66.67 0.46 0.46 1605729 0.00 0.00 longueur + +9.91 0.81 0.11 5867 0.02 0.13 longueur_moyenne +0.00 0.69 0.00 2 0.00 1.68 longueur_moyenne + +On peut voir qu'on a diminué le nombre d'appels de 'longueur' de 35 millions d'appels environ en appelant que 1 seule fois 'longueur_moyenne' dans 'ecart_type_moyenne'. + +real 0m1.205s +user 0m1.167s +sys 0m0.000s + +On a encore diminué le temps d'éxecution de 0.8 secondes. + + + diff --git a/analyseur.c b/analyseur.c index 1192fd0..c29eb49 100644 --- a/analyseur.c +++ b/analyseur.c @@ -217,6 +217,16 @@ void normaliser_ligne(char *ligne) } } +#define TAILLE_HACHAGE 65536 // Puissance de 2, bien plus grand que MAX_MOTS_UNIQUES + +unsigned int hacher(const char *mot) { + unsigned int h = 5381; + for (int i = 0; mot[i] != '\0'; i++) { + h = ((h << 5) + h) + (unsigned char)mot[i]; /* équivalent à h * 33 + c */ + } + return h; +} + /* ------------------------------------------------------------------------ */ /* Comptage des mots */ /* ------------------------------------------------------------------------ */ @@ -235,29 +245,44 @@ int est_mot_vide(const char *mot) return 0; } -int chercher_mot(Entree *table, int nb_entrees, const char *mot) +int chercher_mot(Entree *table, int *table_hachage, const char *mot, int *pos_libre) { - for (int i = 0; i < nb_entrees; i++) { - if (egales(table[i].mot, mot)) - return i; + unsigned int h = hacher(mot) & (TAILLE_HACHAGE - 1); + + while (table_hachage[h] != -1) { + int indice = table_hachage[h]; + if (egales(table[indice].mot, mot)) { + return indice; // Le mot a été trouvé + } + h = (h + 1) & (TAILLE_HACHAGE - 1); // Résolution de collision (sondage linéaire) + } + + // Si on arrive ici, le mot n'est pas dans la table + if (pos_libre != NULL) { + *pos_libre = h; // On sauvegarde l'emplacement libre pour l'insertion } 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 *table_hachage) { - int indice = chercher_mot(table, *nb_entrees, mot); + int pos_libre; + int indice = chercher_mot(table, table_hachage, mot, &pos_libre); + if (indice >= 0) { table[indice].occurrences++; } else { + // Insertion du nouveau mot à la suite de la table classique copier(table[*nb_entrees].mot, mot); table[*nb_entrees].occurrences = 1; + // On mémorise son index dans la table de hachage + table_hachage[pos_libre] = *nb_entrees; (*nb_entrees)++; } } void compter_mots_ligne(Entree *table, int *nb_entrees, const char *ligne, - long *nb_mots_total) + long *nb_mots_total, int *table_hachage) { char mot[TAILLE_MOT]; int i = 0; @@ -275,7 +300,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, table_hachage); } } } @@ -319,8 +344,11 @@ double longueur_moyenne(const Entree *table, int n) double ecart_type_longueur(const Entree *table, int n) { double somme = 0.0; + // On calcule la moyenne une seule fois avant la boucle + double moyenne = longueur_moyenne(table, n); + for (int i = 0; i < n; i++) { - double ecart = longueur(table[i].mot) - longueur_moyenne(table, n); + double ecart = longueur(table[i].mot) - moyenne; somme += ecart * ecart; } return somme / n; /* variance ; la racine est prise dans main */ @@ -412,10 +440,16 @@ int main(void) normaliser_ligne(lignes[i]); Entree *table = malloc(MAX_MOTS_UNIQUES * sizeof(Entree)); + + int *table_hachage = malloc(TAILLE_HACHAGE * sizeof(int)); + for (int i = 0; i < TAILLE_HACHAGE; i++) { + table_hachage[i] = -1; // -1 indique une case vide + } + 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); + compter_mots_ligne(table, &nb_entrees, lignes[i], &nb_mots_total, table_hachage); trier_entrees(table, nb_entrees); @@ -446,6 +480,7 @@ int main(void) free(rapport); free(table); + free(table_hachage); for (int i = 0; i < nb_lignes; i++) free(lignes[i]); free(lignes);