Partage
  • Partager sur Facebook
  • Partager sur Twitter

Changement de valeurs non voulue

12 février 2019 à 21:54:54

Bonjour,

Je dois lire à partir d'un fichier, une matrice et deux vecteurs et résoudre un système en utilisant la méthode de Jacobi, mais là n'est pas le problème (j'espère qu'il ne le sera pas plus tard).

Mon problème vient du fait que premièrement, quand je lis la matrice, un -4 se transforme en +4.
Ensuite dans dans la fonction jacobi, je demande deux fois de nous afficher x0, une fois au début de la fonction (c'est le bon vecteur) et une fois dans une boucle for (ne regarder que lorsque l=0) et là j'ai par exemple le premier terme qui passe de 1 à 44 sans faire de calculs entre deux.

Et je n'ai strictement aucune idée d'où vient le problème.

Pourriez-vous m'éclairer svp ?

#include <iostream>
#include <fstream>
#include <string.h>
#include <math.h>
using namespace std;

void lectura(double**,double*,double*,int*);
void jacobi(double**, double*, double*, int,double );


int main(){
	double**A;
	double*b;
	double*x0;
	int* n;
	n= new int;
	A=new double*[*n];
	b=new double;
	x0=new double;
	for (int i=0;i<*n;i++){
		A[i]=new double;
	}
	lectura(A,b,x0,n);
	cout<<"jacobi"<<endl;
	jacobi(A,b,x0,*n,0.01);
	cout<<"x="<<endl;
	for(int i=0;i<*n;i++){
		cout<<x0[i]<<endl;
	}
	for (int i=0;i<*n;i++){
		delete A[i];
	}
	delete A;
	delete b;
	delete x0;
	delete n;
}

void lectura(double** A, double* b, double* x0, int* n){

	ifstream datos("jacobi.txt");
	string d,a,bb,xx;
	datos>>d>> *n>>a;
	for(int i=0;i<*n;i++){
		for (int j=0;j<*n;j++){
			datos>>A[i][j];
		}
	}
	datos>>bb;
	for(int i=0;i<*n;i++){
		datos>>b[i];
	
	}
	datos>>xx;
	for(int i=0;i<*n;i++){
		datos>>x0[i];
		//cout<<x0[i];
	}	
	datos.close();
	cout<<"Lecture de A quand on est dans la fonction lectura"<<endl;
	for(int i=0;i<*n;i++){
		for (int j=0;j<*n;j++){
			 cout<<A[i][j]<<" ";
	}
	cout<<endl;
	}
}

void jacobi(double**A, double*b, double*x0, int n,double eps){
	double s1,s2;
	// double norm2=norma(b);
	// double norm=norm2;
	cout<<"Lecture de A quand on est dans la fonction jacobi"<<endl;
	for(int i=0;i<n;i++){
		for (int j=0;j<n;j++){
			 cout<<A[i][j]<<" ";
	}
	cout<<endl;
	}
	cout<<endl;
	cout<<"x0= ";
	for (int i=0;i<n;i++){

		cout<<x0[i]<<",";
	}
	cout<<endl;
	cout<<"on commence la boucle sur l"<<endl;
	for(int l=0;l<1;l++){
		for(int i=0; i<n;i++){
			s1=0;
			s2=0;
			for(int j=0;j<i;j++){
				cout<<"i="<<i<<" j="<<j<<endl;
				cout<<"x0["<<j<<"]="<<x0[j]<<endl;
				s1+=s2+=A[i][j]*x0[j];;
			}
			for(int j=i+1;j<n;j++){
				s2+=A[i][j]*x0[j];
			}
			x0[i]=(1/A[i][i]) *(b[i]-s1-s2);
		}
		
	}
}


(Le code est un peu long, ça fait 1 mois que j'ai commencé le c++)

Edit : je fais mes tests pour le moment avec ceci d'écrit dans mon fichier jacobi.txt :

dim: 3
A:
1 3 4
3 5 -4
4 7 -2
b:
50
2
31
x0:
1
1
1

-
Edité par tenn004 12 février 2019 à 21:56:21

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 5:17:05

Bonjour,

Le langage que tu apprends depuis un mois n'est pas le C++ mais le langage C. Ce que tu as écris n'est pas du C++. Ça utilise des stream (qui sont bien du C++) mais le reste est du C.
En C++ on n'utilise beaucoup moins les pointeurs (c'est compliqué, non sûr, et peu compatible avec les exceptions) et jamais jamais on n'utilise les allocations par new et delete. On peut faire des erreurs d'allocation comme C et tu en as justement fait plein.
Lignes 3 et 4 : ne jamais inclure des fichiers entête du C tels que <string.h> ou <math.h>. Il faut utiliser à la place du second <cmath> et ne pas utiliser les string du C, le C++ fait mieux en utilisant <string>.
Ligne 5 : using namespace std; a été créé pour un problème de portage des codes d'il y a 20 ans. Ton code n'est pas un vieux code, il n'a pas besoin de cet adaptateur.
Lignes 7 et 8 : Ici l'utilisation de pointeurs inquiète, d'autant qu'il y a un double pointeur, on n'a jamais ça en C++. Pour gérer une matrice, on utilise un type Matrice que l'on se crée en quelques lignes, et pour le passage des paramètres on utilise des références au lieu de pointeurs.

Je passe à quelques problèmes concrets :
Ligne 17 : tu alloues un tableau de *n pointeurs; comme a cet instant *n n'a jamais été rempli, tu alloues un tableau d'une taille choisie au hasard de pointeurs!
Lignes 18 et 19 et 21 : tu alloues la place pour un seul double, plus loin tu utilises ces pointeurs pour y mettre 3 double, aïe!
Ligne 33 : tu libères A comme un pointeur alors que c'est un tableau!
Ligne 95 : je doute que l'utilisation de 2 fois += dans une unique expression fasse ce que tu souhaites, écris le en 2 lignes.

#include <iostream>
#include <fstream>
#include <cmath>
#include <vector>
#include <algorithm>
#include "matrice.h"

void lectura( Matrice& m, std::vector<double>& b, std::vector<double>& x0 );
void jacobi( Matrice const& m, std::vector<double>const& b, std::vector<double>& x, double eps );

int main() {
    Matrice  A;
    std::vector<double>  b;
    std::vector<double>  x0;

    lectura( A, b, x0 );
    std::cout << "jacobi\n";
    jacobi( A, b, x0, 0.01 );
    std::cout << "x=";
    for ( auto xi : x0 ) {
        std::cout << xi << std::endl;
    }
}

void lectura( Matrice& A, std::vector<double>& b, std::vector<double>& x0 ) {
    std::ifstream  datos( "jacobi.txt" );
    std::string  d, a, bb, xx;

    size_t  n;
    datos >> d >> n >> a;
    A.resize( n );
    b.resize( n );
    x0.resize( n );

    datos >> A;  // lire directement toute la Matrice, elle sait le faire, on lui a appris
    datos >> bb;
    for ( auto& bi : b )  // accès successifs à tous les éléments de b
        datos >> bi;
    datos >> xx;
    for ( auto& xi : x0 ) // accès successifs à tous les éléments de x0
        datos >> xi;

    std::cout << "Lecture de A quand on est dans la fonction lectura\n";
    std::cout << A << std::endl; // écrire directement toute la Matrice
}

Et on crée un fichier matrice.h qui décrit la classe Matrice

#ifndef MATRICE_HEADER
#define MATRICE_HEADER

#include <vector>
#include <iostream>

class Matrice {
public:
   Matrice() = default;
   Matrice( size_t n ) : n{n} , data(n*n) {}
   void resize( size_t n ) {
      this->n = n;
      data.resize( n * n );
   }

   friend std::ostream& std::operator<<( std::ostream& ss , Matrice const& m ) {
      for ( size_t j = 0 ; j < n ; ++j ) {
         for ( size_t i = 0 ; i < n ; ++i )
            ss << m[j][i];
         endl( ss );
      }
      return  ss;
   }
   friend std::istream& std::operator>>( std::istream& ss , Matrice& m ) {
      for ( size_t j = 0 ; j < n ; ++j )
         for ( size_t i = 0 ; i < n ; ++i )
            ss >> m[j][i];
      return  ss;
   }

   double const* operator[]( size_t lgn )const {
      return  &data[n * lgn];
   }
   double* operator[]( size_t lgn ) {
      return  &data[n * lgn];
   }

private:
   size_t  n = 0;
   std::vector<double>  data;
};

#endif
  • Partager sur Facebook
  • Partager sur Twitter

En recherche d'emploi.

13 février 2019 à 11:02:58

Bonjour,

Merci beaucoup !

Cependant, l'utilisation des pointeurs (et notamment des doubles pointeurs) m'est imposée...

Et à vrai dire je ne sais pas ce qu'est le C, j'utilise juste ce que mon prof nous montre (d'où les doubles pointeurs) et je ne suis pas du tout informaticien de base. Ceci est juste une introduction au C++ et donc j'ai du mal à comprendre ton code.

Mais je vais au moins essayer de m'en inspirer pour réparer petit à petit tout ça

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 11:07:03

tenn004 a écrit:

introduction au C++

tenn004 a écrit:

l'utilisation des pointeurs (et notamment des doubles pointeurs) m'est imposée...

o_O

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 11:09:06

Emrak a écrit:

tenn004 a écrit:

introduction au C++

tenn004 a écrit:

l'utilisation des pointeurs (et notamment des doubles pointeurs) m'est imposée...

o_O

Oui je sais... D'autant plus qu'on est en Master de maths, et donc tout ce qu'on a programmé c'est avec du Python, Matlab ou éventuellement Fortran...

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 11:55:06

Peux-tu envoyer ton prof. sur ce forum, histoire qu'on le briefe sur ce qui s'est passé dans le C++ depuis au moins 30 ans ?
  • Partager sur Facebook
  • Partager sur Twitter
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
13 février 2019 à 16:13:21

bacelar a écrit:

Peux-tu envoyer ton prof. sur ce forum, histoire qu'on le briefe sur ce qui s'est passé dans le C++ depuis au moins 30 ans ?


Haha, je sais si ça changera beaucoup ce qu'il veut qu'on fasse
  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 16:43:01

Peut-être, peut-être pas, mais au moins il saura qu'il fait apprendre de la merd.. :-°

-
Edité par bacelar 13 février 2019 à 16:43:17

  • Partager sur Facebook
  • Partager sur Twitter
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
13 février 2019 à 16:50:22

C'est un prof de maths, ça doit être pour ça ^^

Pour en revenir à mon problème j'ai remarqué que si je mets

A=new double*[*n];
for (int i=0;i<*n;i++){
        A[i]=new double[*n];
}
b=new double[*n];
x0=new double[*n];

dans la fonction lectura, juste après la ligne datos>>d>>*n>>a; ma matrice et mes vecteurs sont bien lus correctement (si toujours dans lectura je les affiche à l'écran, il n'y a pas de soucis). Mais une fois lectura exécutée, si je les affiche de nouveaux, mais dans le main() cette fois-ci, j'ai quelque chose de totalement différent.

En fait je pense que le problème vient du fait que ma fonction lectura prend en argument des pointeurs de tableau dont on ne connaît pas encore la dimension, puisque cette dimension nous est donnée par le fichier que l'on doit lire.

Cela dit, sachant que dans mon exemple la dimension vaut 3, j'ai essayé de les déclarer de la bonne taille avant d'exécuter lectura, j'obtiens toujours le même résultat

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 17:36:41

Non, mais même un dev C++ pro fera des erreurs avec un code pareil et évitera d'ecrire un truc comme ca. On le fait que quand on n'a pas le choix. Alors faire ecrire ce genre de code a des debutants...

Au pire, un dev C++ encapsulera les types dans des classes, pour simplifier le code et faciliter l'ecriture. En plus, on découperait le code en fonctions plus simples et plus facilement testables avec des tests unitaires, pour trouver plus facilement les erreurs. (Je suppose que tu n'as pas de tests unitaires ?)

Il faut que tu débuges ton code et que tu fasses au pas a pas, pour trouver quand le calcul est faux.

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 19:05:01

Il y a l'utilisation de variables non initialisées, de VLA (interdite en C++, obsolète en C) dans tous les sens (sans compter les new et delete à qui mieux mieux).

Vous faites n'importe quoi (mais c'est pas de votre faute mais de votre prof. qui n'a rien compris à la programmation).

Utilisez le code de @Dalfab, il est beaucoup plus simple et ne fait pas n'importe quoi.

Vous écrivez et lisez en mémoire complètement au pif.

Quand vous affichez dans votre fonction qui vient d'écrire au milieu de n'importe où les données qu'elle vient d'écrire, c'est normal, parce qu'un autre code mal foutu n'est allé écrire au même endroit comme un gros sagouin et que les variables mal initialisées n'ont pas changées.

Mais quand vous sortez de la fonction, il y a beaucoup de code qui c'est exécuter (dépilage du contenu dans la pile, initialisation ou modification des variables pas initialisées, etc...). Si vous arriviez à voir le bordel après être sortie de la fonction, cela tiendrait du miracle et cela ne marcherait pas très longtemps.

Utilisez le code de @Dalfab, il est beaucoup plus simple et ne fait pas n'importe quoi.(BIS)

-
Edité par bacelar 13 février 2019 à 19:07:30

  • Partager sur Facebook
  • Partager sur Twitter
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
13 février 2019 à 19:05:54

Bonsoir @tenn004, 

vous avez tout à fait raison de vouloir considérer ce fichier comme un fichier C++. C'est votre droit le plus strict dans un cadre pédagogique.

j'ai pris le temps de regarder votre code, et avec plusieurs tests, il semble que déjà vos données du fichier venant de "jacobi.txt" ne soient pas lues correctement, d'après quelques basiques.

Cela expliquerait peut-être pourquoi ça ne fonctionne pas.

Je serais curieux de savoir comment vous pourriez améliorer la lecture, car à priori, votre ifstream est correctement défini.

Pourtant, en lecture la récupération des données dans l'étape de lecture, ne se fait pas correctement

merci de me tenir informé si vous arrivez à corriger votre lecture

EDIT

J'ai pris le temps de modifier votre code et apparemment, d'après ce que j'ai fait votre -4 n'est pas transformé en +4 chez moi :

#include <iostream>
#include <fstream>
#include <string>
#include <math.h>
using namespace std;

void lectura(double**,double*,double*,int*);
void jacobi(double**, double*, double*, int,double );


int main(){
    double**A;
    double*b;
    double*x0;
    int* n;
    n= new int;
    A=new double*[*n];
    b=new double;
    x0=new double;
    for (int i=0;i<*n;i++){
        A[i]=new double;
    }
    lectura(A,b,x0,n);
    cout<<"jacobi"<<endl;
    jacobi(A,b,x0,*n,0.01);
    cout<<"x="<<endl;
    for(int i=0;i<*n;i++){
        cout<<x0[i]<<endl;
    }
    for (int i=0;i<*n;i++){
        delete A[i];
    }
    delete A;
    delete b;
    delete x0;
    delete n;
}

void lectura(double** A, double* b, double* x0, int* n){

    ifstream datos("jacobi.txt");
    if(!datos)
        cout<<"problème";
    string d,a,bb,xx;
    datos>>d>> *n>>a;
    cout<<d<<endl;
    cout<<*n<<a;


    for(int i=0;i<*n;i++){
        for (int j=0;j<*n;j++){
            datos>>A[i][j];
            cout<<A[i][j];
        }
    }
    cout<<endl;
    datos>>bb;
    for(int i=0;i<*n;i++){
        datos>>b[i];
        cout<<b[i];
    }
    cout<<endl;
    datos>>xx;
    for(int i=0;i<*n;i++){
        datos>>x0[i];
        cout<<x0[i];
    }
    datos.close();
    cout<<"Lecture de A quand on est dans la fonction lectura"<<endl;
    for(int i=0;i<*n;i++){
        for (int j=0;j<*n;j++){
    //         cout<<A[i][j]<<" ";
    }
    cout<<endl;
    }
}

void jacobi(double**A, double*b, double*x0, int n,double eps){
    double s1,s2;
    // double norm2=norma(b);
    // double norm=norm2;

    cout<<"Lecture de A quand on est dans la fonction jacobi"<<endl;
    for(int i=0;i<n;i++){
        for (int j=0;j<n;j++){
             cout<<A[i][j]<<" ";
    }
    cout<<endl;
    }
    cout<<endl;
    cout<<"x0= ";
    for (int i=0;i<n;i++){

        cout<<x0[i]<<",";
    }
    cout<<endl;

    cout<<"on commence la boucle sur l"<<endl;
    for(int l=0;l<1;l++){
        for(int i=0; i<n;i++){
            s1=0;
            s2=0;
            for(int j=0;j<i;j++){
                //cout<<"i="<<i<<" j="<<j<<endl;
                //cout<<"x0["<<j<<"]="<<x0[j]<<endl;
                s1+=s2+=A[i][j]*x0[j];;
            }
            for(int j=i+1;j<n;j++){
                s2+=A[i][j]*x0[j];
            }
            x0[i]=(1/A[i][i]) *(b[i]-s1-s2);
        }

    }
}

avec le fichier   jacobi.txt tel que je vous l'envoie :

dim 
3
A
1 3 4
3 5 -4
4 7 -2
b
50
2
31
x0
1
1
1



Il faut BIEN PENSER à l'ajouter au projet

@Tenn004, s'il vous plaît, continuez de progresser en C++ et n'écoutez pas ceux qui sont hors-la-loi sur ce forum et qui pratiquent le harcèlement en ligne, et celui qui est là pour décourager autrui, et ils sont plusieurs sur ce forum. Avancez en C++

-
Edité par pseudo-simple 13 février 2019 à 19:45:48

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 19:33:17

YES, man a écrit:

vous avez tout à fait raison de vouloir considérer ce fichier comme un fichier C++. C'est votre droit le plus strict

Il peut aussi considérer que c'est une "mite en pullover", ca ne veut pas dire que ca le sera effectivement.

C'est pas parce qu'un compilateur C++ peut compiler du code C que le code est du C++. Il y a des choses qui ne sont pas valides selon la norme C++, qui ne correspondent pas aux bonnes pratiques du C++, etc. Même en C++ old school, ce code n'est pas valide. Et en fait, même en C, ce code n'est pas valide.

Il faudrait grandir un peu et arrêter de penser que si on pense très fort à quelque chose, cela devient vrai.

Tu n'as même pas vu les erreurs dans le code, alors que Dalfab en a signalé plusieurs. 

YES, man a écrit:

@Tenn004, s'il vous plaît, continuez de progresser en C++ et n'écoutez pas ceux qui sont hors-la-loi sur ce forum et qui pratiquent le harcèlement en ligne et ils sont plusieurs sur ce forum. Avancez en C++

Merci pour la diffamation.

Bon, pour les autres qui sont réellement intéressé pour apprendre correctement le C++ (pas comme Yes man, qui après plus de 2 ans de C++ ne voit pas des erreurs évidentes) :

n= new int;

Ca, c'est une valeur non intialisée. Donc qui prend une valeur aléatoire. Cette valeur est utilisée pour intialiser un tableau. Donc un comportement indéfini (UB undefined behavior).

C'est juste un code FAUX. 

delete A;

Ca, c'est également un code FAUX. Quand on utilise new[], il faut utiliser delete[].

datos>>A[i][j];

Ca, c'est également un code FAUX. Parce que c'est des accès hors limites des tableaux alloués.

Je ne vais reprendre tout le code, pour montrer toutes les erreurs, je crois que ce n'est pas nécessaire. Maintenant, libres a vous de suivre les conseils des personnes que vous considérez compétentes en C++.

@Yes, Man : sur ce point, il va falloir aussi grandir : repeter en permance que tu te trompes, c'est pas du harcelement si tu te trompes effectivement tout le temps.

-
Edité par gbdivers 13 février 2019 à 19:51:21

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 19:52:11

@Tenn004, n'écoutez pas les harceleurs. Si j'avais écouté toutes les insultes de gbdivers, j'en serais encore loin. Si vous l'écoutez, il va vous décourager. Ses insultes sont bien enregistrées sur le forum

@Tenn04, continuez ce que vous faîtes : cette méthode marche. la perfection dès le départ, c'est pour ces bisounours harceleurs moqueurs. Votre code est intéressant pour un début, et pour comprendre des choses.

J'espère avoir pu le faire tourner.

L'optimisation et la propreté du code, cela viendra ensuite.

C'est cela qui donne beaucoup d'intérêt au cours de Mathieu Nébra, que je vous invite à découvrir, bien que les harceleurs du forum , viendront se moquer de son cours.

Ce cours m'a appris énormément de choses, et je ne peux que vous le recommander.

-
Edité par pseudo-simple 13 février 2019 à 19:55:26

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 19:56:52

YES, man a écrit:

@Tenn004, n'écoutez pas les harceleurs. Si j'avais écouté toutes les insultes de gbdivers, j'en serais encore loin. Si vous l'écoutez, il va vous décourager. Ses insultes sont bien enregistrées sur le forum

Ben... vu que tu n'as pas vu les erreurs dans le code, oui, effectivement, tu es encore loin.

Et dire que tu te trompes, ce n'est ni une insulte, ni du harcelement. Mais c'est ce qui fait que tu n'avances pas.

Et tu n'aides pas Tenn004, puisque tu lui donnes du code faux. 

YES, man a écrit:

la perfection dès le départ, c'est pour ces bisounours harceleurs moqueurs. Votre code est intéressant pour un début, et pour comprendre des choses.

J'espère avoir pu le faire tourner.

L'optimisation et la propreté du code, cela viendra ensuite.

Le code n'est pas "correct mais pas optimisé et pas propre". Il est FAUX. Arrêtes de dire n'importe quoi, tu n'aides pas Tenn004.

-
Edité par gbdivers 13 février 2019 à 19:58:43

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 19:57:17

Merci des conseils Yes Man,

Cependant je suis venu ici parce que j'ai des problèmes et que j'aimerais les comprendre et les résoudre. Alors oui mon code se compile, mais je vois bien qu'il ne fonctionne pas.

Et les autres, même s'ils cassent tout ce que j'ai fais, me disent ce qui ne va pas. Et s'ils cassent tout, c'est que tout ne va pas. Alors je préfère tout recommencer d'une autre manière demain parce qu'on m'a dit que ce que j'ai fais est pourri plutôt que de m'entêter sur quelque chose que je ne peux pas résoudre

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 20:04:37

Ok Tenn004, si c'est un choix que tu fais en ton âme et conscience, alors  je le respecte tout à fait puisque c'est de ton choix que ça vient.

Est-ce que tu peux me dire, si chez toi, le code que je t'ai envoyé, malgré ses imperfections, donne le résultat que tu attends car chez moi , le -4 n'est pas transformé en 44 ?

Merci

-
Edité par pseudo-simple 13 février 2019 à 20:11:33

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 20:10:23


YES, man a écrit:

Est-ce que tu peux me dire, si chez toi, le code que je t'ai envoyé, malgré ses imperfections, donne le résultat que tu attends car chez moi , le -4 n'est pas transformé en 44 ?

Merci

Le 4 est toujours transformé quand A est lue dans la fonction jacobi



-
Edité par tenn004 13 février 2019 à 20:17:57

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 20:18:09

J'ai vraiment envie de t'aider . Je pense que l'on peut résoudre le problème ensembe

Peux-tu me dire ce que tu cherches à faire dans la ligne :

     s1+=s2+=A[i][j]*x0[j];;

à quel partie de l'algorithme de Jacobi ça correspond précisément ?

Je te pose la question car c'est la première fois que je vois ce genre de chose :

 s1+=s2+=A[i][j]*x0[j];;

 Comment traduirais-tu en "développé" cette ligne s'il te plaît ?

Je pense que cela ne fait pas partie de l'algorithme. Tu dois retirer le s1+= de cette ligne à mon avis afin de garder les termes qui ne sont pas diagonaux dans tes deux sommes

-
Edité par pseudo-simple 13 février 2019 à 20:28:09

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 20:25:04

tenn004 a écrit:

Cependant je suis venu ici parce que j'ai des problèmes et que j'aimerais les comprendre et les résoudre. Alors oui mon code se compile, mais je vois bien qu'il ne fonctionne pas.

Bon, on va laisser yes man gesticuler dans son coin, on revient aux choses sérieuses.

J'ai fait un EDIT, je ne sais pas si tu l'as vu. Je te le remets :

gbdivers a écrit:

n= new int;

Ca, c'est une valeur non intialisée. Donc qui prend une valeur aléatoire. Cette valeur est utilisée pour intialiser un tableau. Donc un comportement indéfini (UB undefined behavior).

C'est juste un code FAUX. 

delete A;

Ca, c'est également un code FAUX. Quand on utilise new[], il faut utiliser delete[].

datos>>A[i][j];

Ca, c'est également un code FAUX. Parce que c'est des accès hors limites des tableaux alloués.

Comme tu l'as constaté, un code qui compile n'est pas forcément un code valide (ie un code qui fait correctement ce qu'on attend de lui. Cf https://fr.wikipedia.org/wiki/Qualit%C3%A9_logicielle )

En particulier, les UB (comportement indéfinis) font n'importe quoi (comme le nom l'indique). Donc ca peut crasher, ca peut retourner une valeur fausse. Parfois, ca peut même fonctionner correctement chez quelqu'un et faire n'importe quoi chez une autre personne.

Dis autrement, "ça marche chez moi" n'a aucune valeur pour savoir si un code est valide. Pour écrire un code valide, on va donc se baser sur des "bonnes" pratiques (un exemple : http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines ), sur des diagnostiques du compilateurs, sur des outils externes, sur des tests et des preuves, etc. On a pleins d'outils, il faut les utiliser.

Le problème de la gestion de la mémoire est un problème très complexe. Même les plus grands experts du C++ disent qu'ils utilisent cela avec beaucoup de précautions. Et n'ont jamais la garantie de ne pas faire d'erreur. (On l'appelle "the 30 years old problem"...) Il est extrêmement facile d'appeler un delete au lieu d'un delete[], ou d'oublier d'appeler delete, ou d'appeler 2 fois delete, ou d'utiliser un pointeur invalide.

