Ajouter les statistiques de compression dans compress

This commit is contained in:
Mattéo Delabre 2016-11-19 21:40:37 +01:00
parent ec235ddea7
commit 0bddeb367c
1 changed files with 37 additions and 23 deletions

View File

@ -11,24 +11,23 @@
#include <errno.h> #include <errno.h>
/** /**
* Calculer un tableau de fréquences d'apparition des * Effectuer un comptage des caractères dans le corpus d'entrée. En déduire
* caractères ASCII dans le fichier donné. Le fichier * le tableau des fréquences d'apparition des caractères ASCII
* donné doit être ouvert au moins en lecture
* *
* (résultat à libérer avec `free`) * (résultat à libérer avec `free`)
*/ */
static double* _createFrequencies(FILE*); static double* _createFrequencies(FILE*, size_t*);
/** /**
* Encoder le fichier d'entrée vers le fichier de sortie * Encoder le fichier d'entrée vers le fichier de sortie
* en suivant les étiquettes passées. Les étiquettes * en suivant les étiquettes passées. Les étiquettes
* peuvent être calculées avec labelTree() * peuvent être calculées avec labelTree()
*/ */
void _encodeFromTable(char**, FILE*, Buffer*); static void _encodeFromTable(char**, FILE*, WriteBuffer*);
double* _createFrequencies(FILE* file) { double* _createFrequencies(FILE* file, size_t* total) {
double* frequencies = malloc(NUM_CHARS * sizeof(*frequencies)); double* frequencies = malloc(NUM_CHARS * sizeof(*frequencies));
int totalChars = 0; *total = 0;
for (size_t i = 0; i < NUM_CHARS; i++) { for (size_t i = 0; i < NUM_CHARS; i++) {
frequencies[i] = 0; frequencies[i] = 0;
@ -40,18 +39,18 @@ double* _createFrequencies(FILE* file) {
while ((current = fgetc(file)) != EOF) { while ((current = fgetc(file)) != EOF) {
assert(current >= 0 && current < NUM_CHARS); assert(current >= 0 && current < NUM_CHARS);
frequencies[current]++; frequencies[current]++;
totalChars++; (*total)++;
} }
// Conversion des effectifs des caractères en fréquences // Conversion des effectifs des caractères en fréquences
for (size_t i = 0; i < NUM_CHARS; i++) { for (size_t i = 0; i < NUM_CHARS; i++) {
frequencies[i] /= totalChars; frequencies[i] /= *total;
} }
return frequencies; return frequencies;
} }
void _encodeFromTable(char** labels, FILE* source, Buffer* output) { void _encodeFromTable(char** labels, FILE* source, WriteBuffer* output) {
int current; int current;
// Lecture du fichier d'entrée caractère par caractère // Lecture du fichier d'entrée caractère par caractère
@ -63,25 +62,26 @@ void _encodeFromTable(char** labels, FILE* source, Buffer* output) {
// Ajout du label dans le buffer, caractère par caractère // Ajout du label dans le buffer, caractère par caractère
// vidant progressivement le buffer // vidant progressivement le buffer
while (*label != '\0') { while (*label != '\0') {
pushToBuffer(*label == '1', output); putBuffer(*label == '1', output);
label++; label++;
} }
} }
} }
void compress(FILE* source, FILE* dest) { void compress(FILE* source, FILE* dest) {
// FIXME: gérer le fichier vide // Étape 1 : calcul des fréquences de chaque caractère
// FIXME: gérer les fichiers ne contenant qu'un seul type de caractère // FIXME: éviter la division par zéro pour les fichiers vides
// FIXME: gérer l'entrée depuis stdin (pas de double lecture)
// Calcul de la clef de codage à partir de la source
printVerbose("Calcul des fréquences d'apparition des caractères.\n"); printVerbose("Calcul des fréquences d'apparition des caractères.\n");
double* frequencies = _createFrequencies(source); size_t start_bytes = 0;
double* frequencies = _createFrequencies(source, &start_bytes);
if (isVerbose()) { if (isVerbose()) {
printFrequenciesTable(frequencies, NUM_CHARS); printFrequenciesTable(frequencies, NUM_CHARS);
} }
// Étape 2 : construction d'un arbre de Huffman pour les fréquences
// FIXME: éviter les arbres malformés avec les fichiers ne contenant qu'un
// seul type de caractère
printVerbose("\nConstruction de l'arbre de Huffman.\n"); printVerbose("\nConstruction de l'arbre de Huffman.\n");
HufTree tree = createTree(frequencies); HufTree tree = createTree(frequencies);
@ -92,6 +92,7 @@ void compress(FILE* source, FILE* dest) {
printTree(tree); printTree(tree);
} }
// Étape 3 : calcul de la clef de codage (coloration de l'arbre)
printVerbose("\nÉtiquetage des feuilles de l'arbre.\n"); printVerbose("\nÉtiquetage des feuilles de l'arbre.\n");
char** labels = createTreeLabels(tree); char** labels = createTreeLabels(tree);
@ -99,18 +100,31 @@ void compress(FILE* source, FILE* dest) {
printLabelsTable(labels, NUM_CHARS); printLabelsTable(labels, NUM_CHARS);
} }
// Écriture des données compressées vers la sortie // Étape 4 : écriture des données compressées vers la sortie
Buffer output = createBuffer(dest); WriteBuffer output = createWriteBuffer(dest);
printVerbose("\nÉcriture des données compressées.\n");
printVerbose("\nÉcriture de l'arbre dans la sortie.\n"); // - Entier : nombre d'octets dans le fichier originel
fwrite(&start_bytes, sizeof(start_bytes), 1, dest);
// - Arbre linéarisé : arbre de Huffman permettant le calcul de la clef
writeTree(tree, &output); writeTree(tree, &output);
printVerbose("Écriture des données compressées du fichier.\n"); // - Données compressées brutes (caractères originels traduits dans
// la clef de codage calculée avant)
rewind(source); rewind(source);
_encodeFromTable(labels, source, &output); _encodeFromTable(labels, source, &output);
// Vidage du dernier octet du tampon et nettoyage
flushBuffer(&output); flushBuffer(&output);
// Affichage des statistiques de compression
size_t end_bytes = sizeof(start_bytes) + getFlushedCount(&output);
double gain = (start_bytes - end_bytes) / (double) start_bytes * 100;
printVerbose("Taille originelle : %d octets.\n", start_bytes);
printVerbose("Taille compressée : %d octets.\n", end_bytes);
printVerbose("Gain : %.2f %% !\n", gain);
// Nettoyage des objets
freeTree(tree); freeTree(tree);
freeTreeLabels(labels); freeTreeLabels(labels);
labels = NULL; labels = NULL;