56

プログラミングに関連する停止の問題について人々が尋ねるときはいつでも、人々は「ループを 1 つ追加するだけで、プログラムが停止することになり、タスクを自動化できなくなります」と答えます。

理にかなっています。プログラムに無限ループがある場合、プログラムの実行中に、プログラムがまだ入力を処理しているのか、それとも無限ループしているだけなのかを知る方法はありません。

しかし、これには直観に反するものもあります。ソース コードを入力として受け取る停止型問題解決プログラムを作成していたとしたらどうでしょう。rascher@localhost$ ./haltingSolver source.c

私のコード (source.c) が次のようになっている場合:

for (;;) {  /* infinite loop */  }

私のプログラムがこれを見るのはかなり簡単なようです。「ループを見て、条件を見てください。条件がリテラルのみに基づいており、変数がない場合、ループの結果は常にわかります。変数がある場合 (たとえば、while (x < 10))、これらの変数は常に変更されます。そうでない場合は、ループの結果が常にわかります。」

確かに、これらのチェックは簡単ではありません (ポインター演算の計算など) が、不可能ではないようです。例えば:

int x = 0
while (x < 10) {}

検出できました。とともに - 自明ではありませんが:

int x = 0
while (x < 10)
{
   x++;
   if (x == 10)
   {
      x = 0
   }
}

では、ユーザー入力についてはどうでしょうか。それがキッカーであり、プログラムを予測不能にするものです。

int x = 0;
while (x < 10) 
{
   scanf("%d", &x); /* ignoring infinite scanf loop oddities */
}

これで私のプログラムは、「ユーザーが 10 以上を入力すると、プログラムは停止します。それ以外のすべての入力では、再びループします」と言うことができます。

つまり、何百もの入力があっても、プログラムが停止する条件をリストできるはずです。実際、私がプログラムを書くときは、必ず誰かがプログラムを終了できるようにしています! 結果として得られる条件のリストを簡単に作成できると言っているわけではありませんが、不可能ではないように思えます。ユーザーからの入力を取得し、それらを使用してポインターインデックスを計算することもできますが、それはプログラムが確実に終了するように条件の数を追加するだけであり、それらを列挙することを不可能にするわけではありません.

では、停止の問題とは正確には何ですか?無限ループを検出する問題を書くことができないという考えについて、私が理解していないことは何ですか? または、なぜ「ループ」がそのようなよく引用される例なのですか?

アップデート

では、質問を少し変えさせてください。コンピューターに適用される停止問題とは何ですか? そして、いくつかのコメントに返信します。

多くの人が、プログラムは「任意の入力」を処理できなければならないと言っています。しかし、コンピューターでは、任意の入力はありません。1 バイトのデータのみを入力すると、可能な入力は 2^8 しかありません。したがって、例として:

int c = getchar()

switch (c) {
   case 'q':
      /* quit the program */
}

突然、すべての可能性を説明しました。cビットパターンが 0x71 の場合、1 つのことを行います。他のすべてのパターンでは、別のことを行います。リソースは有限であるため、任意の文字列入力を受け入れるプログラムでさえ、実際には「任意」ではありません。つまり、「任意」の理論が適用されますが、実際には正確に 1 対 1 ではありません。

人々が引用した他の例は次のとおりです。

while (n != 1)
    if (n & 1 == 1) 
        n = 3 * n + 1;
    else 
        n /= 2;

n が 32 ビットの整数である場合は、これが停止するかどうかを視覚的に判断できます。

この編集は何も求めていないと思いますが、私が見た中で最も説得力のある例は次のとおりです。

プログラムの停止を判断するための魔法のプログラム/メソッドがあるとします。

public bool DeterminesHalt(string filename, string[] args){
    //runs whatever program you tell it do, passing any args
    //returns true if the program halts, false if it doesn't
}

さて、次のような小さなコードを書いたとしましょう...

public static void Main(string[] args){
    string filename = Console.ReadLine(); //read in file to run from user
    if(DeterminesHalt(filename, args))
        for(;;);
    else
        return;
}

