Problème en C++

Fermé
ana2sb Messages postés 2 Date d'inscription samedi 22 mai 2004 Statut Membre Dernière intervention 8 mars 2005 - 22 mai 2004 à 11:00
 MIDOU82 - 24 oct. 2008 à 09:55
Bonjour,

Voila je suis un peu déséspérée et vous êtes un peu ma dernière chance pour finir mon tp en C++. Je vous donne l'énoncé :

Concevoir la classe Polynôme, modélisant les polynômes à une indéterminé et à coefficient réels (par exemple 2x(^3(puissance 3, cube)) – 3.4 x +7 ) et contenant au moins :
§ Constructeur(s) et destructeur.
§ La méthode degré() ( renvoie 3 sur l’exemple)
§ La méthode afficher()
§ La méthode coefficient() : retourne le coefficient du terme de degré spécifié.
§ La méthode valeur : retourne la valeur du polynôme quand on donne une valeur à la variable
§ Les 3 opérateurs arithmétiques + - *
§ Les 3 opérateurs composés + = -= *=

Etendre la classe Polynôme pour pouvoir l’utiliser dans une expression algébrique quelconque, comme par exemple : Polynôme P1,P2 ;
// …… Initialisation de P1 et P2
Polynôme résultat = 2*P1 – P2 * 3.14

Je sais que je devrais le faire par moi même mais aprés 4 lignes de codes je plante... Si quelqu'un pourrait réussir à m'aider je lui serait éternellement reconnaissante. Ecrivez moi si vous avez besoin de plus de renseignements ou autre.Merci D'avance.

Julie

9 réponses

marvinrouge
26 mai 2004 à 14:43
Salut, voici mes corrections

#include<iostream>

#include "matrice.h"
#include <vector.h>

using std::cout;
using std::endl;

int main()
{

vector<Matrice> v(3);
for(int i=0;i<3;i++) {cout<<"i= "<<i<<endl; v[i]=identite(3);} // la matrice identite 3*3

cout<<endl;

cout<<v[0]<<v[1]<<v[2]<<endl;
return 0;
}

Il y tout qui marche, tout s'affiche sauf que j'ai un segmentation fault apres l'affichage de v. D'ou cela peut provenir.

Voici mon constructeur par defaut et mon operateur =

Matrice::Matrice() {
l=1;
c=1;
m = new double [1]; // ### LIGNE A AJOUTER ### car sinon l'instruction suivante m[0] = 0. PEUT planter (pas systématique c'est ça qui est fourbe en C/C++ ...)
m[0]=0.; // ### (1)
}


Matrice& Matrice::operator=(const Matrice& mat) // operateur =
{
if(this==&mat) return *this; // pour eviter de faire mat=mat // ### C'EST BIEN, mais AU CONTRAIRE c'est pour PERMETTRE d'ecrire mat = mat; ET QUE CA PLANTE PAS

l=mat.l; // nb ligne
c=mat.c; // nb colonne
ulong cl=c*l; //ulong pour unsigned long
// les trois lignes suivantes permettent de faire A=B ou A et B n'ont pas les memes dimensions. Ainsi les dimensions de A sont modifiees !

if (m!=NULL) { // ### LIGNE A AJOUTER ###
delete [] m;
m=NULL; // evite d'avoir un pointeur fou // ### m = NULL; car même si NULL vaut 0 c'est plus lisible pour unautre développeur
} // ### LIGNE A AJOUTER ###

m=new double[cl]; // on cree de la place dans le tas

for(ulong i=0;i<cl;i++)
m[i]=mat.m[i];

return *this;
}


### Je pense que tu devrais écrire le constructeur de copie (toujors utile) comme ceci

Matrice::Matrice(const Matrice& mat) {
// ### comme on est feignant on initialise une matrice VIDE et ...
l = 0
c = 0;
m = NULL;
// ### .. on profite que tu as déjà écrit un bon opérateur =
*this = mat;
}

### Tu as oublié le destructeur de matrice, la mémoire n'est pas libérée correctemet sans lui !!!

