58 votes

Quel est le problème?

Chaque fois que les gens se posent sur le problème de l'arrêt que ce qui a trait à la programmation, les gens réagissent avec des "Si vous venez d'ajouter une boucle, vous avez l'arrêt du programme et, par conséquent, vous ne pouvez pas automatiser des tâches"

Du sens. Si votre programme est une boucle infinie, puis lorsque votre programme est en cours d'exécution, vous n'avez aucun moyen de savoir si le programme est toujours à croquer d'entrée, ou si c'est juste en boucle à l'infini.

Mais certains cela semble contre-intuitif. Que faire si j'écrivais un problème de l'arrêt solveur, qui prend le code source en entrée. rascher@localhost$ ./haltingSolver source.c

Si mon code (la source.c) ressemble à ceci:

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

Il semble que ce serait assez facile pour mon programme pour voir ce. "Regardez la boucle, et de regarder l'état. Si la condition est juste, fondée sur les littéraux, et aucune des variables, alors vous savez toujours le résultat de la boucle. Si il y a des variables (par exemple while (x < 10)), voir si ces variables sont jamais modifiés. Si non, alors vous savez toujours le résultat de la boucle."

Accordé, ces contrôles ne serait pas trivial (le calcul de l'arithmétique de pointeur, etc), mais il ne semble pas impossible. par exemple:

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

a pu être détecté. avec - mais ce n'est pas trivialement:

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

Maintenant, quelle est la saisie de l'utilisateur? C'est le kicker, c'est ce qui rend un programme imprévisible.

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

Maintenant mon programme peut dire: "Si l'utilisateur entre un 10 ou plus, le programme s'arrête. Sur tous les autres commentaires, il passe en boucle à nouveau."

Ce qui signifie que, même avec des centaines d'entrées, on devrait être en mesure d'énumérer les conditions dans lesquelles le programme s'arrête. En effet, quand j'écris un programme, je fais toujours en sorte que quelqu'un a la possibilité d'y mettre fin! Je ne dis pas que la liste de conditions est trivial à créer, mais il ne semble pas impossible pour moi. Vous pourriez prendre l'entrée de l'utilisateur, les utiliser pour calculer pointeur d'index, etc - mais qui ajoute juste le nombre de conditions pour s'assurer que le programme se termine, n'est pas impossible de les énumérer.

Alors, quel est exactement le problème de l'arrêt? Ce que je ne suis pas à la compréhension de l'idée que l'on ne peut pas écrire un problème pour détecter les boucles infinies? Ou, pourquoi sont des "boucles" un tel, souvent citée en exemple?

Mise à JOUR

Alors, permettez-moi de changer la question un peu: qu'est-ce que le problème de l'arrêt en tant qu'il s'applique aux ordinateurs? Et puis je vais répondre à certains commentaires:

Beaucoup de gens ont dit que le programme doit être en mesure de faire face à "toute entrée quelconque." Mais dans les ordinateurs, il n'y a pas toujours de tout arbitraire d'entrée. Si je ne saisissez qu'un seul octet de données, que je n'ai que 2^8 entrées possibles. Ainsi, à titre d'exemple:

int c = getchar()

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

Tout d'un coup, j'ai juste comptabilisés pour toutes les possibilités. Si c a la séquence de bits 0x71, il ne fait qu'une chose. Pour tous les autres modèles, il fait quelque chose d'autre. Même un programme qui accepte une chaîne de caractères arbitraire d'entrée n'est jamais vraiment "arbitraire", puisque les ressources sont limitées, ce qui signifie que, bien que la théorie de "l'arbitraire" s'applique... ce n'est pas exactement un-à-un avec la pratique.

L'autre exemple les personnes citées est ceci:

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

Si n est un entier de 32 bits... alors je peux visuellement vous dire si oui ou non cela va s'arrêter.

Je suppose que cette édition n'est pas en train de demander quoi que ce soit, mais le plus convaincant exemple que j'ai vu est ce un:

Supposons que vous avez votre magique de programme/méthode pour déterminer qu'un programme s'arrête.

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
}

Maintenant, disons que nous écrire un petit morceau de code, tels que...

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

Ainsi, pour cet exemple, nous pouvons écrire un programme pour faire l'exact opposé de notre magique arrêt de méthode. Si nous réussissons à nous de déterminer qu'un programme stopper les, nous venons de sauter dans une boucle infinie; autrement, si nous déterminons que le programme est dans une boucle infinie, nous la fin du programme.

Et puis, si vous avez intentionnellement écrire un programme qui contient une boucle infinie... "résoudre le problème de l'arrêt" est assez discutable, n'est-ce pas?

54voto

Bob Cross Points 13552

EDIT (beaucoup plus tard que la réponse originale à cette question): MarkCC de Maths Bon, Mauvais en Mathématiques a récemment écrit une excellente analyse du problème de l'Arrêt avec des exemples concrets.

Le problème de l'arrêt est en fait un de manière formelle de demander si vous pouvez dire si oui ou non un programme arbitraire finira par s'arrêter.

En d'autres termes, pouvez-vous écrire un programme appelé un arrêt d'oracle, HaltingOracle(programme, input), qui retourne true si le programme(entrée) serait finalement arrêter, et qui renvoie false si il ne le serait pas?

La réponse est: non, vous ne pouvez pas.

Le suivi des questions quant à savoir si les données d'entrée du problème de l'Arrêt est pertinent ou un hareng rouge: Oui, l'entrée est important. Aussi, il semble y avoir une certaine confusion dans ce que je vois "infini" est utilisé là où "arbitraire" est plus correct.

