18

重複の可能性:
最大再帰深度?

私のコードには別の問題があります。私は Vpython で最初のプログラムを書いており、2 つのガスを混合するシミュレーションを作成する必要があります。最初は境界線に問題がありましたが、ボール (ガス粒子を表す) が境界線内にとどまると、別の問題が発生します。数秒後、関数のソース コードの下に表示されるエラーが表示されます。

コード:

def MovingTheBall(listOfBalls,position,numCell,flagOfExecution):
    flag = 0
    if flagOfExecution==0:
        positionTmp = position
    else:
        positionTmp = (position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0)
    for i in range( 0, len(listOfBalls) ):
        if positionTmp==listOfBalls[i].pos:
            flag=1
        
            
    if flag==1:
        return MovingTheBall(lista,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
    else:
        if positionTmp[0]==0 or positionTmp[0]>=numCell or positionTmp[0]<=-numCell or positionTmp[1]>=numCell or positionTmp[1]<=-numCell:
            return MovingTheBall(lista,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)

        return positionTmp

エラーは次のとおりです。

    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 130, in MovingTheBall
    if positionTmp==listOfBalls[i].pos:
RuntimeError: maximum recursion depth exceeded while calling a Python object

私の機能を単純化する方法を考えられる人はいますか?

ループしながら関数を実行します。

while 1:
        rate(20)
        for i in range(0,len(self.listOfBalls)):
            self.listOfBalls[i].pos=poruszanie(self.listOfBalls,self.listOfBalls[i].pos,self.numCell,0)
4

4 に答える 4

43

Pythonには、lispなどの関数型言語で一般的な末尾再帰の最適化がありません。Pythonでは、再帰は999回の呼び出しに制限されています(sys.getrecursionlimitを参照)。

999の深さが予想よりも大きい場合は、実装に再帰を停止する条件がないかどうか、またはこのテストが場合によっては間違っている可能性があるかどうかを確認してください。

Pythonでは、純粋な再帰的​​アルゴリズムの実装は正しく/安全ではありません。999に制限されたfib()の実装は実際には正しくありません。再帰を反復に変換することは常に可能であり、そうすることは簡単です。

多くの再帰的アルゴリズムでは、深さが対数になる傾向があるため、頻繁に到達することはありません。アルゴリズムが当てはまらず、999回の呼び出しよりも深い再帰が予想される場合は、次の2つのオプションがあります。

sys.setrecursionlimit(n)1)プラットフォームで許可されている最大値まで、再帰制限を変更できます。

sys.setrecursionlimit(limit)

Pythonインタープリタースタックの最大深度を制限するように設定します。この制限により、無限再帰がCスタックのオーバーフローを引き起こしてPythonをクラッシュさせるのを防ぎます。

可能な最高の制限はプラットフォームに依存します。深い再帰を必要とするプログラムと、より高い制限をサポートするプラットフォームがある場合、ユーザーは制限をより高く設定する必要がある場合があります。制限が高すぎるとクラッシュする可能性があるため、これは注意して行う必要があります。

2)アルゴリズムを再帰から反復に変換してみることができます。再帰の深さがプラットフォームで許可されているよりも大きい場合は、それが問題を解決する唯一の方法です。インターネットには段階的な説明があり、CSの教育を受けている人にとっては簡単な操作であるはずです。問題が発生した場合は、新しい質問を投稿してください。サポートさせていただきます。

于 2013-01-08T19:45:38.573 に答える
10

再帰を反復に変更しました。

def MovingTheBall(listOfBalls,position,numCell):
while 1:
    stop=1
    positionTmp = (position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0)
    for i in range(0,len(listOfBalls)):
        if positionTmp==listOfBalls[i].pos:
            stop=0
    if stop==1:
        if (positionTmp[0]==0 or positionTmp[0]>=numCell or positionTmp[0]<=-numCell or positionTmp[1]>=numCell or positionTmp[1]<=-numCell):
            stop=0
        else:
            return positionTmp

うまくいきます:D

于 2013-01-08T20:10:47.067 に答える
7

エラーはスタック オーバーフローです。それはこのサイトでベルを鳴らすはずですよね?これは、 への呼び出しが への別の呼び出しとなり、再帰の深さが 1 ずつ増えるために発生poruszanieporuszanieます。2 番目の呼び出しは、同じ関数への別の呼び出しになります。これは、再帰の深さをインクリメントするたびに、何度も何度も発生します。

現在、プログラムの使用可能なリソースは限られています。各関数呼び出しは、スタックと呼ばれるものの上に一定量のスペースを必要とします。スタックの最大高さに達すると、スタック オーバーフロー エラーが発生します。

于 2013-01-08T19:40:00.980 に答える
1

これは、関数がそれ自体に対して再帰呼び出しを行う回数が多すぎる場合に発生するエラーです。これは、基本ケースが満たされない (そのため、無限ループに陥る) ため、または単に自分自身を多数呼び出すためである可能性があります。再帰呼び出しを while ループに置き換えることができます。

于 2013-01-08T20:03:30.560 に答える