Ajouter les statistiques de compression dans compress
This commit is contained in:
parent
ec235ddea7
commit
0bddeb367c
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue