Commit f849fab5 authored by david's avatar david
Browse files

Ajout des fichiers C++ du TP1

parent 1d8da6ae
CC= g++
CXXFLAGS= -Wall -ansi --pedantic -g
CPP_O_FILE = arraylist.o main.o
all: $(CPP_O_FILE)
$(CC) $(CXXFLAGS) -o arraylist_analysis $(CPP_O_FILE)
clean:
rm -rf *.o
rm -rf *~
rm -rf arraylist_analysis
#ifndef __ANALYZER_HPP__
#define __ANALYZER_HPP__
#include<cmath>
#include <vector>
#include <iostream>
#include <fstream>
/**
Classe utilisée pour faire des statistiques élémentaires
sur une séquence d'opérations.
*/
class Analyzer{
public:
/**
Constructeur de la classe analyse
Complexité en temps/espace, pire et meilleur cas : O(1)
*/
Analyzer():cumulative_square(0){}
/**
Ajoute un coût, une valeur à l'analyse.
Complexité en temps/espace, pire cas : O(size)
Complexité en temps/espace, meilleur cas : O(1)
Complexité amortie : O(1)
@param x est la valeur que l'on souhaite ajouter à l'analyse.
*/
void append(const double & x){
cost.push_back(x);
cumulative_cost.push_back( (cumulative_cost.size()) ? cumulative_cost.back()+x : x);
cumulative_square += x*x;
}
/**
Renvoie la somme des coûts enregistrés dans cette analyse.
Complexité en temps/espace, meilleur cas : O(1)
@returns la somme des coûts enregistrés dans cette analyse.
*/
double get_total_cost(){
return cumulative_cost.back();
}
/**
Renvoie le coût amorti d'une opération.
Complexité en temps/espace, meilleur cas : O(1)
@param pos est l'indice de l'opération pour laquelle on veut connaître le coût amorti.
@returns le coût amorti d'une opération.
*/
double get_amortized_cost(size_t pos){
return (pos)? cumulative_cost.at(pos)/pos : cumulative_cost.at(pos);
}
/**
Renvoie la moyenne des coûts de toutes les opérations enregistrées dans l'analyse.
Complexité en temps/espace, meilleur cas : O(1)
@returns la moyenne des coûts de toutes les opérations enregistrées dans l'analyse.
*/
double get_average_cost(){
if(cumulative_cost.empty())
throw std::runtime_error("List is empty");
return cumulative_cost.back()/cumulative_cost.size();
}
/**
Renvoie la variance des coûts de toutes les opérations enregistrées dans l'analyse.
Complexité en temps/espace, meilleur cas : O(1)
@returns la variance des coûts de toutes les opérations enregistrées dans l'analyse.
*/
double get_variance(){
double mean, mean_square;
mean = get_average_cost();
mean_square = mean * mean;
return cumulative_square - mean_square;
}
/**
Renvoie l'écart-type des coûts de toutes les opérations enregistrées dans l'analyse.
Complexité en temps/espace, meilleur cas : O(1)
@returns l'écart-type des coûts de toutes les opérations enregistrées dans l'analyse.
*/
double get_standard_deviation(){
return std::sqrt(get_variance());
}
/**
Sauvegarde la liste des coûts et des coûts amortis dans un fichier.
Complexité en temps, meilleur/pire cas : O(size)
@param path est le chemin du fichier dans lequel la sauvegarde est faite.
*/
void save_values(const std::string & path){
std::ofstream f;
size_t i;
f.open(path.c_str());
for (i = 0; i < cost.size(); ++i)
f<<i<<" "<<cost.at(i)<<" "<<get_amortized_cost(i)<<std::endl;
f.close();
}
/**
Affiche la liste des coûts et des coûts amortis sur la sortie standard.
Complexité en temps, meilleur/pire cas : O(size)
*/
void plot_values(){
size_t i;
for (i = 0; i < cost.size(); ++i)
std::cout<<i<<" "<<cost.at(i)<<" "<<get_amortized_cost(i)<<std::endl;
}
private:
// Coût de chaque opération. Peut représenter du temps ou une autre mesure.
std::vector<double> cost;
// Coût cumulatif. La case i contient la somme des coûts des i premières opérations.
// Permet de calculer le coût amorti d'une opération.
std::vector<double> cumulative_cost;
// Carré du coût cumulatif. Sert à calculer la variance. On ne garde que la dernière valeur.
double cumulative_square;
};
#endif
#include "arraylist.hpp"
template <typename P>
P ArrayList<P>::get(const int & pos){
return data[pos];
}
#ifndef __ARRAYLIST_HPP
#define __ARRAYLIST_HPP
#include<iostream>
#include<vector>
/**
Cette classe est un proxy pour les vecteurs, c'est à dire les tableaux dynamiques en C++.
On utilise cette classe afin d'avoir le contrôle sur la gestion de la mémoire.
*/
template <typename P>
class ArrayList{
public:
/**
Constructeur de la classe des tableaux dynamiques.
Complexité en temps/espace, pire et meilleur cas : O(1)
*/
ArrayList(){
data.reserve(4);
}
/**
Ajoute une valeur dans le tableau.
Complexité en temps/espace, pire cas : O(size)
Complexité en temps/espace, meilleur cas : O(1)
Complexité amortie : O(1)
@param x est la valeur que l'on souhaite ajouter.
@returns true si le tableau a été agrandit, false sinon
*/
bool append(P x){
bool memory_allocation = false;
if( enlarging_capacity() ){
memory_allocation = true;
data.reserve( data.capacity() *2 );
}
data.push_back(x);
return memory_allocation;
}
/**
Supprime la dernière valeur du tableau.
Complexité en temps, pire cas : O(size)
Complexité en temps, meilleur cas : O(1)
Complexité amortie : O(1)
@returns true si le tableau a été réduit, false sinon
*/
bool pop_back(){
bool memory_reduction = false;
if(!data.empty()){
if( reducing_capacity() ){
memory_reduction = true;
data.reserve( data.capacity() /2 );
}
data.pop_back();
}
return memory_reduction;
}
/**
Renvoie la valeur située à la position donnée par l'utilisateur.
Complexité en temps/espace, pire cas : O(1)
@param pos est la l'indice de la case on l'utilisateur veut connaître la valeur.
@returns la valeur située à la position donnée par l'utilisateur.
*/
P get(const int & pos);
/**
Renvoie le nombre d'éléments stockés dans le tableau.
Complexité en temps/espace, pire cas : O(1)
@returns le nombre d'éléments stockés dans le tableau.
*/
const size_t get_size(){ return data.size(); }
private:
// Vecteur contenant les données.
std::vector<P> data;
/**
Cette fonction détermine la règle selon laquelle un espace mémoire plus grand sera alloué ou non.
@returns true si le tableau doit être agrandi, false sinon.
*/
bool enlarging_capacity(){
return data.size() >= (data.capacity() * 3)/4;
}
/**
Cette fonction détermine la règle selon laquelle un espace mémoire plus petit sera alloué ou non.
@returns true si le tableau doit être réduit, false sinon.
*/
bool reducing_capacity(){
return data.size() <= data.capacity()/4 && data.size() >4;
}
};
#endif
#include<iostream>
#include<time.h>
#include<cstdlib>
#include "arraylist.hpp"
#include "analyzer.hpp"
int main(int argc, char ** argv){
int i;
// Tableau dynamique.
ArrayList<int> a;
// Analyse du temps pris par les opérations.
Analyzer time_analysis;
// Analyse du nombre de copies faites par les opérations.
Analyzer copy_analysis;
struct timespec before, after;
// Booléen permettant de savoir si une allocation a été effectuée.
bool memory_allocation;
for(i = 0; i < 1000000 ; i++){
// Ajout d'un élément et mesure du temps pris par l'opération.
timespec_get(&before, TIME_UTC);
memory_allocation = a.append(i);
timespec_get(&after, TIME_UTC);
// Enregistrement du temps pris par l'opération
time_analysis.append(after.tv_nsec - before.tv_nsec);
// Enregistrement du nombre de copies efféctuées par l'opération.
// S'il y a eu réallocation de mémoire, il a fallu recopier tout le tableau.
copy_analysis.append( (memory_allocation)? i:1 );
}
// Affichage de quelques statistiques sur l'expérience.
std::cerr<<"Total cost :"<<time_analysis.get_total_cost()<<std::endl;
std::cerr<<"Average cost :"<<time_analysis.get_average_cost()<<std::endl;
std::cerr<<"Variance :"<<time_analysis.get_variance()<<std::endl;
std::cerr<<"Standard deviation :"<<time_analysis.get_standard_deviation()<<std::endl;
// Sauvegarde les données de l'expérience: temps et nombre de copies effectuées par opération.
time_analysis.save_values("../dynamic_array_time_cpp.plot");
copy_analysis.save_values("../dynamic_array_copy_cpp.plot");
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment