Pourquoi est-il impossible de créer un compilateur capable de déterminer si une fonction C ++ changera la valeur d'une variable particulière?

104

J'ai lu cette ligne dans un livre:

Il est prouvé impossible de construire un compilateur qui puisse réellement déterminer si une fonction C ++ changera ou non la valeur d'une variable particulière.

Le paragraphe parlait de la raison pour laquelle le compilateur est prudent lors de la vérification de la const-ness.

Pourquoi est-il impossible de construire un tel compilateur?

Le compilateur peut toujours vérifier si une variable est réaffectée, une fonction non-const y est appelée, ou si elle est passée en tant que paramètre non-const ...

Joueur de cricket
la source
24
La première chose qui me vient à l'esprit est les bibliothèques de liens dynamiques. Si je compile du code sur ma machine et que vous compilez du code sur votre machine, et que nous les lions au moment de l'exécution , comment votre compilateur pourrait-il savoir si j'ai modifié des variables ou non?
Mooing Duck le
4
@MooingDuck Exactement ça. Plus largement, le compilateur ne compile pas la fonction individuellement, mais la compile dans le cadre d'une image plus large qui peut ne pas toutes être dans la portée du compilateur.
called2voyage
3
«impossible» peut être une exagération - «infaisable par le calcul» (comme dans NP-hard) peut être une meilleure caractérisation, mais c'est un peu plus difficile à saisir pour l'étudiant. Imaginez une liste chaînée ou une autre structure de données abstraite. Si j'appelle une fonction qui change un nœud dans cette liste / arbre / quoi que ce soit, comment un compilateur pourrait-il espérer prouver exactement quel nœud a été modifié (et peut-être plus important encore, lequel n'a pas été modifié) sans simuler complètement le programme avec le entrée attendue, tout en ne prenant pas 3 jours pour compiler un fichier source ...
twalberg
36
@twalberg Impossible n'est pas une exagération, le problème Halting s'applique ici comme l'expliquent plusieurs réponses. Il n'est tout simplement pas possible d'analyser complètement un programme général par un algorithme.
Fiktik
5
@twalberg Les compilateurs qui ne compilent qu'un sous-ensemble de programmes valides ne sont pas très utiles.
Caleb

Réponses:

139

Pourquoi est-il impossible de construire un tel compilateur?

Pour la même raison que vous ne pouvez pas écrire un programme qui déterminera si un programme donné se terminera. C'est ce qu'on appelle le problème de l' arrêt , et c'est l'une de ces choses qui n'est pas calculable.

Pour être clair, vous pouvez écrire un compilateur qui peut déterminer qu'une fonction change la variable dans certains cas , mais vous ne pouvez pas en écrire un qui vous indique de manière fiable que la fonction changera ou ne changera pas la variable (ou s'arrêtera) pour toutes les fonctions possibles.

Voici un exemple simple:

void foo() {
    if (bar() == 0) this->a = 1;
}

Comment un compilateur peut-il déterminer, simplement en regardant ce code, s'il foochangera un jour a? Que ce soit le cas ou non dépend de conditions externes à la fonction, à savoir la mise en œuvre de bar. Il y a plus que cela à la preuve que le problème d'arrêt n'est pas calculable, mais il est déjà bien expliqué dans l'article Wikipédia lié (et dans tous les manuels de théorie du calcul), donc je n'essaierai pas de l'expliquer correctement ici.

Caleb
la source
48
@mrsoltys, les ordinateurs quantiques ne sont "que" exponentiellement plus rapides pour certains problèmes, ils ne peuvent pas résoudre des problèmes indécidables.
zch
8
@mrsoltys Ces algorithmes exponentiellement compliqués (comme la factorisation) sont parfaits pour les ordinateurs quantiques, mais arrêter le problème est un dilemme logique, il n'est pas calculable quel que soit le type d '«ordinateur» que vous avez.
user1032613
7
@mrsoltys, juste pour être un smartass, oui, ça changerait. Malheureusement, cela signifierait que l'algorithme est à la fois terminé et toujours en cours d'exécution, malheureusement, vous ne pouvez pas dire lequel sans observer directement, par lequel vous affectez l'état réel.
Nathan Ernst
9
@ ThorbjørnRavnAndersen: OK, alors supposons que j'exécute un programme. Comment déterminer exactement s'il prendra fin?
ruakh
8
@ ThorbjørnRavnAndersen Mais si vous exécutez réellement le programme, et qu'il ne se termine pas (par exemple une boucle infinie), vous ne découvrirez jamais qu'il ne se termine pas ... vous continuez simplement à exécuter une étape de plus, car cela pourrait être the last one ...
MaxAxeHax
124