Exemple concret: Imaginez que vous travaillez dans une QA position et vous êtes à écrire un arrêt de programme de vérification (aka un oracle) qui permettra de confirmer que, pour tout arbitraire programme écrit par l'équipe de développement (D) et tout arbitraire d'entrée fournie par l'utilisateur final (I), programme D finira par arrêter lors de l'entrée I.

Cue gestionnaire de voix: "Ho Ho, ceux dingo utilisateurs, assurez-vous que peu importe ce que les ordures, ils type, notre serveur de tâches n'aura jamais de fin dans une boucle sans fin. Faire en sorte, code de singe!"

Cela semble être une bonne idée, non? Vous ne voulez pas que votre serveur à accrocher, à droite?

Ce que le problème de l'arrêt est vous dire, c'est que vous êtes remis une tâche insoluble. Au lieu de cela, dans ce cas particulier, vous devez planifier les tâches qui s'exécutent delà d'un seuil de temps et être prêt à les annuler.

La marque utilise le code au lieu de l'entrée pour illustrer le problème:

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

Dans ma discussion dans les commentaires, je suis allé à la route de malveillant d'entrée de la manipulation pour forcer un problème insoluble. Marque de l'exemple est beaucoup plus élégant, à l'aide de l'arrêt d'oracle pour vaincre lui-même:

Donc, l'entrée de Séducteur est en fait une liste de deux éléments: le premier est un projet d'arrêt d'oracle. L' la deuxième est une autre entrée. Ce que l' l'arrêt de tueur n'est de demander à l'Oracle: "Tu crois que je vais arrêter pour l'entrée je?". Si l'oracle dit, "Oui, vous allez halte", alors le programme va dans un boucle infinie. Si l'oracle dit "Non, vous n'aurez pas arrêter", puis il s'arrête. Donc pas de importe ce que l'oracle dit, c'est mal.

Dit d'une autre manière, sans tricherie, le reformatage des entrées, dénombrable / indénombrable infinis ou quoi que ce soit d'autres distractions, Mark a écrit un bout de code qui peut vaincre toute l'arrêt d'oracle programme. Vous ne pouvez pas écrire un oracle qui répond à la question de savoir si l' Deceiver s'arrête jamais.

Réponse originale à cette question:

De la grande Wikipédia:

Dans la théorie de la compilation, de l'arrêt le problème est un problème de décision qui peut être énoncé comme suit: étant donné un description d'un programme et d'un fini d'entrée, décider si le programme la fin de l'exécution ou s'exécute indéfiniment, étant donné que l'entrée.

Alan Turing a prouvé en 1936 qu'un algorithme général pour résoudre l'arrêt problème pour l'ensemble du programme-entrée les paires ne peut pas exister. Nous disons que l' problème de l'arrêt est indécidable plus Des machines de Turing. Copeland (2004) les attributs de la durée réelle arrêt problème à Martin Davis.

Un des points critiques est que vous n'avez aucun contrôle sur le programme ou l'entrée. Vous sont remis à ceux-ci et c'est à vous de répondre à la question.

Notez également que les machines de Turing sont à la base de modèles efficaces de compilation. Dit d'une autre manière, tout ce que vous faites dans l'ordinateur moderne langues peuvent être mappés à ces archétype des machines de Turing. En conséquence, le problème de l'arrêt est indécidable dans toute langue moderne.

43voto

dsimcha Points 32831

Pour résoudre le problème d'arrêt, vous devez développer un algorithme permettant de déterminer si un programme arbitraire s'arrête pour une entrée quelconque , et pas seulement les cas relativement simples de vos exemples.

30voto

Graphics Noob Points 4004

Voici une explication simple de la preuve que le problème de l'arrêt est indécidable.

Supposons que vous disposez d'un programme, H, qui détermine si oui ou non un programme s'arrête. H prend deux paramètres, le premier est une description d'un programme, P, et la seconde est une entrée, I. H retourne true si P s'arrête sur l'entrée I, et false sinon.

Maintenant écrire un programme, p2, qui prend comme entrée la description d'un autre programme, p3. p2 appels H(p3, p3), puis les boucles retourne vrai si H et les haltes autrement.

Ce qui se passe lors de l'exécution de p2(p2)?

Il doit en boucle et s'arrêter dans le même temps, provoquant l'univers à exploser.

20voto

Doug McClean Points 6355

Cela a été battu à mort, si bien qu'il ya effectivement une poétique de la preuve, écrite dans le style de Lewis Carroll Dr Seuss par Geoffrey Pullum (il a de la Langue du Journal de la gloire).

De drôles de trucs. Voici un avant-goût:

Voici l'astuce que je vais utiliser – et c'est simple à faire.
Je vais définir une procédure, que j'appellerai Q,
qui va utiliser P prédictions de l'arrêt de la réussite
remuer une terrible logique de désordre.

...

N'importe comment P peut effectuer, Q scoop it:
Q utilise P est de sortie pour faire de la P l'air stupide.
Quel que soit P le dit, il ne peut pas prédire Q:
P est la droite quand c'est mal, et il est faux quand c'est vrai!

12voto

Kevin Montrose Points 11936

Il y a un OK de la preuve que le Problème de l'Arrêt sur wikipédia.

Pour illustrer, exactement, pourquoi se contenter d'appliquer une technique de boucles est insuffisante, considérons le programme suivant (pseudo-code):

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;
  }
}

Pouvez-vous penser à une approche qui renvoie true si le présent code s'arrête, et false dans le cas contraire?

Réfléchissez Bien.

Si par hasard vous êtes sérieux lice pour une médaille Fields, imaginez un peu de code pour ces problèmes à la place de la ci-dessus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X