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] ; }