Programmation ardue fonction récursive en C

Fermé
bernard - 11 févr. 2010 à 16:32
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 - 5 mars 2010 à 23:25
Bonjour, je travaille actuellement sur une fonction récursive qui croit trop vite pour pouvoir être calculée par n'importe quel ordinateur, c'est la fonction d'ackermann, voici son code C:

long ackermann(int m, int n){
if(m==0){
return(n+1);
}else if ((n==0){
return ackermann(m-1, 1);
}else{
return ackermann(m-1, ackermann(m,n-1));
}
}

Mon but est d'utiliser une technique dont le principe est simple (et connu) pour diminuer le nombre de récursions: Je stocke les résultats déjà calculés dans un tableau, je vérifie si la valeur a déjà été calculée, si oui je récupère la valeur dans le tableau, si non je la calcule et la stocke dans le tableau. J'ai essayé de traduire en C mon idée, je souhaiterais votre avis s'il vous plait :

long ackermann(int m, int n, long tableau[][4]){
long var;
if(m==0){
return(n+1);
}else if ((n==0){
return ackermann(m-1, 1, tableau);
}else{
if(tableau[m][n] == 0){
var=ackermann(m,n,tableau);
tableau[m][n]=var;
}else{
return tableau[m][n];
}
}

Le tableau est déclaré dans le main. Que pensez vous de ma fonction?
merco bcp.
A voir également:

6 réponses

Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
11 févr. 2010 à 16:52
n vaut entre 0 et 4 ?
Je croi détecter une boucle infini.
si m!=0 et n!=0 et tableau[m][n]==0 alors tu appels la fonction "ackermann(m,n,tableau)" c'est à dire que tu n'as rien changé.
il faut : ackermann(m,ackermann(m,n-1,tableau),tableau) je pense.
Je mettrait tout en "long" aussi.
Par contre, ackermann(m,n-1,tableau) pourrait renvoyer un truc plus grand que 3 et posé un problème de taille de tableau non ?
0
salut charsnipeur, non au niveau de la taille du tableau tout va bien, pour A(m,n), je prends maximum m=4, donc le nombre n sera bien assez large vu que mon tableau est [][4], 4 représente le m :-) et il doit décroitre, mais n peut augmenter pas de soucis.

Je dois stocker chaque appel dans le tableau, donc tu es d'accord que pour stocker une valeur de A(m,n), je dois faire (je précise qu'à la base toutes les cases du tableau sont à 0):

if(tableau[m][n] == 0){
var=ackermann(m,n,tableau);
tableau[m][n]=var

jusqu'ici es tu d'accord avec ça?
0
bernard > bernard
11 févr. 2010 à 17:48
j'ai réécrit une version plus propre, qu'en dis tu :

long ackermann(int m, int n, long tableau[4][]){
long var;
if(m==0){
return(n+1);
}else if ((n==0){
return ackermann(m-1, 1, tableau);
}else{
if(tableau[m][n] == 0){
var=ackermann(m,n,tableau);
tableau[m][n]=var;
return tableau[m][n];
}else{
return ackermann(m-1,ackermann(m,n-1,tableau),tableau);
}
}
}
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
12 févr. 2010 à 08:25
à peu près la même chose. Je suis déjà plus d'accord avec le 4 où tu l'as mis.
par contre le dernier else !!!
Si ton tableau est différent de 0 (si tu l'as rempli donc) alors tu calcul la valeur et tu la retournes !?
ce que je verrai :
long ackermann(long m, long n, long tableau[4][])
{
    long var;
    if(m==0){
        return(n+1);
    }else if ((n==0){
        return ackermann(m-1, 1, tableau);
    }else{
        if(tableau[m][n] == 0){
            var=ackermann(m,ackermann(m,n-1,tableau),tableau); 
            tableau[m][n]=var;
        }else{
            return tableau[m][n];
        }
    }// accolade manquante
} 


e dois stocker chaque appel dans le tableau, donc tu es d'accord que pour stocker une valeur de A(m,n), je dois faire (je précise qu'à la base toutes les cases du tableau sont à 0):

if(tableau[m][n] == 0){
var=ackermann(m,n,tableau);
tableau[m][n]=var

jusqu'ici es tu d'accord avec ça?


absolument pas !
Je persiste sur ton var=, tu tombe sur une boucle infinie. Fait un test à la main pour t'en convaincre.
0
salut snipeur, alors oui ta fonction me semble bonne mais moi à la compilation ça ne marche pas :

ackermann.c:17: error: control reaches end of non-void function...

pourtant on retourne bien quelque chose je comprends pas....
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
12 févr. 2010 à 15:39
oui, mais les retours sont dans des if.
met un return -1 à la fin. En plus ça permet de traiter les erreurs inattendus.
0
la fonction compile bien mais j'ai une erreur de segmentation. Je crée un tableau de 5 colonnes et 65534 lignes et je l'initialise à 0 partout. Voici mon code complet en C:

#include <stdio.h>

long ackermann(long m, long n, long tableau[][65534]){
long var;
if(m==0){
return(n+1);
}else if ((n==0){
return ackermann(m-1, 1, tableau);
}else{
if(tableau[m][n] == 0){
var=ackermann(m,ackermann(m,n-1,tableau),tableau);
tableau[m][n]=var;
}else{
return tableau[m][n];
}
}
return -1;
}

int main(){
long tableau[5][65534];
long res;
long i,j;
for(i=1;i<=65534;i++){
for(j=1;j<=5;j++){
tableau[j][i]=0;
}
}
res=ackermann(2,3,TABLEAU);
printf("%ld\n", res);
return 0;
}

J'ai surement dû mélanger les cases qu'en dis tu?
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
12 févr. 2010 à 16:38
Non, pas de mélange de case, mais en C les tableaux commencent à "0" !
donc :
for(i=0;i<65534;i++){
for(j=0;j<5;j++){
tableau[j][i]=0;
}
}

pour les tableaux, comme tu connais la taille autant la donner à chaque fois.
0
si si même avec tes modfifications j'ai tjs une erreur de segmentation snipeur, regarde bien le code de ma fonction il doit yavoir un probleme de cases...je cherche depuis un moment sans la trouver...
0

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

Posez votre question
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
15 févr. 2010 à 08:04
2 solutions : soit tu débug en mettant des print pour connaitre les valeurs soit tu fais une fonction prorpre.
Comme tu utilises un tableau, il faut tester voir si tu ne dépasses pas.
const int mMAX=5,nMAX=65534;
long ackermann(long m, long n, long tableau[mMAX][nMAX]){
if(m>=mMAX || n>=nMAX) //traitement particulier de l'erreur.
peut être même ajouter (on ne sais jamais)
if(m<0 || n<0) // etc.
0
#include<stdio.h>
#include<conio.h>
main()
{int n,m,y;
int Ack(int,int);
printf("entrez m:\n");
scanf("%d",&m);
printf("entrez n:\n");
scanf("%d",&n);
y=Ack(m,n);
printf("Ack(%d,%d)=%d\n",m,n,y);
getch();
}
int Ack(int m, int n)
{
if (m == 0)
return(n+1);
else{
if (n == 0)
return(Ack(m-1, 1));
else
return( Ack(m-1, Ack(m, n-1)));
}
}
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844
5 mars 2010 à 23:25
Bonjour,

Tu n'as pas besoin de parcourir ton tableau pour le remplir à 0. Ca se fait facilement lors de la déclaration. De plus, l'utilisation du tableau est mal implémenté et tu as fait une erreur dans la définition de la fonction d'Ackermann.
var=ackermann(m,ackermann(m,n-1,tableau),tableau);
Il s'agit de m-1 en premier argument. Ce qui change tout...

Niveau algorithmique, j'aurais plutôt vu un truc du genre :
#include <stdio.h>

long ackermann(long m, long n, long tableau[][65534]) {
    if(m==0 && tableau[n][n]==0) tableau[0][n]=n+1;
    else if(n==0 && tableau[m][n]==0) tableau[m][0]=ackermann(m-1,1,tableau);
    else if(tableau[m][n]==0) tableau[m][n]=ackermann(m-1,ackermann(m,n-1,tableau),tableau);
    return tableau[m][n];
}

int main(void) {
    long tableau[5][65534]={{0}};

    printf("%ld\n", ackermann(2,3,tableau));

    return 0;
}


Ensuite, faudrait voir pour mieux gérer la taille du tableau, quitte à faire de l'allocation dynamique.

Cdlt,
0