Vous êtes sur la page 1sur 8

TP3 : Introduction aux objets

Pensez à structurer l’implémentation, à mettre des commentaires et à passer les arguments par référence en
les protégeant (const) si besoin. On écrira l’implémentation dans des fichiers séparés.

1) Ecrire une classe vecteur ayant pour données membres privées la dimension du vecteur : int dim et
un tableau de float : float * val ayant :

• un constructeur par défaut

• un constructeur avec dimension

• un constructeur avec dimension et valeur par défaut

• un constructeur par copie

• un destructeur

• une fonction membre val(i) d’accès à la i ème valeur (i=1,n) permettant la lecture et l’écriture

• une fonction membre d’impression du vecteur : print()

• des fonctions externes à la classe permettant de faire la somme, la différence de deux vecteurs ainsi
que le produit d’un scalaire par un vecteur

• une fonction réalisant le produit scalaire de deux vecteurs et une fonction calculant la norme d’un
vecteur

- Ecrire l’implémentation des membres de classes dans un fichier séparé et les définitions dans un fichier
entête.
- Afin de tracer le comportement des constructeurs, inclure dans toutes les fonctions une impression indiquant
le passage par la fonction.

2) Faire un programme principal validant toutes les fonctionnalités.

3) Ecrire dans le même esprit une classe matrice utilisant un tableau simple float * val , le rangement
s’opérant par colonne. Prévoir les principaux constructeurs, l’accès à l’élément (i,j) ainsi que des fonctions
d’accès renvoyant un pointeur sur le premier élément d’une ligne et sur le premier élément d’une colonne,
une fonction d’impression.

4) Ecrire un produit matrice × vecteur le plus rapide possible (tester avec la fonction time). Comparer
en particulier, une version fondée sur l’opérateur d’accès (i,j) et celle fondée sur un accès par pointeur et
un algorithme adapté aux pointeurs (déplacement séquentiel) : si p désigne un pointeur p++ incrémente le
pointeur de 1 et donne un pointeur sur l’élément suivant.

1
Correction
classe vecteur
//===========================================================================
// class vecteur (header file)
//===========================================================================
// classe permettant de manipuler des vecteurs mathématiques
// s’appuie sur un tableau de double
//
// principales fonctionnalités :
// - constructeur par défaut, dimension et valeur et par copie
// - accès en lecture et écriture à un élément
// - impression du vecteur
// - somme et différence de deux vecteurs (externes à la classe)
// - produit par un scalaire (externe à la classe)
// - produit scalaire et norme euclidienne (externe à la classe)
//===========================================================================

#ifndef vecteurH
#define vecteurH

// fichiers ent^
etes système
#include <iostream>

using namespace std;

//---------------------------------------------------------------------------
// class vecteur (définition)
//---------------------------------------------------------------------------
class vecteur
{
private :
int dim_; // dimension du vecteur
double * val_; // tableau des valeurs

public :

//constructeurs/destructeurs
vecteur(): dim_(0),val_(NULL) {} //constructeur par défaut
vecteur(int d,double v=0.); //constructeur dimension et val. initiale
vecteur(const vecteur &V); //constructeur par copie
~vecteur(); //destructeur

//accès à un élément
double & val (int ) const; //acces au i ème élément, i=1 à dim
double & val2(int) const; //acces robuste
int dim() const; //retourne la dimension du vecteur

//impression
void print(); //impression sur l’unité standard (cout)
};}
//---------------fin de définition de la classe vecteur-----------------------

//fonctions externes à la classe}


//------------------------------}
vecteur somme(const vecteur &, const vecteur &); //somme de deux vecteur
vecteur diff (const vecteur &, const vecteur &); //différence de deux vecteurs
vecteur produit(const vecteur &, double); //produit d’un vecteur par un scalaire
double prod_scal(const vecteur &, const vecteur &);//produit scalaire
double norme(const vecteur &); //norme euclidienne

//fast version : pas de test et acces par pointeur


vecteur fast_somme(const vecteur &, const vecteur &); //somme de deux vecteur
vecteur fast_diff (const vecteur &, const vecteur &); //différence de deux vecteurs
vecteur fast_produit(const vecteur &, double); //produit d’un vecteur par un scalaire
double fast_prod_scal(const vecteur &, const vecteur &);//produit scalaire
double fast_norme(const vecteur &); //norme euclidienne

