diff --git a/banque b/banque index c38444b..b24d472 100755 Binary files a/banque and b/banque differ diff --git a/banque.c b/banque.c index bc766ee..acc2d13 100644 --- a/banque.c +++ b/banque.c @@ -1,337 +1,3 @@ -<<<<<<< HEAD -/* - * R5.A.04 - Qualité Algorithmique - * TD Complexité algorithmique : analyse des transactions d'une banque - * - * Le programme génère des transactions pseudo-aléatoires (toujours les - * mêmes, grâce à une graine fixe), puis calcule plusieurs indicateurs - * et produit un rapport dans rapport.txt. - * - * L'empreinte affichée à la fin doit rester IDENTIQUE après vos - * optimisations : elle prouve que le résultat n'a pas changé. - * - * Interdit : modifier les constantes, la génération des données, - * le format du rapport, ou écrire les résultats « en dur ». - * - * Compilation : gcc -O2 banque.c -o banque - * Profiling : gcc -O0 -g -pg banque.c -o banque && ./banque && gprof ./banque gmon.out - */ - -#include -#include - -#define NB_TRANSACTIONS 30000 -#define NB_CLIENTS 2000 -#define NB_JOURS 1000 -#define NB_REQUETES 30000 -#define MONTANT_MONNAIE 400 -#define GRAINE 20261020UL - -typedef struct { - int id; - int client; - int jour; - long montant; /* en centimes, négatif pour un débit */ -} Transaction; - -/* ------------------------------------------------------------------ */ -/* Données (ne pas modifier) */ -/* ------------------------------------------------------------------ */ - -static unsigned long etat_alea = GRAINE; - -unsigned long alea(void) -{ - etat_alea = etat_alea * 6364136223846793005UL + 1442695040888963407UL; - return etat_alea >> 33; -} - -Transaction *generer_transactions(int n) -{ - Transaction *t = malloc(n * sizeof(Transaction)); - for (int i = 0; i < n; i++) { - t[i].id = i; - t[i].client = alea() % NB_CLIENTS; - t[i].jour = alea() % NB_JOURS; - if (i > 0 && alea() % 20 == 0) - t[i].montant = -t[alea() % i].montant; /* opération inverse */ - else - t[i].montant = (long)(alea() % 100001) - 50000; - } - for (int i = n - 1; i > 0; i--) { /* mélange des id */ - int j = alea() % (i + 1); - int tmp = t[i].id; - t[i].id = t[j].id; - t[j].id = tmp; - } - return t; -} - -/* ------------------------------------------------------------------ */ -/* Fonctions à analyser et à optimiser */ -/* ------------------------------------------------------------------ */ - -/* F1 : trie les transactions par montant croissant, puis par id */ -void trier_par_montant(Transaction *t, int n) -{ - for (int i = 1; i < n; i++) { - Transaction cle = t[i]; - int j = i - 1; - while (j >= 0 && (t[j].montant > cle.montant || - (t[j].montant == cle.montant && t[j].id > cle.id))) { - t[j + 1] = t[j]; - j--; - } - t[j + 1] = cle; - } -} - -/* F2 : nombre de clients ayant au moins une transaction */ -int nb_clients_distincts(const Transaction *t, int n) -{ - int nb = 0; - for (int i = 0; i < n; i++) { - int deja_vu = 0; - for (int j = 0; j < i; j++) { - if (t[j].client == t[i].client) { - deja_vu = 1; - break; - } - } - if (!deja_vu) - nb++; - } - return nb; -} - -/* F3 : solde total de chaque client en O(n + c) */ -void total_par_client(const Transaction *t, int n, long *totaux) -{ - for (int c = 0; c < NB_CLIENTS; c++) { - totaux[c] = 0; - } - for (int i = 0; i < n; i++) { - totaux[t[i].client] += t[i].montant; - } -} - -/* F4 : solde total de chaque jour */ -void total_par_jour(const Transaction *t, int n, long *totaux) -{ - for (int j = 0; j < NB_JOURS; j++) { - totaux[j] = 0; - for (int i = 0; i < n; i++) - if (t[i].jour == j) - totaux[j] += t[i].montant; - } -} - -/* F5 : période de jours consécutifs dont la somme des soldes est maximale */ -long meilleure_periode(const long *totaux, int nb_jours, int *debut, int *fin) -{ - long meilleur = totaux[0]; - *debut = 0; - *fin = 0; - for (int i = 0; i < nb_jours; i++) { - for (int j = i; j < nb_jours; j++) { - long somme = 0; - for (int k = i; k <= j; k++) - somme += totaux[k]; - if (somme > meilleur) { - meilleur = somme; - *debut = i; - *fin = j; - } - } - } - return meilleur; -} - -/* F6 : retrouve une transaction à partir de son id */ -const Transaction *rechercher_par_id(const Transaction *t, int n, int id) -{ - for (int i = 0; i < n; i++) - if (t[i].id == id) - return &t[i]; - return NULL; -} - -/* F7 : nombre de paires de transactions de montants opposés (a + b = 0) */ -long nb_paires_opposees(const Transaction *t, int n) -{ - long nb = 0; - for (int i = 0; i < n; i++) - for (int j = i + 1; j < n; j++) - if (t[i].montant + t[j].montant == 0) - nb++; - return nb; -} - -/* F8 : nombre de façons de rendre une somme avec les pièces disponibles */ -static const int PIECES[] = {1, 2, 5, 10, 20, 50, 100, 200}; -#define NB_PIECES 8 - -long nb_facons_rendre(int somme, int nb_pieces) -{ - if (somme == 0) - return 1; - if (somme < 0 || nb_pieces == 0) - return 0; - return nb_facons_rendre(somme - PIECES[nb_pieces - 1], nb_pieces) + - nb_facons_rendre(somme, nb_pieces - 1); -} - -/* F9 : catégorie d'une transaction (pour les statistiques) */ -int categorie(const Transaction *t) -{ - if (t->montant < 0) { - if (t->montant < -20000) { - if (t->jour % 7 == 5 || t->jour % 7 == 6) - return 1; - else - return 2; - } else if (t->montant < -5000) { - return 3; - } else { - if (t->client % 10 == 0) - return 4; - return 5; - } - } else if (t->montant == 0) { - return 0; - } else { - if (t->montant > 30000) { - if (t->client % 10 == 0 && t->jour % 7 < 5) - return 6; - return 7; - } else if (t->montant > 10000) { - return 8; - } else if (t->montant > 1000) { - if (t->jour % 30 == 0) - return 9; - return 10; - } - return 11; - } -} - -/* F10 : ajoute une ligne à la fin du rapport */ -int longueur(const char *s) -{ - int n = 0; - while (s[n] != '\0') - n++; - return n; -} - -void ajouter_ligne(char *rapport, const char *ligne) -{ - int fin = longueur(rapport); - int i = 0; - while (ligne[i] != '\0') { - rapport[fin + i] = ligne[i]; - i++; - } - rapport[fin + i] = '\0'; -} - -/* ------------------------------------------------------------------ */ -/* Programme principal (à adapter si vous changez les signatures) */ -/* ------------------------------------------------------------------ */ - -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; -} - -int main(void) -{ - Transaction *t = generer_transactions(NB_TRANSACTIONS); - char *rapport = malloc(1 << 20); - char ligne[128]; - rapport[0] = '\0'; - - /* recherches par id, dans l'ordre d'origine */ - long somme_requetes = 0; - unsigned long etat = 12345; - for (int q = 0; q < NB_REQUETES; q++) { - etat = etat * 1103515245UL + 12345UL; - const Transaction *r = rechercher_par_id(t, NB_TRANSACTIONS, (int)((etat >> 8) % NB_TRANSACTIONS)); - if (r != NULL) - somme_requetes += r->montant; - } - - int nb_clients = nb_clients_distincts(t, NB_TRANSACTIONS); - - static long totaux_clients[NB_CLIENTS]; - total_par_client(t, NB_TRANSACTIONS, totaux_clients); - - static long totaux_jours[NB_JOURS]; - total_par_jour(t, NB_TRANSACTIONS, totaux_jours); - int debut, fin; - long meilleure = meilleure_periode(totaux_jours, NB_JOURS, &debut, &fin); - - long nb_paires = nb_paires_opposees(t, NB_TRANSACTIONS); - - int categories[12] = {0}; - for (int i = 0; i < NB_TRANSACTIONS; i++) - categories[categorie(&t[i])]++; - - trier_par_montant(t, NB_TRANSACTIONS); - - long nb_facons = nb_facons_rendre(MONTANT_MONNAIE, NB_PIECES); - - /* rapport */ - snprintf(ligne, sizeof(ligne), "clients distincts;%d\n", nb_clients); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "somme des requetes;%ld\n", somme_requetes); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "meilleure periode;%d;%d;%ld\n", debut, fin, meilleure); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "paires opposees;%ld\n", nb_paires); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "facons de rendre %d;%ld\n", MONTANT_MONNAIE, nb_facons); - ajouter_ligne(rapport, ligne); - for (int c = 0; c < 12; c++) { - snprintf(ligne, sizeof(ligne), "categorie;%d;%d\n", c, categories[c]); - ajouter_ligne(rapport, ligne); - } - for (int c = 0; c < NB_CLIENTS; c++) { - snprintf(ligne, sizeof(ligne), "client;%d;%ld\n", c, totaux_clients[c]); - ajouter_ligne(rapport, ligne); - } - for (int j = 0; j < NB_JOURS; j++) { - snprintf(ligne, sizeof(ligne), "jour;%d;%ld\n", j, totaux_jours[j]); - ajouter_ligne(rapport, ligne); - } - for (int i = 0; i < NB_TRANSACTIONS; i += 10) { - snprintf(ligne, sizeof(ligne), "rang;%d;%d;%ld\n", i, t[i].id, t[i].montant); - ajouter_ligne(rapport, ligne); - } - - FILE *f = fopen("rapport.txt", "w"); - if (f != NULL) { - fputs(rapport, f); - fclose(f); - } - - printf("Clients distincts : %d\n", nb_clients); - printf("Somme des requêtes : %ld\n", somme_requetes); - printf("Meilleure période : jours %d à %d (%ld)\n", debut, fin, meilleure); - printf("Paires opposées : %ld\n", nb_paires); - printf("Façons de rendre %d : %ld\n", MONTANT_MONNAIE, nb_facons); - printf("Empreinte : %016lx\n", empreinte(rapport)); - - free(rapport); - free(t); - return 0; -} -======= /* * R5.A.04 - Qualité Algorithmique * TD Complexité algorithmique : analyse des transactions d'une banque @@ -422,28 +88,29 @@ void trier_par_montant(Transaction *t, int n) /* F2 : nombre de clients ayant au moins une transaction */ int nb_clients_distincts(const Transaction *t, int n) { - int clients_vus[NB_CLIENTS] = {0}; int nb = 0; - for (int i = 0; i < n; i++) { - int client = t[i].client; - if (!clients_vus[client]) { - clients_vus[client] = 1; - nb++; + int deja_vu = 0; + for (int j = 0; j < i; j++) { + if (t[j].client == t[i].client) { + deja_vu = 1; + break; + } } + if (!deja_vu) + nb++; } - return nb; } -/* F3 : solde total de chaque client */ +/* F3 : solde total de chaque client en O(n + c) */ void total_par_client(const Transaction *t, int n, long *totaux) { for (int c = 0; c < NB_CLIENTS; c++) { totaux[c] = 0; - for (int i = 0; i < n; i++) - if (t[i].client == c) - totaux[c] += t[i].montant; + } + for (int i = 0; i < n; i++) { + totaux[t[i].client] += t[i].montant; } } @@ -452,30 +119,36 @@ void total_par_jour(const Transaction *t, int n, long *totaux) { for (int j = 0; j < NB_JOURS; j++) { totaux[j] = 0; + for (int i = 0; i < n; i++) + if (t[i].jour == j) + totaux[j] += t[i].montant; } - - for (int i = 0; i < n; i++) - totaux[t[i].jour] += t[i].montant; } -/* F5 : période de jours consécutifs dont la somme des soldes est maximale */ +/* F5 : période de jours consécutifs dont la somme des soldes est maximale en O(J) */ long meilleure_periode(const long *totaux, int nb_jours, int *debut, int *fin) { long meilleur = totaux[0]; *debut = 0; *fin = 0; - for (int i = 0; i < nb_jours; i++) { - for (int j = i; j < nb_jours; j++) { - long somme = 0; - for (int k = i; k <= j; k++) - somme += totaux[k]; - if (somme > meilleur) { - meilleur = somme; - *debut = i; - *fin = j; - } + + long somme_courante = totaux[0]; + int debut_courant = 0; + + for (int j = 1; j < nb_jours; j++) { + if (somme_courante < 0) { + somme_courante = totaux[j]; + debut_courant = j; + } else { + somme_courante += totaux[j]; + } + if (somme_courante > meilleur) { + meilleur = somme_courante; + *debut = debut_courant; + *fin = j; } } + return meilleur; } @@ -663,4 +336,3 @@ int main(void) free(t); return 0; } ->>>>>>> 97155f26889184ac9ab593d6aadb23cbdbce96c2