したがって、この例では、魔法の停止方法とは正反対のことを行うプログラムを書くことができます。特定のプログラムが停止すると何らかの形で判断した場合、無限ループに飛び込みます。それ以外の場合、プログラムが無限ループにあると判断した場合は、プログラムを終了します。

繰り返しになりますが、意図的に無限ループを含むプログラムを作成すると... 「停止問題を解決する」というのはちょっと意味がありませんね。

4

25 に答える 25

53

編集(元の回答よりもはるかに遅い):Good MathのMarkCC、Bad Mathは最近、具体的な例を使用して停止問題に関する優れた議論を書き上げました。

停止問題は基本的に、任意のプログラムが最終的に停止するかどうかを判断できるかどうかを尋ねる正式な方法です。

つまり、プログラム(入力) が最終的に停止する場合は true を返し、そうでない場合は false を返す停止オラクル、HaltingOracle(program, input) と呼ばれるプログラムを作成できますか?

答えは: いいえ、できません。

停止問題への入力が関連性があるのか​​、それともニシンなのかについての質問へのフォローアップ: はい、入力は重要です。また、「任意」の方が正しいところに「無限」が使用されているのを見ると、混乱があるようです。

実用的な例: あなたが QA の立場で働いていて、開発チーム (D) によって書かれた任意のプログラムと、最後に提供された任意の入力に対して、それを確認する停止チェッカー プログラム (別名オラクル) を書くことになっていると想像してください。 - ユーザー (I)、プログラム D は、入力 I が与えられると最終的に停止します。

キューマネージャーの声: 「ホーホー、あの間抜けなユーザー、彼らがどんなゴミを入力しても、サーバータスクが無限ループに陥らないようにしましょう。そうしてください、コードモンキー!」

これは素晴らしいアイデアのようですね。サーバーがハングするのは嫌ですよね?

停止問題が伝えているのは、解決不可能なタスクを手渡されているということです。代わりに、この特定のケースでは、しきい値時間を超えて実行されるタスクを計画し、それらをキャンセルする準備を整える必要があります。

マークは、入力の代わりにコードを使用して問題を説明しています。

def Deciever(i):
  oracle = i[0]
  in = i[1]
  if oracle(Deceiver, i):
    while True:
      continue
  else:
    return i

コメントでの私の議論では、悪意のある入力操作のルートをたどり、解決できない問題を強制しました。マークの例ははるかに洗練されており、停止するオラクルを使用して自分自身を打ち負かしています。

したがって、Deceiver への入力は、実際には 2 つの要素のリストです。最初の要素は、提案された停止オラクルです。2 番目は別の入力です。停止キラーが行うことは、オラクルに「入力 i のために停止すると思いますか?」と尋ねることです。オラクルが「はい、停止します」と言った場合、プログラムは無限ループに入ります。オラクルが「いいえ、あなたは止まらない」と言ったら、それは止まります。ですから、オラクルが何を言おうと、それは間違っています。

別の言い方をすれば、不正行為、入力の再フォーマット、可算/不可無限、その他の気を散らすものなしに、マークは停止しているオラクルプログラムを打ち負かすことができるコードを書きました。が停止oracleするかどうかという質問に答える を書くことはできません。Deceiver

元の答え:

偉大なウィキペディアから:

計算可能性理論では、停止問題は次のように述べることができる決定問題です。プログラムの記述と有限の入力が与えられたとき、その入力が与えられたときにプログラムの実行が終了するか、永久に実行されるかを決定します。

アラン・チューリングは 1936 年に、考えられるすべてのプログラムと入力のペアに対して停止問題を解決する一般的なアルゴリズムは存在しないことを証明しました。停止問題は、チューリング マシンでは決定不能であると言います。Copeland (2004) は、実際の用語停止問題を Martin Davis に帰しています。

重要な点の 1 つは、プログラムも入力も制御できないことです。あなたはそれらを手渡され、質問に答えるのはあなた次第です.

また、チューリング マシンは計算可能性の効果的なモデルの基礎であることにも注意してください。別の言い方をすれば、現代のコンピューター言語で行うことはすべて、これらの典型的なチューリング マシンにマッピングすることができます。その結果、停止問題は、有用な現代言語では決定できません。