//utilitaire
//----------
void coherence_dim(const vecteur &,const vecteur &); //test de cohérence de la dimension de deux vecteurs

//---------------fin du fichier ent^


ete vecteur.h-----------------------
#endif

//===========================================================================
// class vecteur (implementation file)}
//===========================================================================
// voir header pour la définition de la classe vecteur}
//---------------------------------------------------------------------------

//fichiers ent^
etes
#include "vecteur.h"

// fichiers ent^
etes système
#include <iostream>

using namespace std;

//constructeurs/destructeurs
//-------------------------
vecteur::vecteur(int d,double v) //constructeur dimension et val. initiale
{//suivi
#ifdef debug
cout<<"vecteur : constructeur (int d,double v)\n";
#endif
dim_=d;val_=NULL;
if(d<=0) return; //aucune allocation, vecteur vide
val_=new double[dim_];
for(int i=0;i<dim_;i++) val_[i]=v; //affectation
}

2
vecteur::vecteur(const vecteur &V) //constructeur par copie
{//suivi
#ifdef debug
cout<<"vecteur : constructeur copie(const vecteur &V)\n";
#endif
dim_=V.dim_;val_=NULL;
if(dim_<=0) return; //aucune allocation, vecteur vide
val_=new double[dim_];}
for(int i=0;i<dim_;i++) val_[i]=V.val_[i]; //recopie
}

vecteur::~vecteur() //destructeur
{//suivi
#ifdef debug
cout<<"vecteur : destructeur\n";
#endif
if(val_!=NULL) delete [] val_; //libération mémoire
}

//accès à un élément
//------------------
double & vecteur::val(int i) const //acces au i ème élément, i=1 à dim
{return val_[i-1];}

double & vecteur::val2(int i) const //acces robuste


{if(i<=0 || i>dim_) {cout<<"indice hor limite";exit(1);}
return val_[i-1];
}

int vecteur::dim() const //retourne la dimension du vecteur


{return dim_;}

//impression
//----------
void vecteur::print() //impression sur l’unité standard (cout)
{cout<<"vecteur de dimension "<<dim_<<endl;
for(int i=0;i<dim_;i++) cout<<val_[i]<<" ";
cout<<endl;
}

//fonctions externes à la classe


//------------------------------
vecteur somme(const vecteur &V1, const vecteur &V2) //somme de deux vecteur
{coherence_dim(V1,V2);
vecteur R(V1); //création du résultat avec copie de V1
for(int i=1;i<=V1.dim();i++) R.val(i)+=V2.val(i);
return R;
}

vecteur diff (const vecteur &V1, const vecteur &V2) //différence de deux vecteurs
{coherence_dim(V1,V2);
vecteur R(V1); //création du résultat avec copie de V1
for(int i=1;i<=V1.dim();i++) R.val(i)-=V2.val(i);
return R;
}

vecteur produit(const vecteur &V, double x) //produit d’un vecteur par un scalaire
{ vecteur R(V); //création du résultat avec copie de V
for(int i=1;i<=V.dim();i++) R.val(i)*=x;
return R;
}

double prod_scal(const vecteur &V1, const vecteur &V2) //produit scalaire


{coherence_dim(V1,V2);
double r=0;
for(int i=1;i<=V1.dim();i++)r+=(V1.val(i)*V2.val(i));
return r;
}

double norme(const vecteur &V) //norme euclidienne


{return sqrt(prod_scal(V,V));}

//versions rapides
//les "fast" version n’appellent pas le test sur la dimension
//et font un accès par pointeur (gain de 25%)

vecteur fast_somme(const vecteur &V1, const vecteur &V2) //somme de deux vecteur
{vecteur R(V1); //création du résultat avec copie de V1
double *pR=&R.val(1);
double *p2=&V2.val(1);
for(int i=1;i<=V1.dim();i++,pR++,p2++) (*pR)+=(*p2);
return R;
}