LA solution, en C++, est d'utiliser le concept RAII ( https://fr.wikipedia.org/wiki/Resource_acquisition_is_initialization ). C'est très simple : au lieu d'écrire 

p = new int[N];
...
delete p; // FAUX !

On va mettre ce code dans des classes :

class Pointer {
public:
    Pointer(int i) { p = new int(i); }
    ~Pointer() { delete p; }
private:
    int* p = nullptr;
};

class Array {
public:
    Array(int i) { p = new int[i]; }
    ~Array() { delete[] p; }
private:
    int* p = nullptr;
};

Et rien qu'avec cela, tu es sur que la version correcte de delete ou delete[] est appelée.

Simple et efficace.

Et comme on est fainéant, on n'écrit pas ces classes RAII si on n'a pas besoin de le faire. On utilise les classe RAII de la bibliotheque standard : std::array, std::vector, std::unique_ptr, std::shared_ptr, etc.

Et c'est bien pour cela qu'on dit que le C et le C++ sont complètement différents. Certaines syntaxes sont proches, mais en fait, la philosophie de ces langages n'ont rien à voir. En C++, on va créer des types (des classes) qui vont être réutilisables, plus simple d'utilisation, et surtout vont apporter des garanties fortes que le code est correct.

C'est exactement ce qu'a proposé Dalfab, avec sa classe Matrix. C'est la "bonne" approche en C++.