Matrice::~Matrice() {
if (m!=NULL)
delete [] m; // ###inutile de mettre m à NULL ici car c'est le desctueru, au sortir de celui-ci la matrice et donc l; c et m n'existent PLUS !
}


### Regles générales en C++ ###
si ta classe comprte des données membres (ici c, l et m) qui sont
- statiques uniquement, pas besoin d'écrire le constrcuteur de copie et le =, ceux par défuts sont ok
- dynamiques (pointeurs comme m) que tu alloue toi meme par 'new', il VAUT mieux réécrire le constrcuteur de copie et le =, ceux par défuts sont ok car ceux par d&éfauts sont POURRIS , ET il FAUT écrire le destructeur (utilisation de 'delete')

Je ne connais pas bien la STL avec la classe vector
mais ne templates pas ta classe pour utiliser un tableau de matrice ça n'a pas beacoup de sens,
l'utilisation du vector est mieux.

### Tu DOIS réécrire l'opérateur d'affichage cout <<
La syntaxe est étrange et dois se trouver dans le .h dans la partie publique de la classe:

friend ostream& operator<<(ostream& os, const Matrice& mat) {
for (int i=0; i<l; i++) {
for (int j=0; j<c; j++) {
os << m[i*c + j]; // vérifies que i*c + j est bien le coeffcient M(i,j) je suis plus sur de la formule ... les Maths c'est loin
}
os << endl; // Saut de ligne
}
return os; // car on veut pouvoir écrire cout << xxx << yyy << ...; et pas seulement cout << xxx;
}

### A mon avis Le segmentation fault est du
-soit à m[0] = 0 // voir (1) plus haut
-soit = cout << v[0]
-soit au vector que je connais trop mal

est-ce clair ?

marvinrouge
1
marvinrouge
26 mai 2004 à 11:26
Salut Julie,
contactes moi sur marvinrouge@hotmail.com pour ton TP
0


Bonjour

en fait je suis un étudiant en fin de cycl génie mécanique , et on nous a donné un projet en C++ dans le cadre d'un modul qui s'appel code de calcul ,
Et là j'ai du mal à commencer mon programme
je me demmande ,si vous aviez une idée ou je peut trouver des exemples ou des cours pour résoudre des problemmes mécanique par le prog C++
merci
0
Salut Julie, est-ce que Marvinrouge t'a débloquée ? Si oui tant mieux, sinon si tu as encore des pb pour ton tp dis-le moi. Mais normalement il a surement bien du t'aider car j'avais aussi un pb en c++ et Marvinrouge m'a donné un bon tuyau. Je lui fait confiance en tout cas.

Je t'ai demandé au début si tu as été débloquée car la réponse ne prend pas 3 lignes... et si tu as un prgm qui marche ca ne sert plus trop que je te donne une classe polynome.

salut et bon courage,

Pom
0
Salut Marvinrouge. Mille mercis ! Vraiment merci. En effet le seg fault venait de mon constructeur par défaut où il manquait m = new double [1]. mais j'ai bien pris note (et implémenter) toutes tes autres corrections.

Merci aussi pour tes corrections AVEC des explications. Ca me permet d'apprendre plus facilement.

Merci encore
Pom
0
marvinrouge
26 mai 2004 à 16:47
de rien !

les explications c'est naturel: si j'avais juste donné le listing ça t'aurait débloquer 1 fois mais ça t'aurais pas aidé à progresser ce qui est le cas je pense.

@+,

marvinrouge@hotmail.com

PS: personnellement j'initialisais mes matrices à 0/0/NULL mais c'est vrai que mathématiqueemnt ça a pas beaucoup de sens ...

le vecteur de matrice et pas de pointeurs sur des matrices pose un problème je pense: lenteur de recopie (à confirmer):
moi je créait à l'époque un tableau de pointeur de matrice:
Matrice** tab = new Matrice*[nbMatrices];
intérêt: ajout/suppression de matrice rapide sans recopie de toutes (nbMatrices) les matrices
MAIS gestion mémoire un peu plus fine
allocation/désallocation du tableau ET des différentes matrices ...