vecteur fast_diff (const vecteur &V1, const vecteur &V2) //différence de deux vecteurs
{vecteur R(V1); //création du résultat avec copie de V1
double *pR=&R.val(1);
double *p2=&V2.val(1);
for(int i=1;i<=V1.dim();i++,pR++,p2++) (*pR)-=(*p2);
return R;
}

vecteur fast_produit(const vecteur &V, double x) //produit d’un vecteur par un scalaire
{vecteur R(V); //création du résultat avec copie de V
double *pR=&R.val(1);
for(int i=1;i<=V.dim();i++,pR++) (*pR)*=x;
return R;
}

double fast_prod_scal(const vecteur &V1, const vecteur &V2) //produit scalaire


{double r=0;
double *p1=&V1.val(1);
double *p2=&V2.val(1);
for(int i=1;i<=V1.dim();i++,p1++,p2++) r+=(*p1)*(*p2);
return r;

3
}

double fast_norme(const vecteur &V) //norme euclidienne


{return sqrt(fast_prod_scal(V,V));}

//utilitaire
//----------
void coherence_dim(const vecteur &V1,const vecteur &V2) //test de cohérence de la dimension de deux vecteurs
{if(V1.dim()==V2.dim()) return;
cout<<"somme de deux vecteurs : dimensions incohérentes "<<V1.dim()<<" et "<<V2.dim();
exit(1);
}

classe matrice
//===========================================================================
// class matrice (header file)
//===========================================================================
// classe permettant de manipuler des matrices
// s’appuie sur un tableau de double (rangement par colonne, idem Fortran)
//
// principales fonctionnalités :
// - constructeur par défaut, dimension et valeur et par copie
// - accès en lecture et écriture à un élément
// - impression du vecteur
// - somme et différence de deux vecteurs (externes à la classe)
// - produit par un scalaire (externe à la classe)
//===========================================================================

#ifndef matriceH
#define matriceH

// fichiers ent^
etes système
#include <iostream>

//fichiers ent^
ete
#include "vecteur.h"

using namespace std;

//---------------------------------------------------------------------------
// class matrice (définition)
//---------------------------------------------------------------------------
class matrice
{
private :
int dim_l_,dim_c_; // dimension de la matrice matrice
double * val_; // tableau des valeurs

public :

//constructeurs/destructeurs
matrice(): dim_l_(0),dim_c_(0),val_(NULL) {} //constructeur par défaut
matrice(int ,int ,double v=0.); //constructeur dimensions et val. initiale
matrice(const matrice &); //constructeur par copie
~matrice(); //destructeur

//accès à un élément
double & val (int i,int j) const; //acces au terme(i,j), i=1 à dim_l, j=1 à dim_c
double & val2(int i,int j) const; //acces robuste
int dim_l() const; //retourne la dimension du matrice
int dim_c() const; //retourne la dimension du matrice

//impression
void print(); //impression sur l’unité standard (cout)
};}
//---------------fin de définition de la classe matrice-----------------------

//fonctions externes à la classe


//------------------------------

matrice somme(const matrice &, const matrice &); //somme de deux matrice
matrice diff (const matrice &, const matrice &); //différence de deux matrices
matrice produit(const matrice &, double); //produit d’un matrice par un scalaire

//fast version : pas de test et acces par pointeur


matrice fast_somme(const matrice &, const matrice &); //somme de deux matrice
matrice fast_diff (const matrice &, const matrice &); //différence de deux matrices
matrice fast_produit(const matrice &, double); //produit d’un matrice par un scalaire

vecteur produit(const matrice & ,const vecteur & ); //produit matrice x vecteur
vecteur fast_produit(const matrice & ,const vecteur & ); //produit matrice x vecteur (fast version)

//utilitaire
//----------
void coherence_dim(const matrice &,const matrice &); //test de cohérence de la dimension de deux matrices

//---------------fin du fichier ent^


ete matrice.h-----------------------
#endif

//===========================================================================
// class matrice (implementation file)
//===========================================================================
// voir header pour la définition de la classe matrice
//---------------------------------------------------------------------------

//fichiers ent^
etes
#include "matrice.h"

// fichiers ent^
etes système

4
#include <iostream>

using namespace std;

