2017-10-05 1 views
1

引数m>=4n>=1を持つ合計計算可能な再帰関数ackermann(m,n)をpythonで最大再帰深度を超えないで計算することは可能ですか?最大反復深度を超えずに、Pythonでargs m> = 4およびn> = 1を持つ再帰的ackermann(m、n)関数を計算することは可能ですか?

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

ackermanは、原始的な再帰関数では定義できなかったことを大きく増やすものを意図的に定義しています。 –

+3

Pythonは再帰には適していません。テールコールの消去はないため、常にスタックオーバーフローが発生しやすくなります。あなたは最大再帰深度を増やすことができますが、スタックオーバーフローを防ぐために* –

+0

* ackermann(4,2)*は10進数で約2万桁です。 )の定義を文字通り。 – greybeard

答えて

1

このレベルの応答では、動的プログラミングを使用してください。関数をメモしてください。これは、以前の結果の表を保持することを意味します。すでに計算されている結果が見つかった場合は、それをテーブルから戻します。それが新しい呼び出しである場合にのみ、計算を行いますか?その場合、再帰呼び出しのほとんどまたはすべてがテーブルにあります。例えば:

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) 

あなたはまだによるメモリ使用にACK(4、2)、同じくらい大きなものに問題があるでしょう。

125 
65533 
Segmentation fault (core dumped) 
+0

どのくらいのメモリがありますか? ack(4、1)は私のためにipythonでカーネルを再起動させます。 – Paddy3118

+0

メモリはかなり大きいです(しかし私は開示していません)。私はこの箱で深い勉強をします。 – Prune

1

はい。アルゴリズムを改善するためにsys.setrecursionlimit以上の数学を使用することができます。 PythonコードについてはRosetta Code taskを参照してください。

注!

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

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

答えでほぼ20 桁です:

は、私はちょうどACK2を再実行しました。

+0

Rosettaページに** ack2 **の* 2つのバージョンがあることに注意してください。私の答えは最初から得られたものです。私はあなたが2番目の「Mathematica ack3の例から」を実行したと信じています。私はそれを試しました、そして、それはack(4,2)と何の問題もありません。しかし、ack(5,1)はまだスタックオーバーフローを起こし、ack(4,3)は(期待どおり)長い時間実行されます。私は15分後に仕事を殺した。 – Prune

関連する問題