2017-10-05 7 views
1

Il est possible de calculer la fonction récursive totale calculable ackermann(m,n) avec les arguments m>=4 et n>=1 en python sans dépasser la profondeur maximale de récursivité?Il est possible de calculer la fonction ackermann récursive (m, n) avec les arguments m> = 4 et n> = 1 en python sans dépasser la profondeur de récursion maximale?

def ackermann(m,n): 

    if m == 0: 
     return n+1 
    if n == 0: 
     return ackermann(m-1,1) 
    else: 
     return ackermann(m-1,ackermann(m,n-1)) 

ackermann(4,1) 
+6

Vous savez que l'ackerman a été intentionnellement défini pour montrer quelque chose qui augmente en grande partie qu'il ne pourrait pas être défini par des fonctions récursives primitives? –

+3

Python n'est pas bon pour la récursivité. Il n'y a pas d'élimination par appel de fin, et donc, il est toujours sujet à un débordement de pile. Vous pouvez augmenter la profondeur de max-récursivité, mais c'est là pour * empêcher * le débordement de pile ... –

+0

* ackermann (4, 2) * a presque vingt-mille chiffres décimaux - tout comme la profondeur d'imbrication) définition littéralement. – greybeard

Répondre

1

Pour ce niveau de réponse, utilisez la programmation dynamique: memoize la fonction. Cela signifie que vous gardez une table des résultats précédents. Si vous trouvez un résultat qui a déjà été calculé, vous le retournez de la table. Seulement quand c'est un nouvel appel, faites-vous le calcul - et dans ce cas, la plupart ou la totalité des appels récursifs seront dans la table. Par exemple:

import sys 
sys.setrecursionlimit(30000) 

memo = {} 

def ack(m, n): 
    if not (m, n) in memo: 
     result = (n + 1) if m == 0 else (
      ack(m-1, 1) if n == 0 else ack(m-1, ack(m, n-1))) 
     memo[(m, n)] = result 
    return memo[(m, n)] 

print ack(3, 4) 
print ack(4, 1) 
print ack(4, 2) 

Vous aurez toujours des problèmes avec quoi que ce soit aussi grand que ack (4, 2), en raison de l'utilisation de la mémoire.

125 
65533 
Segmentation fault (core dumped) 
+0

Combien de mémoire avez-vous? ack (4, 1) provoque un redémarrage du noyau dans ipython pour moi. – Paddy3118

+0

La mémoire est assez grande (mais je ne divulgue pas); Je fais un travail d'apprentissage en profondeur sur cette boîte. – Prune

1

Oui. On peut utiliser sys.setrecursionlimit et plus de mathématiques pour améliorer l'algorithme. Voir le Rosetta Code task pour le code Python.

Remarque!

Je viens de re-couru ack2:

%timeit a2 = ack2(4,2) 
1000 loops, best of 3: 214 µs per loop 

len(str(a2)) 
Out[9]: 19729 

soit près de vingt chiffres dans la réponse.

+0

Notez qu'il existe * deux * versions de ** ack2 ** sur la page Rosetta. Ma réponse est dérivée du premier; Je crois que vous avez couru la seconde, "De l'exemple Mathematica ack3." J'ai essayé celui-là, et ça n'a aucun problème avec ack (4,2). Cependant, ack (5, 1) reçoit toujours un débordement de pile, et ack (4, 3) dure un temps trop long (comme prévu). J'ai tué le travail après 15 minutes. – Prune