//constructeurs/destructeurs
//-------------------------
matrice::matrice(int dl,int dc,double v) //constructeur dimension et val. initiale
{//suivi
#ifdef debug
cout<<"matrice : constructeur (int dl,int dc,double v)\n";
#endif
dim_l_=dl;dim_c_=dc;val_=NULL;
int d=dl*dc;
if(d<=0) return; //aucune allocation, matrice vide
val_=new double[d];
for(int k=0;k<d;k++) val_[k]=v; //affectation
}

matrice::matrice(const matrice &V) //constructeur par copie


{//suivi
#ifdef debug
cout<<"matrice : constructeur copie matrice(const matrice &V)\n";
#endif
dim_l_=V.dim_l_;dim_c_=V.dim_c_;val_=NULL;
int d=dim_l_*dim_c_;
if(d<=0) return; //aucune allocation, matrice vide
val_=new double[d];
for(int k=0;k<d;k++) val_[k]=V.val_[k]; //recopie
}

matrice::~matrice() //destructeur
{//suivi
#ifdef debug
cout<<"matrice : destructeur";
#endif
if(val_!=NULL) delete [] val_; //libération mémoire
}

//accès à un élément
//------------------
double & matrice::val(int i, int j) const //acces à l’élément (i,j)
{return val_[(j-1)*dim_l_+i-1];}

double & matrice::val2(int i,int j) const //acces robuste


{if(i<=0 || i>dim_l_ || j<=0 || j>dim_c_) {cout<<"indice hor limite";exit(1);}
return val_[(j-1)*dim_l_+i-1];}

int matrice::dim_l() const //retourne le nb de lignes de la matrice


{return dim_l_;}

int matrice::dim_c() const //retourne le nb de colonnes de la matrice


{return dim_c_;}

//impression
//----------
void matrice::print() //impression sur l’unité standard (cout)
{cout<<"matrice de dimensions "<<dim_l_<<" x "<<dim_c_<<endl;
for(int i=1;i<=dim_l_;i++)
{for(int j=1;j<=dim_c_;j++) cout<<val(i,j)<<" ";
cout<<endl;
}
cout<<endl;
}

//fonctions externes à la classe


//------------------------------

matrice somme(const matrice &V1, const matrice &V2) //somme de deux matrice
{coherence_dim(V1,V2);
matrice R(V1); //création du résultat avec copie de V1
for(int i=1;i<=V1.dim_l();i++)
for(int j=1;j<=V1.dim_c();j++)
R.val(i,j)+=V2.val(i,j);
return R;
}

matrice diff (const matrice &V1, const matrice &V2) //différence de deux matrices
{coherence_dim(V1,V2);
matrice R(V1); //création du résultat avec copie de V1
for(int i=1;i<=V1.dim_l();i++)
for(int j=1;j<=V1.dim_c();j++)
R.val(i,j)-=V2.val(i,j);
return R;
}

matrice produit(const matrice &V, double x) //produit d’un matrice par un scalaire
{ matrice R(V); //création du résultat avec copie de V
for(int i=1;i<=V.dim_l();i++)
for(int j=1;j<=V.dim_c();j++) R.val(i,j)*=x;
return R;
}

//les "fast" versions n’appellent pas le test sur la dimension


//et font un accès par pointeur (gain de 25%)

matrice fast_somme(const matrice &V1, const matrice &V2) //somme de deux matrice
{matrice R(V1); //création du résultat avec copie de V1
double *pR=&R.val(1,1);
double *p2=&V2.val(1,1);
int lg=V1.dim_l()*V1.dim_c();
for(int k=0;k<lg;k++,pR++,p2++) (*pR)+=(*p2);
return R;
}

matrice fast_diff (const matrice &V1, const matrice &V2) //différence de deux matrices

5
{matrice R(V1); //création du résultat avec copie de V1
double *pR=&R.val(1,1);
double *p2=&V2.val(1,1);
int lg=V1.dim_l()*V1.dim_c();
for(int k=0;k<lg;k++,pR++,p2++) (*pR)-=(*p2);
return R;
}

matrice fast_produit(const matrice &V, double x) //produit d’un matrice par un scalaire
{matrice R(V); //création du résultat avec copie de V
double *pR=&R.val(1,1);
int lg=V.dim_l()*V.dim_c();
for(int k=0;k<lg;k++,pR++) (*pR)*=x;
return R;
}