il faut faire ceci si tu as des GROSSES matrices et BEAUCOUP de matrices, sinon te prends pas la tête utilises directement le vecteur de la STL
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
concernant double * m ou vector<double> j'ai fait une simule et avec vector<double> le produit de deux matrices 2000*2000 fait 55 minutes (j'ai un 850 Mz) et avec double * m ca fait 13 minutes.

J'utilise ma classe de matrice dans deux cas : pour faire des éléments finis. Donc la j'en manipule que très peu (la matrice de rigidité et de masse) mais elles sont grosses (2000*2000). Pour mon stage j'ai maillé à mort le domaine car j'avais une solution qui explosait. J'avais 228 000 sommets !

2e application : lors du controle. Je résoud énormément d'équation différentielle ordianires. Les matrice sont petites 10*10 mais très nombreuses dans le prgm.

Donc concernant ce que tu as dit, il y a un choix à faire...

Pour mon année de DESS, j'ai fait un projet sur du controle d'EDP (l'équation de la chaleur) donc j'avais une énorme matrice (rigidité et masse) que j'incorporais dans des équa diff. Ca mettait trois plombes en matlab donc je passe en c++ et à l'aide d'un ofstream j'affiche le film en matlab (movie)

merci encore de ton aide précieuse.

pom
0
marvinrouge
26 mai 2004 à 17:48
Pas forcément trancher l'un OU l'autre

tu peux utiliser dans le MEME programme l'UN ou l'AUTRE selon la taille des matrice

mais le mieux est qd même d'utiliser des pointeurs pour les perf
(recopier une collection de N matrices quand une seule a changé c'est lourd ...)

Si tes matrices sont TRES grosses 2000x2000,
est-ce qu'elles sont creuses (bcp de 0) ?

car si oui il va falloir que je t'indique une autre méthode possible (plus complexe)

marvinrouge
0
Salut, oui oui les matrices sont archi creuses. Il y a a peu pres 95% des coeff qui sont des 0. J'ai commencé à me pencher sur le codage des matrices creuses (je crois que ca doit s'appeler le morse). J'ai chopé ca dans un livre sur les éléments finis.
Si tu as une idée d'implémentation je suis preneur. Mais je n'ai pas encore pensé à la partie programation. J'en suis encore au stade de comprendre le fonctionnement.

Pom
0
marvinrouge
27 mai 2004 à 09:08
Je connais pas le morse mais il existe une méthode al lieu d'avoir
int col
int lig
double[] coeff

tu as 3 tableaux qui ne contienne QUE les coefficients non nuls
int[] i
int[] j
double[] val

par exemple
lig = 1 3 3
col = 1 1 2
val = 0.8 0.6 0.5

représente la matrice creuse
0.8 0 0
0 0 0
0.6 0.5 0

avantages:
- petite consommation mémoire
-possibilité de représenter des matrices "énormes" exemple Identité(1000000)

inconvénients:
-calculs plus longs car accès à Mat(i,j) plus compliqué (balayer les tableaux de coefficients lig et/ou col)
-création/modification dem atrcies plus long impliquant des réallocation mémoires
- il FAUT réécrire les méthodes
void set(lig, col, val) qui met val dans mat(lig, col)
double get(lig, col) qui retourne mat(lig, col)
constructeur
destructeur
optimiser éventuellement opérateur = , constrcuteru de copie

En fait est ce que les matrices creuses évoluent pas trop c'est à dire partant d'une matrice M(0) dont k coeff sont non nuls, calcules tu M(i) pour i allant de 1 à n (n GRAND) avec la position des coefficients non nul qui change fortement d'un i à un i+1 ?
(je sais pas si je suis clair là ?)

mais comme tu as l'air de bien te débrouiller en C/C++ et que ton projet le demande ça devrait pas te poser trop de pb.

marvinrouge
0
Salut,
le stockage morse est exactement celui que tu viens de me dire. Il existe aussi un autre stockage (presque identique) qui consiste a stocker les éléments non pas par ligne mais par colonne (ou l'inverse). Mais je crois qu'il vaut mieux les stocker par ligne car un ami m'a dit que la mémoire cache était en ligne donc l'acces des éléments est plus rapide quand on la parcous en ligne et non en colonne.

Concernant ton nb d'élément non nul qui varie au cours du temps, cette variation me semble très limitée (par rapport à la quantité de coefficient). Pour me ramener à des conditions de Dirichlet homogènes une solution consiste à mettre des 1 et des 0 au "bon endroit". Donc la ca change. Mais tout dépend du nombre de sommets que j'ai sur le bord du domaine, et bien entendu, plus le maillage est fin, pluls le nombre de sommet est élevé. Ensuite si je veux faire du controle, je dois encore modifier les coeff représentant les sommets sur lesquels j'exerce mon controle.

Mais ceci n'est qu'une question de temps pour les calculs et pas trop de mémoire. pour me rassurer, je dis que c'est l'ordi qui travaille, pas moi... De toute manière, avec des EDP et la métode des éléments finis (volume fini aussi je pense), il faut toujours privilégier le stockage de matrice creuse car on a un gain de mémoire considérable.

Ma prochaine étape consisterait à coder de tel matrice. Je pense que je vais faire une classe dérivée pour éviter d'avoir tout à refaire. Je finis mon projet sur la méthode du tir multiple puis je passe aux matrices creuses.

Pom
0
marvinrouge
27 mai 2004 à 10:41
Resalut Pom, je connais mal dirichlet mais si Dirichlet <=> formule donnant M(i,j) = fonction(i, j)

tu peux coder ta matrice "brutaleemnt" (en fait finement) avec une métode:

double Matrice::get(int col, int lig) {
return fonctionDirichlet(col, lig);
}

je suis peut être àcôté de la plaque ici mais on peut coder des matrices particulières comme ceci exemple pour la matrice identite

class Identite: public Matrice {
double get(int col, lig) {
if (lig==col)
return 1;
else
return 0;
}
}
marvinrouge
0
marvinrouge > marvinrouge
27 mai 2004 à 10:43
j'ai oublié de préciser que la méthode get(col, lig) doit être virtuelle (mot clefs virtual) dans la classe de base (MAtrice) et dans la classe dérivée (Identite)
0
pom > marvinrouge
28 mai 2004 à 10:07
Salut Marvinrouge,
je te vois répondre à toutes les questions de C/C++ du forum. Depuis combien de temps pratiques tu ces logiciels ? Tu m'as l'air franchement bien callé !

Pom
0
pom > marvinrouge
27 mai 2004 à 16:09
Salut Marvinrouge, non non tu n'es pas à coté de la plaque, mais pour Dirichlet
1) je code la matrice sans tenir compte des coeff aux bords du domaine
2) je tiens compte des sommets et je mets des 1 au 0 sur la ligne et colonne en question.

Donc je dois d'abord coder ma matrice (creuse bien entendu)

pom
0
Alex SwartzKaiser
27 mai 2004 à 11:33
Il y a des algorithmes de multiplication plus rapides que la multiplication brutale.
Pour une matrice (n,n), l'algo naif, on fait n^3 multiplications élementaires. (Les additions sont quasiment gratuites)
Avec un algo moins naif (Strassen), on fait n^2.7 multiplications, ca devient rentable pour n > 50 environ, ca dépend du compilateur et de la machine.
0
Salut Alex
saurais-tu ou je pourrais me procurer un tel algo s'il te plait ? Car je manipule très fréquement des matrices 11500*11500 et des matrices 11500*3 (équations de Navier-Stokes). Une fois, j'ai maillé à mort et j'étais à 228000*228000, donc autant dire que je dépasse très largement les 50 sommets.

mais comme le dit Marvinrouge, il faut que je passe aux matrices creuses pour diminuer le nombre de coeff.
0