-
Edité par gbdivers 13 février 2019 à 20:32:35

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 20:26:33

YES, man a écrit:

J'ai vraiment envie de t'aider . Je pense que l'on peut résoudre le problème ensembe

Peux-tu me dire ce que tu cherches à faire dans la ligne :

     s1+=s2+=A[i][j]*x0[j];;

à quel partie de l'algorithme de Jacobi ça correspond précisément ?

Je te pose la question car c'est la première fois que je vois ce genre de chose :

 s1+=s2+=A[i][j]*x0[j];;

 Comment traduirais-tu en "développé" cette ligne s'il te plaît ?

Je pense que cela ne fait pas partie de l'algorithme. Tu dois retirer le s1+= de cette ligne à mon avis

-
Edité par YES, man il y a moins de 30s

Cette ligne devait être une erreure dûe à un copier coller.

C'est juste s1+=A[i][j]*x0[j];

A vrai dire j'écris maintenant ma matrice comme si c'était un vecteur de longueur n², ça me permet d'utiliser un seul pointeur.

De plus lors des premières lignes j'ai déclaré la longueur de A comme étant 9, et celles de b et x0 comme étant 3 (je verrai plus tard comment faire lorsqu'on ne sait pas la dimension de la matrice)

De ce que j'ai à présent, A ne change plus qu'elle que soit l'endroit où elle est appelé.

