Dépassement de la pile!

newkam2013 Messages postés 4 Date d'inscription mercredi 21 août 2013 Statut Membre Dernière intervention 22 août 2013 - Modifié par KX le 21/08/2013 à 21:23
newkam2013 Messages postés 4 Date d'inscription mercredi 21 août 2013 Statut Membre Dernière intervention 22 août 2013 - 22 août 2013 à 22:24
Bonjour,
Cela fait des années que je n'ai pas codé avec C++. J'ai implémenté un algorithme simple, le code compile, l'exécutable est parfait, sauf que ça crash pour des performances faibles ( tableaux 5000*3*2 par exemple). pour etre pratique, vous trouver ci-après le main du code si vous avez des propositions, sachant que je ne sais plus comment manipuler des vecteurs std::...Merci infiniment par avance!
int main()
{
double Data1[k][n][d];
double Data2[k][n][d];
double x[d];
double sum=0;
//double ksi[k+1][d];
double k_nouveau[k+1][d];
double x_nouveau[k+1][d];
//double valeur[d];
double gamma[k];
double beta[k];
double ck[k];
double grad_discret[d];
double grad_W[d];
int deb=0;
double moyenne[d];
 double sumgamma=0;
 //initialisation generateur pseudo-aléatoire :
srand(time(0));

 for(int i=0;i<d;i++)
   {
     x[i]=rand()/(double)RAND_MAX;
       sum=sum+x[i];
   }

 for(int i=0;i<d;i++)
   {
     x[i]=x[i]*u/sum;
     //  cout << "init x "<< x[i] <<endl;
   }
 // cout << endl;


  // on lit les données dans le fichier entree.txt qui contient
 ifstream fichier1("C:/simple/prog/data1.txt", ios::in);
ifstream fichier2("C:/simple/prog/data2.txt", ios::in);
 ifstream fichier3("C:/simple/prog/param_algo.txt",ios::in); 

fichier1.precision(15); 
fichier2.precision(15); 
fichier3.precision(15); 

        if(fichier1&&fichier2&&fichier3)
        {
	  for (int j=0;j<d;j++)
	    for (int i=0; i<n; i++)
	      for (int p=0; p<k; p++)
		{
		  fichier1 >> Data1[p][i][j];
		  fichier2 >> Data2[p][i][j];
		}

	  for (int p=0;p<k;p++)  fichier3 >> gamma[p] >> beta[p] >> ck[p];
                fichier1.close();
		fichier2.close();
		fichier3.close();
        }
        else
                cerr << "Impossible d'ouvrir les fichiers !" << endl;

	for (int j=0;j<d;j++)
	  { grad_discret[j]=0;
	    grad_W[j]=0;
	    //	    valeur[j]=0;
	    k_nouveau[0][j]=0;
	    x_nouveau[0][j]=x[j];
	    //	    ksi[0][j]=0;
	    moyenne[j]=0;
	  }
	deb=int(k/2);
	//	cout << " debut "<<deb<<endl;

	for (int p=1;p<(k+1);p++)
	  {
	    // cout <<"p="<<p<<" "<<gamma[p-1]<<" "<<beta[p-1]<<" "<<ck[p-1]<<" ";
	    H(grad_discret,x_nouveau[p-1], Data1[p-1], Data2[p-1],ck[p-1]);
	    
	      for (int j=0;j<d;j++)
		{//cout<<" Data1 et Data2 "<<setprecision(5)<<Data1[p-1][0][j]<<" "<<setprecision(5)<<Data2[p-1][0][j];
		k_nouveau[p][j]=k_nouveau[p-1][j]-gamma[p-1]*grad_discret[j];
    	      }
	      //  cout<<endl;
	    W(grad_W,k_nouveau[p], beta[p-1]);
	    for (int j=0;j<d;j++)
	      {
		x_nouveau[p][j]=grad_W[j];
		//	cout << "j="<<j<<" grad_discret " <<grad_discret[j]<<" grad_W "<<grad_W[j]<<" x " << x_nouveau[p][j] << " ksi " << k_nouveau[p][j]<<endl;
		//if (p>deb) 
		if(p>deb)
		  {
		    moyenne[j]=moyenne[j]+gamma[p-1]*x_nouveau[p-1][j];
		    if (j==0) sumgamma=sumgamma+gamma[p-1];
		  }
	      }
	     
	  }
 for (int i=0;i<d;i++) {
   moyenne[i]=moyenne[i]/sumgamma;
   // cout << "i="<< i <<" "<<moyenne[i]<<" ";
 }
 // cout << endl;
ofstream fichier4("C:/simple/prog/resultats.txt", ios::out);  // Ecriture résultats
ofstream fichier5("C:/simple/prog/details.txt",ios::out);
fichier4.precision(12); 
fichier5.precision(12); 

        if(fichier4&&fichier5)
	  { //cout<<"Ecriture des resultats";
	  for (int i=0; i<d; i++) {
	    fichier4 << moyenne[i] << " ";
	    for (int p=0; p<(k+1);p++)
	      {
		fichier5<<x_nouveau[p][i]<<" ";
	      }
	    fichier5<<endl;
	    fichier4<<endl;
	    	  }
	  }
	else  cout << "Erreur d'ouverture du fichier resultats !" << endl;
	fichier4.close();
	return(0);
}


6 réponses

KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 127
21 août 2013 à 21:34
Je n'ai pas vraiment regardé en détail ton code, mais dès que j'ai vu que tu faisais appel à des fonctions (H, W, etc.) je me suis dit que c'était du récursif, ce qui explique ton problème. Car même si les dimensions de tes tableaux sont relativement petites, le nombre d'appels récursifs peut facilement exploser et ainsi dépasser la taille de la pile.
Dans ton cas, essaye de remplacer les appels récursifs par des boucles, ou au minimum d'en limiter le nombre simultané, en privilégiant des algorithmes à profondeur d'abord qui sont généralement moins gourmand en appels récursifs que les algorithmes en largeur d'abord.
1
newkam2013 Messages postés 4 Date d'inscription mercredi 21 août 2013 Statut Membre Dernière intervention 22 août 2013
21 août 2013 à 21:57
Je te remercie beaucoup pour ton message! les fonctions sont réellement très simples, ( pour ne pas encombrer le main). si j'ai bien compris ta proposition, il vaut mieux développer ces fonctions à l'intérieur du main? J'ai passé la journée entière à essayer de trouver une façon pour résoudre ce problème, il faut avouer que je suis redevenu un débutant en programmation. Je te remercie encore!
0
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 127
21 août 2013 à 22:36
Je ne dis pas tout mettre dans le main, mais éviter d'avoir des fonctions récursives.
En effet à chaque fois qu'une fonction X appelle une fonction Y, l'exécution de X est mis en pause et stockée dans la pile d'appel en attendant que la fonction Y soit terminée. Avec les appels récursifs on se retrouve avec X qui appelle X qui appelle X, etc. le nombre de méthodes ouvertes en même temps devient donc très important, jusqu'à dépasser la taille de stockage de la pile.

Ce qu'il faut faire c'est diminuer le nombre de fonctions ouvertes en même temps afin de rester dans la limite de la pile.
Cela se fait en changeant d'algorithme, passer du récursif à l'itératif, du parcours en largeurs à un parcours en profondeur, ou encore en faisant de la récursivité terminale (faire en sorte que la fonction X n'est plus rien à faire après la fin de Y, comme ça le compilateur peut optimiser le traitement en fermant X avant d'ouvrir Y, ce qui évite de mettre X dans la pile)

Exemple simple, la fonction factorielle.

// récursive

int fac1(int n)
{
    if (n>1)
        return fac1(n-1)*n;
    else
        return 1;
}

// récursive terminale

int fac2(int n)
{
    return fac2(n,1);
}

int fac2(int n, int r)
{
    if (n>1)
        return fac2(n-1,r*n);
    else
        return r;
}

// itérative

int fac3(int n)
{
    int r=1;
    for (int i=2; i<=n; i++)
        r *= i;
    return i;
}
0
newkam2013 Messages postés 4 Date d'inscription mercredi 21 août 2013 Statut Membre Dernière intervention 22 août 2013
21 août 2013 à 22:49
Je comprends mieux la, je te remercie pour tes explications, et pour le temps que tu as consacré à me répondre, je vais essayer d'appliquer ce que tu m'as conseillé et utiliser aussi les std::vector, et je te tienderais au courant!
Merci encore!
0

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

Posez votre question
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
22 août 2013 à 11:04
Bonjour.

En plus de vérifier si tu as des fonctions récursives non terminales, je t'invite aussi à vérifier que tes tableaux statiques ne soient pas trop gros. Autant des tableaux "alloués en mémoire" (pour vulgariser) n'ont pas de limite de taille autre que la RAM, autant des tableaux "alloués" sur la pile, ont une limite basse.
Si tu fais du C++, il est évident que tu devrais utiliser les outils fournis avec ce langage, notamment le std::vector.

Quelques petites trucs qui me choquent dans ton code:
- Évite les using namespace, voir: http://0217021.free.fr/portfolio/axel.berardino/articles/bon-usage-using-namespace
- Découpe ton code en petites fonctions ! Une fonction proprement écrite dépasse rarement 50 lignes. Chaque étape logique devrait être une fonction.
- std::ostream + std::ios::in => std::ifstream, donc pas besoin de remettre std::ios::in en argument des std::ifstream. Même remarque pour les std::ofstream
- Pas besoin de "fichier.close()", c'est automatique à la destruction de l'objet "fichier" (au sortir du scope).
- Évite les variables globales. Un code propre n'en a pas. (Variables globales != constantes globales, les constantes étant tout à fait acceptable).

- Si tu as accès au C++0x (option std=C++0x), alors tu peux avantageusement remplacer le rand/srand par un mersenne_twister, bien plus efficace, et qui t'affranchie d'utiliser du C.

- Si vraiment tu as besoin de tableaux à taille fixe, sans faire péter la pile, tu peux regarder les classes suivantes (des dérivés de std::vector):
https://github.com/cptpingu/game/blob/master/src/Core/Array2D.hh
https://github.com/cptpingu/game/blob/master/src/Core/Array3D.hh
0
newkam2013 Messages postés 4 Date d'inscription mercredi 21 août 2013 Statut Membre Dernière intervention 22 août 2013
22 août 2013 à 22:24
Merci beaucoup pour cette réponse détaillée! mais je craint que je n'ai plus le niveau pour comprendre sa totalité! Merci en tout cas!
0
Rejoignez-nous