//produit matrice x vecteur


//-------------------------
vecteur produit(const matrice & A,const vecteur & V)
{if(A.dim_c()!=V.dim())
{cout<<"produit matrice x vecteur, incohérence dans les dimensions : ";
cout<<"dimension de la matrice "<<A.dim_l()<<" x "<<A.dim_c();
cout<<" dimension du vecteur "<<V.dim();
exit(-1);
}
vecteur R(A.dim_l()); //nouveau vecteur de dimension le nombre de ligne de A
for(int i=1;i<=A.dim_l();i++)
for(int j=1;j<=A.dim_c();j++)
R.val(i)+=(A.val(i,j)*V.val(j));
return R;
}

vecteur fast_produit(const matrice & A,const vecteur & V)


{vecteur R(A.dim_l()); //nouveau vecteur de dimension le nombre de ligne de A
double *pA=&A.val(1,1); //pointeur sur le premier terme de la matrice
double *pV=&V.val(1); //pointeur sur le premier terme du vecteur V
double *pR=&R.val(1); //pointeur sur le premier terme du vecteur R
for(int j=1;j<=A.dim_c();j++,pV++)
{pR=&R.val(1);
for(int i=1;i<=A.dim_c();i++,pA++,pR++)
(*pR)+=((*pA)*(*pV));
}
return R;
}

//utilitaires
//-----------
void coherence_dim(const matrice &V1,const matrice &V2) //test de cohérence de la dimension de deux matrices
{if(V1.dim_l()==V2.dim_l() && V1.dim_c()==V2.dim_c()) return;
cout<<"somme de deux matrices : dimensions incohérentes ";
cout<<V1.dim_l()<<"x"<<V1.dim_c()<<" et "<<V2.dim_l()<<"x"<<V2.dim_c();
exit(1);
}

Programme principal
//===========================================================================
// TP2 Introduction aux classes d’objets
//===========================================================================
// classe vecteur et matrice

//fichiers d’ent^
etes
//------------------
#include "vecteur.h"
#include "matrice.h
#include <iostream>
#include <time.h>
using namespace std;

//programme principal
//-------------------

int main( )

{//test de la classe vecteur


//=========================

//test des constructeurs


vecteur V1; //constructeur par défaut
vecteur V2(3); //constructeur avec dimension
vecteur V3(3,1); //constructeur avec dimension et valeur initiale
vecteur V4(V3); //constructeur par copie

//test impression
cout<<"V1 ";V1.print();
cout<<"V2 ";V2.print();
cout<<"V3 ";V3.print();
cout<<"V4 ";V4.print();

//test acces
V2.val(1)=1.;V2.val(2)=2.;V2.val(3)=3.;
cout<<"acces : V2 ";V2.print();

//test destructeur
vecteur *pV5=new vecteur(V2);
pV5->print();
delete pV5;

//test de la somme et différence, produit


vecteur V6,V7,V8;
V6=somme(V2,V3);

6
cout<<"somme V6=V2+V3 ";V6.print();
V7=diff(V2,V3);
cout<<"différence V7=V2-V3 ";V7.print();
V8=produit(V2,5);
cout<<"produit V8=5*V2 ";V8.print();

//test des versions "fast"


V6=fast_somme(V2,V3);
cout<<"somme V6=V2+V3 ";V6.print();
V7=fast_diff(V2,V3);
cout<<"différence V7=V2-V3 ";V7.print();
V8=fast_produit(V2,5);
cout<<"produit V8=5*V2 ";V8.print();

cout.flush();
time_t t0,t1;

//test de vitesse
vecteur U(1000,1);
vecteur V(1000,2);
vecteur W(1000);

t0=time(NULL);
for(int k=0;k<800000;k++) W=somme(U,V);
t1=time(NULL);
cout<<"\ntemps pour la somme = "<<t1-t0;
cout.flush();

t0=time(NULL);
for(int k=0;k<800000;k++) W=fast_somme(U,V);
t1=time(NULL);
cout<<"\ntemps pour la somme = "<<t1-t0<<endl;

//test de la classe matrice


//=========================
matrice Id(3,3); //constructeur avec dimension
Id.val(1,1)=1; //acces aux élément en écriture
Id.val(2,2)=1;
Id.val(3,3)=1;
cout<<"Id ";Id.print(); //impression
matrice A(Id); //constructeur par copie
cout<<"A ";A.print();
matrice B=somme(A,Id); //test de la somme
cout<<"somme B=A+Id ";B.print();
B=diff(A,Id); //test différence
cout<<"différence B=A-Id ";B.print();
B=produit(A,5); //test produit
cout<<"produit B=5*Id ";B.print();
B=fast_somme(A,Id); //test de la fast somme
cout<<"fast somme B=A+Id ";B.print();
B=fast_diff(A,Id); //test fast différence
cout<<"fast différence B=A-Id ";B.print();
B=fast_produit(A,5); //test fast_produit
cout<<"fast produit B=5*Id ";B.print();

//test produit matrice x vecteur


//==============================
vecteur R=produit(A,V2);
cout<<"matrice vecteur R=A*V2 ";R.print();
R=fast_produit(A,V2);
cout<<"fast matrice vecteur R=A*V2 ";R.print();

//test de vitesse
//===============
vecteur U(100,1);
vecteur V(100,0);
matrice I(100,100,1);
t0=time(NULL);
for(int k=0;k<50000;k++) V=produit(I,U);
t1=time(NULL);
cout<<"\ntemps pour le produit matrice vecteur = "<<t1-t0<<endl;
cout.flush();

t0=time(NULL);
for(int k=0;k<50000;k++) V=fast_produit(I,U);
t1=time(NULL);
cout<<"\ntemps pour le fast produit matrice vecteur = "<<t1-t0<<endl;

//fin du programme
return 0;
}
//============================= F I N ===================================