Cependant dans jacobi, x0 est bon juste avant la boucle for, mais à l'intérieur non

@bgdriver, merci beaucoup, c'est très bien expliqué !
Je vais essayer comme ça pour le moment,puis revenir ensuite, car le problème est que l'on vient à peine d'aborder les classes et que ce prof est très à cheval sur les méthodes demandées. Mais si ça me permet d'y arriver au moins une fois, je vais tenter



-
Edité par tenn004 13 février 2019 à 20:31:28

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 20:28:54

@Tenn004 :

Je te pose la question car c'est la première fois que je vois ce genre de chose :

 s1+=s2+=A[i][j]*x0[j];;

Je pense que cela ne fait pas partie de l'algorithme. Tu dois retirer le s1+= de cette ligne à mon avis afin de garder les termes qui ne sont pas diagonaux dans tes deux sommes pour les bons termes de la matrice de Jacobi.

Pour le reste, je suis en train de vérifier

EDIT :

j'ai compris une deuxième erreur:

si tu veux avoir l'espoir à une solution valide, tu devrais en plus ajouter une condition de convergence, ce que tu n'as pas pour l'instant dans ton code.

Pour l'instant, ton algorithme ne fait qu'une seule itération.

Quand tu ajoutes un epsilon pour ta condition infinitésimale, alors tu vas converger vers ta solution après un certain nombre d'itérations

