正解は、この関数はすべての整数で終了しないことです(具体的には、-1で終了しません)。あなたの友人は、これが擬似コードであり、擬似コードがスタックオーバーフローで終了しないと述べているのは正しいです。擬似コードは正式には定義されていませんが、アイデアはブリキに書かれていることを実行するというものです。コードに「スタックオーバーフローエラーで終了」と表示されていない場合、スタックオーバーフローエラーはありません。
これが実際のプログラミング言語であったとしても、スタックの使用が言語の定義の一部でない限り、正しい答えは依然として「終了しない」です。ほとんどの言語は、スタックがオーバーフローする可能性のあるプログラムの動作を指定しません。プログラムが使用するスタックの量を正確に知ることは難しいからです。
実際のインタープリターまたはコンパイラーでコードを実行すると、多くの言語でスタックオーバーフローが発生する場合、それは言語の正式なセマンティクスと実装の間に矛盾があります。一般に、言語の実装は、有限のメモリを備えた具体的なコンピュータで実行できることのみを行うと理解されています。プログラムがスタックオーバーフローで死ぬ場合は、より大きなコンピューターを購入し、必要に応じてシステムを再コンパイルして、すべてのメモリをサポートし、再試行します。プログラムが終了していない場合、永久にこれを実行する必要がある場合があります。
テールコールの最適化やメモ化などの一部の最適化により、定数バインドスタックスペースで関数呼び出しの無限チェーンが可能になるため、プログラムがスタックをオーバーフローするかどうかは明確に定義されていません。一部の言語仕様では、可能な場合に実装でテールコールの最適化を実行することも義務付けられています(これは関数型プログラミング言語では一般的です)。この関数でf(-1)
は、に展開しf(f(-2))
ます。の外側の呼び出しf
は末尾呼び出しなので、スタックに何もプッシュせず、スタックにのみf(-2)
移動し、それがを返す-1
ため、スタックは最初の状態に戻ります。したがって、末尾呼び出しの最適化f(-1)
では、一定のメモリ内で永久にループします。