Imaginez qu'un tel compilateur existe. Supposons également que pour plus de commodité, il fournisse une fonction de bibliothèque qui renvoie 1 si la fonction passée modifie une variable donnée et 0 lorsque la fonction ne le fait pas. Alors que doit imprimer ce programme?

int variable = 0;

void f() {
    if (modifies_variable(f, variable)) {
        /* do nothing */
    } else {
        /* modify variable */
        variable = 1;
    }
}

int main(int argc, char **argv) {
    if (modifies_variable(f, variable)) {
        printf("Modifies variable\n");
    } else {
        printf("Does not modify variable\n");
    }

    return 0;
}
orlp
la source
12
Agréable! Le paradoxe « Je suis un menteur» écrit par un programmeur.
Krumelur
28
C'est en fait juste une belle adaptation de la célèbre preuve de l'indécidabilité du problème de l' arrêt .
Konstantin Weitz
10
Dans ce cas concret "modifies_variable" doit retourner true: il y a au moins un chemin d'exécution dans lequel la variable est effectivement modifiée. Et ce chemin d'exécution est atteint après un appel à une fonction externe non déterministe - la fonction entière est donc non déterministe. Pour ces 2 raisons, le compilateur doit adopter la vue pesimiste et décider qu'il modifie la variable. Si le chemin pour modifier la variable est atteint après qu'une comparaison déterministe (vérifiable par le compilateur) donne faux (c'est-à-dire "1 == 1"), alors le compilateur pourrait dire en toute sécurité qu'une telle fonction ne modifie jamais la variable
Joe Pineda
6
@JoePineda: La question est de savoir si fmodifie la variable - pas si elle pourrait modifier la variable. Cette réponse est correcte.
Neil G
4
@JoePineda: rien ne m'empêche de copier / coller le code de modifies_variabledepuis le source du compilateur, annulant totalement votre argument. (en supposant open-source, mais le point devrait être clair)
orlp
60

Ne pas confondre "modifiera ou ne modifiera pas une variable étant donné que ces entrées" pour "a un chemin d'exécution qui modifie une variable."

La première est appelée détermination de prédicat opaque , et est trivialement impossible à décider - en dehors de la réduction du problème d'arrêt, vous pouvez simplement signaler que les entrées peuvent provenir d'une source inconnue (par exemple l'utilisateur). Cela est vrai pour tous les langages, pas seulement pour C ++.

Cette dernière instruction, cependant, peut être déterminée en examinant l'arbre d'analyse, ce que font tous les compilateurs d'optimisation. La raison pour laquelle ils le font est que les fonctions pures (et les fonctions référentiellement transparentes , pour une certaine définition de référentiellement transparentes ) ont toutes sortes d'optimisations intéressantes qui peuvent être appliquées, comme être facilement insérables ou avoir leurs valeurs déterminées au moment de la compilation; mais pour savoir si une fonction est pure, il faut savoir si elle peut jamais modifier une variable.

Donc, ce qui semble être une déclaration surprenante sur C ++ est en fait une déclaration triviale sur tous les langages.

BlueRaja - Danny Pflughoeft
la source
5
C'est la meilleure réponse à mon humble avis, il est important de faire cette distinction.
UncleZeiv
"trivialement impossible"?
Kip le
2
@Kip "trivialement impossible de décider" signifie probablement "impossible de décider, et la preuve est triviale".
fredoverflow
28

Je pense que le mot clé dans «si une fonction C ++ changera ou non la valeur d'une variable particulière» est «volonté». Il est certainement possible de construire un compilateur qui vérifie si une fonction C ++ est autorisée à changer la valeur d'une variable particulière, vous ne pouvez pas dire avec certitude que le changement va se produire:

void maybe(int& val) {
    cout << "Should I change value? [Y/N] >";
    string reply;
    cin >> reply;
    if (reply == "Y") {
        val = 42;
    }
}
dasblinkenlight
la source
"Il est certainement possible de construire un compilateur qui vérifie si une fonction C ++ peut ou non changer la valeur d'une variable particulière" Non, ce n'est pas le cas. Voir la réponse de Caleb. Pour qu'un compilateur sache si foo () peut changer a, il devrait savoir s'il est possible pour bar () de renvoyer 0. Et il n'y a pas de fonction calculable qui puisse dire toutes les valeurs de retour possibles d'une fonction calculable. Il existe donc des chemins de code tels que le compilateur ne pourra pas dire s'ils seront jamais atteints. Si une variable est modifiée uniquement dans un chemin de code qui ne peut pas être atteint, elle ne changera pas, mais un compilateur ne la détectera pas
Martin Epsz
12
@MartinEpsz Par "peut" je veux dire "est autorisé à changer", pas "peut éventuellement changer". Je crois que c'est ce qu'OP avait à l'esprit en parlant de constcontrôles de qualité.
dasblinkenlight
@dasblinkenlight Je devrais convenir que je crois que l'OP peut avoir signifié le premier, "est autorisé à changer", ou "peut ou non changer" contre "ne changera certainement pas". Bien sûr, je ne peux pas penser à un scénario où ce serait un problème. Vous pouvez même modifier le compilateur pour répondre simplement «peut changer» sur n'importe quelle fonction contenant soit l'identificateur, soit un appel à une fonction qui a un attribut de réponse «peut changer». Cela dit, C et C ++ sont des langages horribles avec lesquels essayer, car ils ont une définition si vague des choses. Je pense que c'est pourquoi la const-ness serait un problème en C ++.
DDS
@MartinEpsz: "Et il n'y a pas de fonction calculable qui puisse dire toutes les valeurs de retour possibles d'une fonction calculable". Je pense que vérifier "toutes les valeurs de retour possibles" est une approche incorrecte. Il existe des systèmes mathématiques (maxima, mathlab) qui peuvent résoudre des équations, ce qui signifie qu'il serait logique d'appliquer une approche similaire aux fonctions. Ie le traiter comme une équation avec plusieurs inconnues. Les problèmes sont le contrôle de flux + les effets secondaires => des situations insolubles. IMO, sans ceux-ci (langage fonctionnel, pas d'affectation / effets secondaires), il aurait été possible de prédire quel programme de chemin prendra
SigTerm
16

Je ne pense pas qu'il soit nécessaire d'invoquer le problème d'arrêt pour expliquer que vous ne pouvez pas savoir algorithmiquement au moment de la compilation si une fonction donnée modifiera une certaine variable ou non.

Au lieu de cela, il suffit de souligner que le comportement d'une fonction dépend souvent des conditions d'exécution, que le compilateur ne peut pas connaître à l'avance. Par exemple

int y;

int main(int argc, char *argv[]) {
   if (argc > 2) y++;
}

Comment le compilateur pourrait-il prédire avec certitude s'il ysera modifié?

LarsH
la source
7

Cela peut être fait et les compilateurs le font tout le temps pour certaines fonctions , c'est par exemple une optimisation triviale pour de simples accesseurs en ligne ou de nombreuses fonctions pures.

Ce qui est impossible, c'est de le savoir dans le cas général.

Chaque fois qu'il y a un appel système ou un appel de fonction provenant d'un autre module, ou un appel à une méthode potentiellement remplacée, tout peut arriver, y compris la prise de contrôle hostile de l'utilisation par un pirate d'un débordement de pile pour changer une variable non liée.

Cependant, vous devez utiliser const, éviter les globaux, préférer les références aux pointeurs, éviter de réutiliser des variables pour des tâches non liées, etc. qui faciliteront la vie du compilateur lors de l'exécution d'optimisations agressives.

Kriss
la source
1
Si je me souviens bien, c'est tout l'intérêt de la programmation fonctionnelle, non? En utilisant uniquement des fonctions purement déterministes, sans effets secondaires, les compilateurs sont libres de faire des optimisations agressives, une pré-exécution, une post-exécution, une mémorisation et même une exécution au moment de la compilation. Le point que je pense que beaucoup de répondants ignorent (ou sont confus) est qu'il est en effet possible pour un sous-ensemble bien comporté de tous les programmes . Et non, ce sous-ensemble n'est ni trivial ni inintéressant, en fait il est très utile. Mais c'est en effet impossible pour le cas général absolu.
Joe Pineda
La surcharge est un concept au moment de la compilation. Vous vouliez probablement dire "méthode remplacée".
fredoverflow
@FredOverflow: oui, je veux dire remplacé. La surcharge est en effet un concept de temps de compilation. Merci de l'avoir repérée (bien sûr, si l'implémentation provient d'une autre unité de compilation, le compilateur peut encore avoir des difficultés à l'analyser, mais ce n'est pas ce que je voulais dire). Je vais fixer la réponse.
kriss
6

Il existe plusieurs moyens d'expliquer cela, dont l'un est le problème de l' arrêt :

Dans la théorie de la calculabilité, le problème d'arrêt peut être énoncé comme suit: "Étant donné la description d'un programme d'ordinateur arbitraire, décidez si le programme finit de fonctionner ou continue de fonctionner pour toujours". Cela équivaut au problème de décider, étant donné un programme et une entrée, si le programme s'arrêtera finalement lorsqu'il sera exécuté avec cette entrée, ou s'il fonctionnera pour toujours.

Alan Turing a prouvé en 1936 qu'un algorithme général pour résoudre le problème d'arrêt pour toutes les paires possibles de programme-entrée ne peut pas exister.

Si j'écris un programme qui ressemble à ceci:

do tons of complex stuff
if (condition on result of complex stuff)
{
    change value of x
}
else
{
    do not change value of x
}

Est-ce que la valeur du xchangement? Pour déterminer cela, vous devez d'abord déterminer si la do tons of complex stuffpièce provoque le déclenchement de la condition - ou, plus élémentaire encore, si elle s'arrête. C'est quelque chose que le compilateur ne peut pas faire.

Timothy Shields
la source
6

Vraiment surpris qu'il n'y ait pas de réponse qui utilise directement le problème d'arrêt! Il y a une réduction très simple de ce problème au problème de l'arrêt.

Imaginez que le compilateur puisse dire si une fonction a changé la valeur d'une variable ou non. Ensuite, il serait certainement en mesure de dire si la fonction suivante change la valeur de y ou non, en supposant que la valeur de x peut être suivie dans tous les appels dans le reste du programme:

foo(int x){
   if(x)
       y=1;
}

Maintenant, pour tout programme que nous aimons, réécrivons-le comme suit:

int y;
main(){
    int x;
    ...
    run the program normally
    ...
    foo(x);
}

Notez que, si, et seulement si, notre programme change la valeur de y, il se termine alors - foo () est la dernière chose qu'il fait avant de quitter. Cela signifie que nous avons résolu le problème en suspens!

Ce que la réduction ci-dessus nous montre, c'est que le problème de déterminer si la valeur d'une variable change est au moins aussi difficile que le problème d'arrêt. Le problème de l'arrêt est connu pour être incalculable, donc celui-ci doit l'être également.

John Doucette
la source
Je ne suis pas sûr de suivre votre raisonnement, sur la raison pour laquelle notre programme se termine ssil change la valeur de y. Il me semble que les foo()retours sont rapides, puis les main()sorties. (De plus, vous appelez foo()sans argument ... cela fait partie de ma confusion.)
LarsH
1
@LarsH: Si le programme modifié se termine, la dernière fonction qu'il a appelée était f. Si y a été modifié, f a été appelé (les autres instructions ne peuvent pas changer y, car il n'a été introduit que par la modification). Par conséquent, si y a été modifié, le programme se termine.
MSalters le
4

Dès qu'une fonction appelle une autre fonction dont le compilateur ne "voit" pas la source, il doit soit supposer que la variable a été modifiée, soit les choses peuvent mal tourner plus loin. Par exemple, disons que nous avons ceci dans "foo.cpp":

 void foo(int& x)
 {
    ifstream f("f.dat", ifstream::binary);
    f.read((char *)&x, sizeof(x));
 }

et nous avons ceci dans "bar.cpp":

void bar(int& x)
{
  foo(x);
}

Comment le compilateur peut-il "savoir" que ce qui xne change pas (ou qui est en train de changer, de manière plus appropriée) dans bar?

Je suis sûr que nous pouvons trouver quelque chose de plus complexe, si ce n'est pas assez complexe.

Mats Petersson
la source
Le compilateur peut savoir que x ne change pas dans la barre si la barre x est passée comme passe-par-référence-à-const, non?
Cricketer
Oui, mais si j'ajoute un const_castin foo, cela apporterait toujours des xmodifications - je serais en violation du contrat qui stipule que vous ne devez pas modifier les constvariables, mais puisque vous pouvez convertir n'importe quoi en "more const" et qu'il const_castexiste, les concepteurs du langage avaient sûrement en tête l'idée qu'il y a parfois de bonnes raisons de croire que les constvaleurs peuvent avoir besoin de changer.
Mats Petersson
@MatsPetersson: Je crois que si vous const_cast vous pouvez garder tous les morceaux qui cassent parce que le compilateur peut, mais n'a pas à compenser cela.
Zan Lynx
@ZanLynx: Oui, je suis sûr que c'est correct. Mais en même temps, le casting existe, ce qui signifie que quelqu'un qui a conçu le langage avait une sorte d'idée que "nous pourrions en avoir besoin à un moment donné" - ce qui signifie que ce n'est pas censé ne rien faire d'utile du tout.
Mats Petersson
1

Il est en général impossible au compilateur de déterminer si la variable sera modifiée, comme cela a été souligné.

Lors de la vérification de la const-ness, la question qui nous intéresse semble être de savoir si la variable peut être modifiée par une fonction. Même cela est difficile dans les langues qui prennent en charge les pointeurs. Vous ne pouvez pas contrôler ce que fait un autre code avec un pointeur, il pourrait même être lu à partir d'une source externe (bien que peu probable). Dans les langages qui restreignent l'accès à la mémoire, ces types de garanties peuvent être possibles et permettent une optimisation plus agressive que C ++.

Krumelur
la source
2
Une chose que je souhaite être prise en charge dans les langues serait une distinction entre les références (ou pointeurs) éphémères, retournables et persistantes. Les références éphémères ne peuvent être copiées que vers d'autres références éphémères, celles pouvant être retournées peuvent être copiées vers des références éphémères ou retournables, et les références persistantes peuvent être copiées de n'importe quelle manière. La valeur de retour d'une fonction sera contrainte par le plus restrictif des arguments qui sont passés en tant que paramètres «retournables». Je trouve regrettable que dans de nombreuses langues, quand on passe une référence, rien n'indique combien de temps elle peut être utilisée.
supercat
Ce serait certainement utile. Il existe bien sûr des modèles pour cela, mais en C ++ (et dans de nombreux autres langages), il est toujours possible de "tricher".
Krumelur
Un des principaux moyens par lesquels .NET est supérieur à Java est qu'il a un concept de référence éphémère, mais malheureusement, il n'y a aucun moyen pour les objets d'exposer des propriétés en tant que références éphémères (ce que j'aimerais vraiment voir serait un moyen par quel code utilisant une propriété passerait une référence éphémère à un code (avec des variables temporaires) qui devrait être utilisé pour manipuler l'objet.
supercat
1

Pour rendre la question plus précise, je suggère que l'ensemble de contraintes suivant peut avoir été ce que l'auteur du livre a pu avoir à l'esprit:

  1. Supposons que le compilateur examine le comportement d'une fonction spécifique par rapport à la const-ness d'une variable. Pour l'exactitude, un compilateur devrait supposer (à cause de l'aliasing comme expliqué ci-dessous) si la fonction appelée une autre fonction la variable est modifiée, donc l'hypothèse n ° 1 s'applique uniquement aux fragments de code qui ne font pas d'appels de fonction.
  2. Supposons que la variable n'est pas modifiée par une activité asynchrone ou simultanée.
  3. Supposons que le compilateur détermine uniquement si la variable peut être modifiée, et non si elle sera modifiée. En d'autres termes, le compilateur n'effectue qu'une analyse statique.
  4. Supposons que le compilateur ne considère que le code fonctionnant correctement (sans prendre en compte les dépassements / sous-exécutions de tableau, les mauvais pointeurs, etc.)

Dans le contexte de la conception d'un compilateur, je pense que les hypothèses 1, 3, 4 ont un sens parfait du point de vue d'un rédacteur de compilateur dans le contexte de l'exactitude de la génération de code et / ou de l'optimisation du code. L'hypothèse 2 a du sens en l'absence du mot-clé volatile. Et ces hypothèses focalisent également suffisamment la question pour rendre le jugement d'une réponse proposée beaucoup plus définitif :-)

Compte tenu de ces hypothèses, l'une des principales raisons pour lesquelles la constance ne peut pas être supposée est due à l'aliasing des variables. Le compilateur ne peut pas savoir si une autre variable pointe vers la variable const. L'aliasing pourrait être dû à une autre fonction dans la même unité de compilation, auquel cas le compilateur pourrait regarder à travers les fonctions et utiliser un arbre d'appels pour déterminer statiquement qu'un aliasing pourrait se produire. Mais si l'alias est dû à une bibliothèque ou à un autre code étranger, alors le compilateur n'a aucun moyen de savoir à l'entrée de la fonction si les variables sont aliasées.

Vous pourriez soutenir que si une variable / argument est marqué const, il ne devrait pas être sujet à changement via l'aliasing, mais pour un rédacteur de compilateur, c'est assez risqué. Il peut même être risqué pour un programmeur humain de déclarer une variable const dans le cadre, par exemple, d'un grand projet où il ne connaît pas le comportement de l'ensemble du système, ou du système d'exploitation, ou d'une bibliothèque, pour vraiment connaître une variable gagnée '' t changer.

Χpẘ
la source
0

Même si une variable est déclarée const, cela ne signifie pas qu'un code mal écrit peut l'écraser.

//   g++ -o foo foo.cc

#include <iostream>
void const_func(const int&a, int* b)
{
   b[0] = 2;
   b[1] = 2;
}

int main() {
   int a = 1;
   int b = 3;

   std::cout << a << std::endl;
   const_func(a,&b);
   std::cout << a << std::endl;
}

production:

1
2
Mark Lakata
la source
Cela se produit car aet bsont des variables de pile, et b[1]se trouve être le même emplacement de mémoire que a.
Mark Lakata
1
-1. Undefined Behavior supprime toutes les restrictions sur le comportement du compilateur.
MSalters le
Je ne suis pas sûr du vote négatif. Ceci est juste un exemple qui va à la question originale de l'OP sur pourquoi un compilateur ne peut pas déterminer si quelque chose est vraiment constsi tout est étiqueté const. C'est parce que le comportement non défini fait partie de C / C ++. J'essayais de trouver une manière différente de répondre à sa question plutôt que de mentionner le problème de l'arrêt ou la contribution humaine externe.
Mark Lakata
0

Pour développer mes commentaires, le texte de ce livre n'est pas clair, ce qui obscurcit le problème.

Comme je l'ai commenté, ce livre essaie de dire: "obtenons un nombre infini de singes pour écrire toutes les fonctions C ++ imaginables qui pourraient être écrites. Il y aura des cas où si nous choisissons une variable qui (une fonction particulière que les singes ont écrite) utilise, nous ne pouvons pas déterminer si la fonction changera cette variable. "

Bien sûr, pour certaines (voire plusieurs) fonctions dans une application donnée, cela peut être déterminé par le compilateur, et très facilement. Mais pas pour tous (ou forcément pour la plupart).

Cette fonction peut être facilement analysée:

static int global;

void foo()
{
}

"foo" ne modifie clairement pas "global". Cela ne modifie rien du tout, et un compilateur peut résoudre ce problème très facilement.

Cette fonction ne peut pas être analysée ainsi:

static int global;

int foo()
{
    if ((rand() % 100) > 50)
    {
        global = 1;
    }
    return 1;

Puisque les actions de "foo" dépendent d'une valeur qui peut changer à l'exécution , il est manifestement impossible de déterminer au moment de la compilation si elle modifiera "global".

Tout ce concept est beaucoup plus simple à comprendre que les informaticiens ne le prétendent. Si la fonction peut faire quelque chose de différent en fonction des choses qui peuvent changer au moment de l'exécution, vous ne pouvez pas déterminer ce qu'elle fera jusqu'à ce qu'elle s'exécute, et chaque fois qu'elle s'exécute, elle peut faire quelque chose de différent. Que ce soit prouvé impossible ou non, c'est évidemment impossible.

El Zorko
la source
ce que vous dites est vrai, mais même pour des programmes très simples pour lesquels tout est connu au moment de la compilation, vous ne pourrez rien prouver, pas même que le programme s'arrêtera. C'est le problème qui s'arrête. Par exemple, vous pouvez écrire un programme basé sur Hailstone Sequences en.wikipedia.org/wiki/Collatz_conjecture et le rendre vrai s'il converge vers un. Les compilateurs ne pourront pas le faire (car cela déborderait dans de nombreux cas) et même les mathématiciens ne savent pas si c'est vrai ou non.
kriss
Si vous voulez dire "il existe des programmes très simples pour lesquels vous ne pouvez rien prouver", je suis entièrement d'accord. Mais la preuve classique de Halting Problem de Turing repose essentiellement sur le fait qu'un programme lui-même soit capable de dire s'il s'arrête afin de mettre en place une contradiction. Comme il s'agit de mathématiques et non de mise en œuvre. Il y a certainement des programmes qu'il est tout à fait possible de déterminer statiquement au moment de la compilation si une variable particulière sera modifiée et si le programme s'arrêtera. Ce n'est peut-être pas prouvable mathématiquement, mais c'est pratiquement réalisable dans certains cas.
El Zorko le