Résultats du programme

V1 vecteur de dimension 0

V2 vecteur de dimension 3
0 0 0
V3 vecteur de dimension 3
1 1 1
V4 vecteur de dimension 3
1 1 1
acces : V2 vecteur de dimension 3

7
1 2 3
vecteur de dimension 3
1 2 3
somme V6=V2+V3 vecteur de dimension 3
2 3 4
différence V7=V2-V3 vecteur de dimension 3
0 1 2
produit V8=5*V2 vecteur de dimension 3
5 10 15
somme V6=V2+V3 vecteur de dimension 3
2 3 4
différence V7=V2-V3 vecteur de dimension 3
0 1 2
produit V8=5*V2 vecteur de dimension 3
5 10 15
temps pour la somme = 22
temps pour la fast somme = 14
Id matrice de dimensions 3 x 3
1 0 0
0 1 0
0 0 1
A matrice de dimensions 3 x 3
1 0 0
0 1 0
0 0 1
somme B=A+Id matrice de dimensions 3 x 3
2 0 0
0 2 0
0 0 2
différence B=A-Id matrice de dimensions 3 x 3
0 0 0
0 0 0
0 0 0
produit B=5*Id matrice de dimensions 3 x 3
5 0 0
0 5 0
0 0 5
fast somme B=A+Id matrice de dimensions 3 x 3
2 0 0
0 2 0
0 0 2
fast différence B=A-Id matrice de dimensions 3 x 3
0 0 0
0 0 0
0 0 0
fast produit B=5*Id matrice de dimensions 3 x 3
5 0 0
0 5 0
0 0 5
matrice vecteur R=A*V2 vecteur de dimension 3
1 2 3
fast matrice vecteur R=A*V2 vecteur de dimension 3
1 2 3
temps pour le produit matrice vecteur = 14
temps pour le fast produit matrice vecteur = 5

On remarquera que les versions ”fast” (programmation par pointeur et algorithmes séquentiels) sont plus
rapides. En particulier, le produit matrice x vecteur est 3 fois plus rapide. Cela résulte du fait que dans la ver-
sion normale du produit matrice x vecteur, comme on accède à un élément (i,j) via la formule (j-1)*dim l+i-
1, on a à faire à chaque étape 4 additions et 2 multiplications contre 1 addition et une multiplication dans
la version rapide (les incréments de pointeurs ont été négligés).