Examen Maˆıtrise MIM math

Transcription

Examen Maˆıtrise MIM math
Examen Maı̂trise MIM math-info, Option C++
le 21 janvier 2003 ,
F. HECHT
Durée 2h, les Documents sont autorisés
Vous ferez attention au « collision de nom » dans les classes. De plus, je vous demande des classes minimales
pour répondre aux questions (tout doit servir, pas opérateur en trop).
Q1 ) Construire une classe P3 qui modélise les points de IR3 comme des tableaux à trois valeurs, tel que l’on
puisse écrire
P3 P(3.0,5.,3) ;
double x=P[1] ,y = P[2] , z = P[3] ;
double xx=P.x() , yy=P.y() , zz=P.z() ;
Où P[1] et P.x() définissent l’abscisse, P[2] et P.y() définissent l’ordonnée et P[3] et P.z() définissent
la côte. Dans tous les cas nous voulons pouvoir changer l’abscisse, l’ordonnée ou la côte d’un point M et
aussi utiliser avec des const comme suit :
P3 M(0,0,0) ;
M.x() = 2 ;
M[1] = 5 ;
M.y() = 3 ;
M[2]=3 ;
const P3 cM(M) ;
cout << cM[1] << " " << cM[2] << " " << cM[3] << endl ;
cout << cM.x() << " " << cM.y() << " " << cM.z() << endl ;
Solution :
class P3 {
double v[3] ; //
public:
P3(double a,double b,double c) { v[0]=a ;v[1]=b,v[2]=c ;}
// version non const retourne une reference pour l’affectation
double & &operator(&int i){ &return v[i-1] ;}
double & x() { return v[1] ;}
double & y() { return v[2] ;}
double & z() { return v[3] ;}
// version const retourne une copie pour eviter la modification de la classe
#ifdef V1
double operator(int i) const { return v[i-1] ;}
double x() const { return v[1] ;}
double y() const { return v[2] ;}
double z() const { return v[3] ;}
#else
//
ou version const retourne une ref. const pour eviter la modification de la classe
const double & operator(int i) const { return v[i-1] ;}
const double & x() const { return v[1] ;}
const double & y() const { return v[2] ;}
const double & z() const { return v[3] ;}
#endif
};
Q2 ) Que faut-il ajouter, si P est de type P3, pour utilisation de P[i] pour i non compris entre 1 et 3 arrête
l’exécution
Une solution :
class P3 {
double v[3] ; //
public:
P3(double a,double b,double c) { v[0]=a ;v[1]=b,v[2]=c ;}
// version non const retourne une reference pour l’affectation
double & operator(int i){ assert(i >0 && i <= 3) ; return v[i-1] ;}
double & x() { return v[1] ;}
double & y() { return v[2] ;}
double & z() { return v[3] ;}
// version const retourne une copie pour eviter la modification de la classe
double operator(int i) const { assert(i >0 && i <= 3) ; return v[i-1] ;}
double x() const { return v[1] ;}
double y() const { return v[2] ;}
double z() const { return v[3] ;}
};
Q3 ) Maintenant, nous voulons pouvoir écrire les opérations vectorielles + et * multiplication à gauche par un
scalaire, que faut-il ajouter.
la Solution : à ajouter après la classe P3.
inline
inline
P3 operator+(const P3 & A,const P3 &)
P3 operator*(double a,const P3 &)
{
{
return P3(A.x+B.x, A.y+B.y, A.z+A.z) ; }
return P3(a*B.x,
a*B.y,
a*A.z) ; }
Q4 ) Définir 2 fonctions Min(A,B) et Max(A,B) qui retournent respectivement le point de coordonnées minimales composantes par composantes (resp. maximales) des points A,B de type P3.
la Solution : à ajouter après la classe P3.
inline
Min(const P3 & A,const P3 &)
{
inline
Max(const P3 & A,const P3 &)
{
return P3( A.x
A.y
A.z
return P3( A.x
A.y
A.z
<
<
<
>
>
>
B.x ?
B.y ?
B.z ?
B.x ?
B.y ?
B.z ?
A.x
A.y
A.z
A.x
A.y
A.z
:
:
:
:
:
:
B.x
B.y
B.z
B.x
B.y
B.z
,
,
); }
,
,
); }
Q5 ) Nous allons définir 2 classes :un Tetraedre qui est défini par les 4 point A,B,C,D de type P3 , et une
Sphere qui est définie par son centre C (de type P3) et son rayon r (de type double). Ecrire les 2 classes
avec 3 fonctions membres (méthode) : P3 Min() ; P3 Max() ; doubleVolume() ; Où Min() et Max()
définissent la boite contenant l’objet, et où Volume() calcul le volume de l’objet.
on ajoute un constructeur de bipoint à la class P3.
P3(const P3 & A,const P3 & B) { v[0] = B[1]-A[1] ;v[1] = B[2]-A[2] ;v[2] = B[3]-A[3] ; }
soit la constante π et les fonctions déterminant suivantes :
const double pi = 4*atan(1.) ; //
la constant pi ajouter #include <cmath>
inline double det(double a11, double a12, double a13,
double a21, double a22, double a23,
double a31, double a32, double a33)
{
return
a12*(a21*a32-a31*a22)
- a23*(a11*a32-a31*a12)
+ a3"*(a11*a22-a21*a12) ; }
inline double det(const P3 & A,const P3 & B,const P3 &C)
{ return det(A.x(),A.y(),A.z(), B.x(),B.y(),B.z(), C.x(),C.y(), C.z()) ; }
class Tetraedre { public :
P3 A,B,C,D ;
Tetraedre(P3 a,P3 b,P3 c,P3 d) : A(a),B(b),C(c),D(d) {}
P3 Min() { return Min(Min(A,B),Min(C,D)) ;}
P3 Max() { return Max(Max(A,B),Max(C,D)) ;}
double Volume { P3 AD(A,D),BD(B,D),CD(C,D) ; return det(AD,BD,CD)/6 ;}
} ; // attention a point virgule après la classe
class Sphere { public :
P3 C ;
double r ;
Tetraedre(P3 a,double rr) : C(a),r(rr) {}
P3 Min() { return C+P3(-r,-r,-r) ;}
P3 Min() { return C+P3(+r,+r,+r) ;}
double Volume { return r*r*r*Pi*4./3.}
} ; // attention a point virgule après la classe
Q6 ) Nous voulons que ces deux classes héritent d’une classe Objet ne contenant que les 3 fonctions membres
P3 Min() ; P3 Max() ; doubleVolume() ; . Que faut-il faire dans les classes Tetraedre, Sphere, et
Objet pour qu’il ne soit pas possible de créer une instance de la classe Objet, et que le code suivant
fonctionne :
Tetraedre T(P3(0,0,0),P3(1,0,0),P3(0,1,0)),P4(0,0,1)) ;
Sphere C(R(0,0,0),1) ;
Objet *obj[2] ;
obj[0] = &T ;
obj[1] = &C ;
double voltotal=0 ;
for (int i=0 ;i<2 ;i++)
voltotal += obj[i]->Volume() ;
cout << " Somme des volumes : " << voltotal << endl ;
class Objet :public Objet { public:
virtual P3 Min() =0 ; // pure virtual pour que la classe ne soit pas instanciable
virtual P3 Min() =0 ;
virtual double Volume =0 ;
};
class Tetraedre { public :
P3 A,B,C,D ;
Tetraedre(P3 a,P3 b,P3 c,P3 d) : A(a),B(b),C(c),D(d) {}
P3 Min() { return Min(Min(A,B),Min(C,D)) ;}
P3 Max() { return Max(Max(A,B),Max(C,D)) ;}
double Volume { P3 AD(A,D),BD(B,D),CD(C,D) ; return det(AD,BD,CD)/6 ;}
} ; // attention a point virgule après la classe
class Sphere :public Objet { public :
P3 C ;
double r ;
Tetraedre(P3 a,double rr) : C(a),r(rr) {}
P3 Min() { return C+P3(-r,-r,-r) ;}
P3 Min() { return C+P3(+r,+r,+r) ;}
double Volume { return r*r*r*Pi*4./3.}
} ; // attention a point virgule après la classe
Q7 ) Trouver les deux erreur, corriger et expliquer ?
inline double & Norme2(const P3 &P)
{ double r(0) ; for (i=1 ;i<=3 ;i++) r+= P[i]*P[i] ;return r ;}
Premièrement la variable i n’est pas déclarée, de plus la fonction retourne une référence sur une variable
locale qui n’existe plus après le return. donc la version correct est :
inline double Norme2(const P3 &P)
{ double r(0) ; for (int i=1 ;i<=3 ;i++) r+= P[i]*P[i] ;return r ;}
Q8 ) Nous avons un ensemble A de n = 106 nombres réels (double) distincts. Cette ensemble est définie via
un pointeur sur des double.
Nous voulons construire F : IR −→ A où F (x) est l’un des éléments de A le plus proche de x. Comment,
modéliser cette fonction et comment la construire sachant qu’elle sera appelée k = 109 fois avec une loi
aléatoire uniforme dans [−1010 , 1010 ]. Donner la complexité de votre algorithme et estimez le temps calcul
sachant que votre ordinateur fait 109 opérations à la second. (remarque : un temps calcul de plus d’une
heure est inacceptable).
: Premierement, il suffit d’utiliser un algorithme de trie en nlog2 n pour trie l’ensemble A, puis avec une
recheche dichothomique il est facile de retrouver les l’éléments ax ,bx de A ∪ −∞, +∞ encadrant x, (il y a
4 cas : x < inf (A), x > sup(A), x ∈]ax , bx [).
la solution est : 1) utiliser la fonction de trie HeapSort du cours,
double & F(double *A,int n,double x)
{ // a des triee ici
int i0=0 ;i1=n-1 ;
if (x <= A[i0]) return A[i0] ;
if (y >= A[i1]) return A[i1] ;
// Dichothomie
while (i1-i0>1)
{
assert( A[iO] < x && x < A[i1]) ;
int im=(i0+i1)/2 ;
if ( x < A[im]) { i1=im ; }
else if ( x > A[im] { i0=im ;}
return A[im] ;
}
if ( x-A[i0] < A[i1] -x)
return A[i0] ;
else
return A[i1] ;
}