于 2009-07-10T18:27:15.790 に答える
42

停止の問題を解決するには、例の比較的単純なケースだけでなく、任意のプログラムが任意の入力に対して停止するかどうかを判断できるアルゴリズムを開発する必要があります。

于 2009-07-10T18:20:44.540 に答える
21

これは非常にうまく打ちのめされており、Geoffrey Pullum ( Language Logで有名な人物) によってルイス・キャロルDr. Seussのスタイルで書かれた詩的な証拠が実際にあるほどです。

面白いもの。ここに味があります:

これが私が使用するトリックです - そしてそれは簡単です.
私は、Q と呼ぶ手順を定義します。この手順は、
P の成功を停止するという予測を使用
して、ひどい論理的混乱を引き起こします。

...

P がどのように機能しても、Q はそれをすくい取ります
。Q は P の出力を使用して、P をばかげているように見せます。
P が何を言おうと、それは Q を予測することはできません
。P は間違っているときは正しく、それが真であるときは偽です!

于 2009-07-10T19:18:36.997 に答える
9

ウィキペディアには停止性問題のOKの証拠があります。

ループにいくつかの手法を適用するだけでは不十分である理由を正確に説明するために、次のプログラム(擬似コード)を検討してください。

int main()
{
  //Unbounded length integer
  Number i = 3;

  while(true)
  {
    //example: GetUniquePositiveDivisiors(6) = [1, 2, 3], ...(5) = 1, ...(10) = 1, 2, 5, etc.
    Number[] divisiors = GetUniquePositiveDivisiors(i);
    Number sum = 0;
    foreach(Number divisor in divisiors) sum += divisor;

    if(sum == i) break;

    i+=2;
  }
}

このコードが停止した場合はtrueを返し、それ以外の場合はfalseを返すアプローチを考えられますか?

慎重に考えてください

たまたまフィールズ賞をめぐって深刻な争いをしている場合は、上記の代わりにこれらの問題のコードを想像してみてください。

于 2009-07-10T18:41:15.900 に答える
5

サブポイント「人々は「ループを1つ追加するだけでは、停止プログラムがあるため、タスクを自動化できません」と応答します」を参照して、次の詳細を追加します。

任意のプログラムが停止するかどうかをアルゴリズムで計算できないという投稿は、チューリングマシンにとって絶対に正しいものです。

重要なのは、すべてのプログラムがチューリングマシンを必要とするわけではないということです。これらは、概念的に「弱い」マシンで計算できるプログラムです。たとえば、正規表現は、入力で常に停止する有限状態マシンによって完全に具体化できます。いいじゃないですか?

人々が「ループを1つ追加する」と言うとき、プログラムが十分に複雑な場合、チューリングマシンが必要であり、したがって停止性問題(アイデアとして)が適用されるという考えを表現しようとしているのではないかと思います。

これは質問に少し接しているかもしれませんが、質問の詳細を考えると、これは指摘する価値があったと思います。:)

于 2009-07-12T01:34:29.920 に答える
5

チューリングの素晴らしい例は自己言及的でした。別のプログラムを調べて、停止するかどうかを判断できるプログラムがあるとします。停止プログラム チェッカー ITSELF を停止プログラム チェッカーにフィードします - どうすればよいですか?

于 2009-07-10T18:21:26.910 に答える
3

これまでのところ、多くの興味深い具体例/類推があります。背景を深く読みたい場合は、チャールズ・ペツォルドによる、チューリングの元の論文The Annotated Turingに関する優れた本があります。

関連する、横向きの静脈では、ウェブ上に非常にきちんとしたエッセイがあります。チューリングマシンとアッカーマン関数を扱います。

于 2009-07-10T19:18:16.997 に答える
2

すでに多くの良い答えがありますが、理論と実用性の一種の選択的混合において、停止性問題が実際に解決可能であるという事実に誰も言及していません。