-
Edité par pseudo-simple 13 février 2019 à 20:37:59

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 20:37:52

tenn004 a écrit:

@bgdriver, merci beaucoup, c'est très bien expliqué !

Je vais essayer comme ça pour le moment,puis revenir ensuite, car le problème est que l'on vient à peine d'aborder les classes et que ce prof est très à cheval sur les méthodes demandées. Mais si ça me permet d'y arriver au moins une fois, je vais tenter

C'est (malheureusement) classique. Est-ce que tu peux utiliser std::vector au moins ?

Mais de toute façon, même sans écrire tes propres classes, ton code n'a aucune chance de fonctionner correctement si tu as des erreurs dans ton code pour les allocations. Tous les plus gros problèmes ont été signalés par Dalfab. Si tu ne comprends pas certains points, tu peux demander des explications. En attendant, je te laisse jouer avec yes man.

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 20:38:02

@Yesman, pour ce qui est de la partie mathématique, il n'y a aucun soucis avec, c'est un algorithme que j'ai déjà fait sur Matlab, ainsi que ses variantes. Le but de l'exercice n'est pas savoir faire l'algorithme de jacobi mais bien de pratiquer le c++.

Quant à la convergence je sais très bien, mais tant que le code n'est pas bon, ça ne sert à rien de prendre le risque de faire encore plus d'erreur avec des fonctions calculant les normes de vecteurs (qui sont déjà prêtes en bas, et commentées et que je n'ai pas partagées ici car inutiles pour le moment).

@bgdivers, je pense pouvoir utiliser std::vector (en tout cas je l'ai déjà utilisé pour un autre travail). Sauf qu'il est précisé d'utiliser les pointeurs. Je vais demander de détails sur ses restrictions

-
Edité par tenn004 13 février 2019 à 20:40:35

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 20:57:03

Ok, même en utilisant les pointeurs, on peut faire les choses un peu mieux.

Pour commencer, une evidence : si on a des etapes A, B, C, etc, on ne commence pas par corriger l'etape K. On fait dans l'ordre : on verifie etape par etape que les choses se passent correctement.

Et pour simplifier les vérifications, on sépare le code en partie plus simple a verifier. Avec des classes ou des fonctions, peut importe. Mais on découpe le code dans tous les cas.

Dans ton code, on a un ensemble fonctionnel très clair : ce tableau 2D. Sans classe, il faut quand même séparer les manipulations de ce tableau dans des fonctions. Donc la première chose a faire :

- écrire les fonctions pour allouer, initialiser, libérer et accéder a ce tableau 2D

- écrire les tests pour vérifier que les fonctions sont correctes

Ecrire ces fonctions est un exercice très classique en C. C'est la première etape.

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 21:31:07

@Tenn004, chez moi, les petites modifications que j'ai apportées à ton code, m'ont permis, en premier lieu d'avoir un code, certes nop optimisé, mais fonctionnel.

Il faut évidemment vérifier que utilises bien delete[] à la place de delete quand tu as un tableau. C'est une erreur très classique. 

POur le reste, ton code, fonctionne chez moi (codeblocks+gcc), et je n'ai pas de modification à la lecture.

Attention, j'ai modifié ton fichier avec la matrice de notre cher Mr Jacobi en enlevant les ":" pour faciliter la lecture de la matrice et éviter la transformation de 4 en autre chose.

D'ailleurs le cout, le montre.

Fais un if(!datos) pour vérifier que ton flux en lecture de fichier s'est bien ouvert.

Si tu as l'occasion de faire la boucle avec la condition de convergence, tiens-moi informé, ça m'intéresse de vérifier ton code en le faisant tourner sur ma machine.

Prends soin de toi

-
Edité par pseudo-simple 13 février 2019 à 21:35:21

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 21:40:16

YES, man a écrit:

en premier lieu d'avoir un code, certes nop optimisé, mais fonctionnel.

Tu n'as pas compris quoi dans "ce code est FAUX" ?

Tu appelles cela "fonctionnel" ? Tu peux expliquer comment la ligne "A=new double*[*n];" a la moindre chance d'etre correcte ? Tu initialises la taille de ton tableau avec des valeurs aléatoires !!!



-
Edité par gbdivers 13 février 2019 à 21:41:35

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 22:23:47

Bonsoir Tenn004,

voici un code, non optimal et fonctionnel, qui répond encore mieux à vos attentes, et  avec le concept plus avancé de référence sur des pointeurs pour le passage dans la fonction de lecture. Prenez soin de vous.

#include <iostream>
#include <fstream>
#include <string>
//#include <math.h>
using namespace std;

void lectura(double**&,double*&,double*&,int*&);
void jacobi(double**, double*, double*, int,double );


int main(){
    double**A;
    double *b;
    double *x0;
    int *n;
    /*
    n= new int();
    A=new double*[*n];
    b=new double;
    x0=new double;

    for (int i=0;i<*n;i++){
        A[i]=new double;
    }
*/
    lectura(A,b,x0,n);
    cout<<"jacobi"<<endl;
    jacobi(A,b,x0,*n,0.01);
    cout<<"x="<<endl;
    for(int i=0;i<*n;i++){
        cout<<x0[i]<<endl;
    }
    for (int i=0;i<*n;i++){
        delete[] A[i];
    }
    delete[] A;
    delete[] b;
    delete[] x0;
    delete n;
}

void lectura(double**& A, double*& b, double*& x0, int*& n){


    n= new int();

    ifstream datos("jacobi.txt");
    if(!datos)
        cout<<"problème";
    string d,a,bb,xx;
    datos>>d>> *n>>a;
    cout<<d<<endl;
    cout<<*n<<a;


/*
    A=new double*[*n];
*/
    for (int i=0;i<*n;i++){
        A[i]=new double[*n];
    }

    b=new double[*n];
    x0=new double[*n];
    cout<<"test sur n : "<<*n<<endl;
    for(int i=0;i<*n;i++){
        for (int j=0;j<*n;j++){
            datos>>A[i][j];
            cout<<A[i][j];
            cout<<"voici i : "<<i<<" voici j : "<<j<<endl;
        }

    }
    cout<<endl;
    datos>>bb;
    for(int i=0;i<*n;i++){
        datos>>b[i];
        cout<<b[i];
    }
    cout<<endl;
    datos>>xx;
    for(int i=0;i<*n;i++){
        datos>>x0[i];
        cout<<x0[i];
    }
    datos.close();
    cout<<"Lecture de A quand on est dans la fonction lectura"<<endl;
    for(int i=0;i<*n;i++){
        for (int j=0;j<*n;j++){
             cout<<A[i][j]<<" ";
    }
    cout<<endl;
    }
}

void jacobi(double**A, double*b, double*x0, int n,double eps){
    double s1,s2;
    // double norm2=norma(b);
    // double norm=norm2;

    cout<<"Lecture de A quand on est dans la fonction jacobi"<<endl;
    for(int i=0;i<n;i++){
        for (int j=0;j<n;j++){
             cout<<A[i][j]<<" ";
    }
    cout<<endl;
    }
    cout<<endl;
    cout<<"x0= ";
    for (int i=0;i<n;i++){

        cout<<x0[i]<<",";
    }
    cout<<endl;

    cout<<"on commence la boucle sur l"<<endl;
    for(int l=0;l<1;l++){
        for(int i=0; i<n;i++){
            s1=0;
            s2=0;
            for(int j=0;j<i;j++){
                //cout<<"i="<<i<<" j="<<j<<endl;
                //cout<<"x0["<<j<<"]="<<x0[j]<<endl;
                s1+=A[i][j]*x0[j];;
            }
            for(int j=i+1;j<n;j++){
                s2+=A[i][j]*x0[j];
            }
            x0[i]=(1/A[i][i]) *(b[i]-s1-s2);
        }

    }
}



-
Edité par pseudo-simple 13 février 2019 à 22:26:33

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2019 à 22:46:22

YES, man a écrit:

voici un code, non optimal et fonctionnel

Non, toujours pas. Ton code est encore faux. A quel moment initialises-tu A avant de l'utiliser ?

YES, man a écrit:

avec le concept plus avancé de référence sur des pointeurs 

C'est juste inutile de mélanger des pointeurs et de références : les pointeurs suppriment les bénéficent des références.

Je n'ai pas regardé le reste du code, mais de toute façon, ce qu'il faut corriger en premier, c'est la démarche. Faire les choses dans l'ordre, écrire des codes simples et testables.

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
13 février 2019 à 23:23:51

Le code est mauvais dès la ligne 5...
  • Partager sur Facebook
  • Partager sur Twitter