标签:证明 else NPU diagonal dha while 函数 知乎 定义
看过离散数学上的证明。
也在知乎上搜过。
还有刘未鹏关于停机问题的那篇的博客http://mindhacks.cn/2006/10/15/cantor-godel-turing-an-eternal-golden-diagonal/
基本都是文字加代码论述,但我始终有几个问题没太想明白,感觉证明得牵强,于是自己理解了一下,记于此处,希望能有人来讨论、指点。
一般都是这么证明的(此处我用C++代码):
假设存在这么一个算法可以判断出别的程序是否可以停机。
1 bool halting_judge (program a, char* input) 2 { 3 if (程序a会停止) 4 return true; 5 else 6 return false; 7 }
因为一般的程序都是要有输入输出的,这里的input就是程序a的输入。使用char形式是因为后面证明时需要把程序代码作为输入,而程序代码是字符串,这里就直接规定好了。
然而图灵大佬想说具有这种能力的程序是不存在的。于是我们创造下面这个函数:
1 bool hack (program a, char* input) 2 { 3 if (halting_judge(a, input))//如果程序a可以停机 4 { 5 while (1);//这里就无限循环出不去了 6 return false; 7 } 8 else 9 return true; 10 }
这个函数的作用是:如果程序a可以停机,则接下来进行无限循环让hack函数无法停机;如果程序a无法停机,则return使hack函数可以停机。
接下来用hack程序代入a,用hack的代码代入input:
bool hack (program a, char* input) { if (halting_judge(hack, hack))//如果程序hack可以停机 { while (1);//这里就无限循环出不去了 return false; } else return true; }
于是人们说:如果halting_judge判断hack为停机,则hack(hack)就无限循环,不停机;如果halting_judge判断hack为无法停机,则hack(hack)会返回,为停机。So,hack到底是不是停机的呢?矛盾了,所以halting_judge无法判断。
可能是我理解错什么了吧?个人认为这样的证明未免有些模糊。
首先想到,所谓hack(hack),括号里的hack应该指的是程序吧?那作为程序它的两个参数是什么呢?难道什么参数都行?这里不解释一下吗?
然后看一看halting_judge的定义,想一下上面的问题,则发现括号里的hack它的参数是hack代码字符串。
至此可以发觉,我们上述的hack函数是不能代入进去的,它和program a不是一类函数!因为hack有两个参数,一个是程序,一个是字符串;而当时定义halting_judge函数的时候,它只能承受这样一类程序a:这个程序的参数只需要一个——字符串。
我的意思是说:虽然halting_judge里随便敷衍过去了,但实际上默认的a运行起来只需要input,而不是像hack那样需要一个program加一个input才能运行。
也就是说,要把halting_judge改成(hack程序,hack程序,hack代码)这种形式,或者把hack改成(char* input)这种形式,才可以实现hack自身代入。而第二种改法就是我之后要使用的。
另外,我们先抛开这个小bug不说,假如hack函数输入只需要用input来代替,则,(接下来我只说一种情况),如果hack(input)用halting_judge判断完是停机的,那么hack(hack(input))是不停机的,也只能说明hack的输入为input时停机,hack的输入为hack(input)时不停机,凭什么用一个简单的hack就代替了全部情况呢?就说hack停不停机是矛盾的呢?这逻辑就像“父亲(我的)是程序员,父亲(父亲(我的)的)——也就是爷爷~不是程序员,所以父亲到底是不是程序员这矛盾了判断有误”……单说父亲不说谁的,耍流氓。
当然了还是那句话,很可能是我理解上的差错。但各种短证明都会在结尾矛盾的那个地方轻飘飘一笔带过,确实难以捉摸。
下面是我的想法:
我修改一下hack函数:
1 bool hack (char* code) 2 { 3 program a = 编译code;//这是我加的一句话 4 if (halting_judge(a, code))//如果程序a可以停机 5 { 6 while (1);//这里就无限循环出不去了 7 return false; 8 } 9 else 10 return true; 11 }
然后hack就可以自身代入了,把hack这段代码传入进去就是下面这样:
1 bool hack (char* hackcode) 2 { 3 program a = 编译hackcode;//现在a即hack函数 4 if (halting_judge(hack, hackcode))//如果程序a可以停机 5 { 6 while (1);//这里就无限循环出不去了 7 return false; 8 } 9 else 10 return true; 11 }
程序往下走,if判断语句我们进去,情况是:
1 bool halting_judge (program hack, char* hackcode) 2 { 3 //现在a就是hack,input就是hack的code 4 if (程序hack会停止) 5 return true; 6 else 7 return false; 8 }
而程序hack会不会停止呢?取决于它while(1)了还是return true了,即,注意,我们现在是在用halting_judge判断:当hack函数的输入为hackcode时是否停机。
有没有发现这个和第一步一样?又递归回来了!最初一步也就是还没走到halting_judge的时候,就是用hack函数输入hackcode。
那么总结一下就是,只有我们把hack函数的输入设置为hackcode,才真正变成了用halting_judge去检测hack程序它自己(而不是什么hack(hack(……))),之后再讨论两种情况才能达到自相矛盾的效果。
这时才表现了证明中的输入非要用hack本身(其实是它的code)的重要意义:你把输入换成POJcode试试,判断就成了(POJ,POJcode),没法指向hack自身。
刚刚我说hack(hack(input))和hack(input)不能全统一为hack,那这里为什么可以?因为这里这俩hack都是用hackcode编译出来的。比喻来说,你就是hackcode,假如把你拎出来会导致我们能从人群中确定你爸爸。现在把你拎出来,和我们先把你带进幼儿园再把你拎出来,我们从人群中找出来的你爸爸,是一个人。
这上面的表述大费周章其实就是为了真真正正地达到:让hack程序运行是否停机,然后让halting_judge判断的也是hack程序本身是否停机,然后通过矛盾反证halting_judge不存在。两种情况都矛盾我就不多说了。
以上就是我的思考。等有能力看懂刘未鹏先生关于Y combinator和哥德尔不完备性的精彩论述,以及我自身不断学习计算机技术以后,我会继续补充和改正以上论述的。由于初涉计算机领域,个人逻辑也不怎么样,非常希望大家指出我文章中的错误,感谢!
标签:证明 else NPU diagonal dha while 函数 知乎 定义
原文地址:https://www.cnblogs.com/AlphaWA/p/9598436.html