したがって、まず第一に、停止問題は基本的に、任意の2番目のプログラムを取り、2番目のプログラムが任意の入力で停止するかどうかを決定するプログラムを作成するタスクです。つまり、「はい、このプログラムはこの入力で停止します」または「いいえ、停止しません」と言います。そして実際、チューリングマシンでは一般的なケース(他の人はすでにこれの証拠を提供しているようです)では解決できません。本当の問題は、何かを実行することで何かが停止するかどうかを知ることができるということです(停止するまで待つだけです)が、実行することで何かが停止しないかどうかを実際に知ることはできません(ずっと待ってください)。

これは、定義上、無限の量のメモリを持ち、したがって無限に多くの状態を持つチューリングマシンの問題です。しかし、私たちのコンピュータには限られた量のメモリしかありません。コンピュータには非常に多くのビットしかありません。したがって、プログラムの実行中に見た以前のすべての状態(ビット構成)を何らかの方法で追跡できれば、チェッカーが無限ループに入らないことを保証できます。セカンダリプログラムが最終的に停止する場合は、「はい、このプログラムはこの入力で停止します」と言います。停止する前に同じビット構成を2回表示すると、「いいえ、停止しません」とわかります。おそらく技術的にそれほど重要ではありませんが、私たちが直面する本当に「難しい」問題の多くは、理論的には実際よりも難しいことを知っておくとよいでしょう。

于 2009-07-10T19:07:02.433 に答える
2

これは、犬の代わりにプログラムを使用し、吠える代わりに停止することを除いて、停止する犬の問題の変形です。

于 2009-07-12T06:26:46.360 に答える
1

プログラミングパールから、JonBentley著

4.6問題

5.このプログラムが入力xが正の整数のときに終了することを証明します。

while x != 1 do
    if even(x)
        x = x/2
    else
        x = 3*x +1
于 2009-07-10T18:46:42.007 に答える
1

いくつかの単純なケースをリストしました。

さて、残りのすべてのケースについて考えてみてください。

考えられるシナリオは無数にあり、それらをすべてリストする必要があります。

もちろん、それを一般化できない限り。

そこで、停止問題の出番です。それをどのように一般化しますか?

于 2009-07-10T18:23:08.123 に答える
1

あなたのプログラムはコラッツ予想をどのように解決しますか?

于 2009-07-10T18:26:58.537 に答える
0

停止問題の重要性は、問題自体の重要性にあるわけではありません。それどころか、自動化されたテストは、ソフトウェア エンジニアリングではほとんど実用的ではありません (プログラムが停止することを証明しても、それが正しいことを証明するわけではありません。いずれにせよ、仮想アルゴリズムは与えられた有限入力の証明のみを提供しますが、実際のソフトウェア開発者は、すべての可能な有限入力のテストにもっと関心を持つでしょう)。

むしろ、停止問題は決定不能であることが最初に証明された問題の 1 つでした。これは、一般的なケースで機能するアルゴリズムが存在しないことを意味します。言い換えれば、チューリングは 70 年以上前に、正しいアルゴリズムがまだ見つかっていないという理由だけでなく、そのようなアルゴリズムが論理的に存在できないという理由で、コンピューターが解決できない問題があることを証明しました。

于 2009-08-26T15:28:17.623 に答える
0

なぜこの問題が_アルゴリズム的な方法。

于 2009-07-10T18:23:57.357 に答える
0

さらに別の例。最近、ヘイルストーン番号と呼ばれるものに出くわしました。これらの数字は、これらのルールでシーケンスを形成します

f(n) is odd  -  f(n+1) = 3*f(n)+1
f(n) is even -  f(n+1) = f(n)/2

現在、すべての開始点は最終的に 1 に到達し、それを繰り返すと想定されていますが、4,2,1,4,2,1,4,2,1...これに対する証明はありません。したがって、現在のところ、雹列に入力された数値が終了するかどうかを判断する唯一の方法は、1 に到達するまで実際に計算することです。

これが、停止問題理解するための鍵です。私が理解しているのは、実際にプログラムを実行しない限り、プログラムが停止する/停止しないことを確実に知ることはできないということです。したがって、停止問題に対する確実な回答を提供できるプログラムを作成する場合は、実際にプログラムを実行する必要があります。

于 2009-07-10T19:58:54.777 に答える