【C语言】怎么用C语言来解逻辑推理题 | 运用离散数学+形式逻辑学的思想

作者:a727911438


最近在看波老师的形式逻辑学书籍,发现了一个很有趣的逻辑推理题,这个题的要求非常简单,就是判断一段话是对的还是错的,来看看这道逻辑题:


如果我有一千万,我就能买到房子。现在我没有一千万,我不能买到房子。


看完这道题目,我果断的断定,这是对的结果答案是:错的!


知道真相的我,开始怀疑我的智商了。后来学了一小段时间的形式逻辑学后,我才理解了这道题为什么是错的。因为,如果我没有一千万,但是可能房子只需要一百万啊,所以我还是能买到房子的。又知道真相的我,被自己蠢哭了。。。


其实这道题的正确解法是用离散数学来解的,几乎现实中的含逻辑推理色彩的话语,都能转化成离散数学来演绎推理。简单来说,形式逻辑学,就是用离散数学来做逻辑推理(个人观点)。


------------------------------------------------------------------------------


先来简单回顾一下离散数学,对于一个陈述句,可以用真、假两个值来表示陈述句的正确性,真、假值用1、0来表示,同时用一个字母来表示这个陈述句,比如:


p : 小明吃饭了          1

┐p : 小明没有吃饭      0

q : 小红吃饭了          1

┐q : 小红没有吃饭      0


如果是有两个陈述句有关系,用相应符号表示,但是这个关系也是可能为真可能为假,这个很像程序代码的思维,再举例:


p∧q : 小明和小红都吃饭了

p∨q : 小明或者小红吃饭了


如果两个陈述句有因果关系,用→符号表示,比如:


p→q : 如果小明吃饭了,小红就吃饭了


离散数学还有更多语法,不再一一叙述,接下来是真值表的相关知识。


真值表,在数字逻辑电路中很常用的知识,简单点的有与非门、与或门的真值表,更难的有反馈电路等等,用真值表来分析电路的输入输出十分实用。离散数学的真值表跟数字逻辑的差不多,可能是同个祖宗。用离散数学的真值表思维来进行演绎推理,是一种很牛逼的方法,训练多了就分分钟成为下一个福尔摩斯。扯远了。。。回归正题,“小明吃饭了”这句话有真有假,那么真值表其实就是一张列举了所有真假关系的表,真值表也是离散数学的运算规则


p:小明吃饭了 
0
1


p
q
p∧q
p∨q
0 0 0 0
0 1 0 1
1 0 0 1
1 1 1 1


因果关系的真值表有点特殊,只有因是真的、果是假的情况时,整个推断就是假的,其他情况都是真的。为什么会这样子?因为如果前提是假的,那么结论不管结果是什么都没有意义,所以就把整个推断归为真的。还是不理解为什么会这样子的话,可以简单理解为吹牛吹大了,鬼知道真还是假,当是真的算了。


p q p→q
0 0 1
0 1 1
1 0 0
1 1 1


======================================================================================


有了以上的离散数学基础知识,可以开始解那道逻辑题了:


如果我有一千万,我就能买到房子。现在我没有一千万,我不能买到房子。


(以下的解法有可能你会觉得发现了新大陆,反正我是觉得真的很神奇,再次体会到数学之美


解:先把陈述句全部用字母和符号表示:


p : 我有一千万

q : 我能买到房子


┐p : 我没有一千万

┐q : 我不能买到房子


p→q : 如果我有一千万,我就能买到房子

┐p→┐q : 我没有一千万,我不能买到房子


有了以上的表示方式,就可以继续往下做,对于题目陈述句“如果我有一千万,我就能买到房子。现在我没有一千万,我不能买到房子。”这句话,有两种表示方式:


(1)(p→q)→(┐p→┐q)

(2)((p→q)∧┐p) → ┐q


为了接下来用C语言编写程序方便,我们来选用 第(2)种 方式列真值表

(这种方式的意思是把((p→q)p)当成前提条件,把┐q当成结论,通过合取p→q和p来推结论┐q是否正确


p ┐p
q ┐q
p→q ((p→q)∧┐p)
((p→q)∧┐p)→┐q
0 1 0 1 1 1 1
0 1 1 0 1 1 0
1 0 0 1 0 0 1
1 0 1 0 1 0 1



观察真值表,发现((p→q)p)→┐q不是重言式(全为真),因为其中有一个0这就意味着,推理后可以判定这道题的逻辑是有问题的,是错的。在形式逻辑学中,有一个很重要的思想,就是将一句话用字母和符号完整表示出来后,通过离散数学的运算规则列出真值表,如果表达式的真值中存在假即0时,就说明这句话的逻辑是错误的,推理是不成立的。


如果不知道((p→q)p)→┐q这个式子是怎么得出真值表的,只要把→符号的左右两边看成整体,再按照前面提到的运算规则即可得出真值表。






激动人心的时候到了,接下来我要用离散数学+形式逻辑学的思想用C语言编写程序来推理验证((p→q)∧┐p)→┐q的正确性。





(一)首先,我准备写一个函数,返回值为布尔型,命名为 decude,即推理的意思,先定义在main主函数之前,调用这个函数就相当于以上用离散数学解题的过程;

bool decude();


(二)现在开始编写decude,定义四个布尔变量,p为“我有一千万,q为“我能买到房子,condition为“我有一千万所以我能买房子”和“我有一千万所以我能买房子,现在我没有一千万”(之后会在代码动态变化),result为推理结果,默认为1即推理是正确的;

	bool p;
	bool q;
	
	bool condition;	
	bool result = 1;



(三)前面说过,离散数学中的因果关系的真值表十分特殊,只有因是真的、果是假的情况时,推理出的结果就是假的,其他情况都是真的。所以在代码中,可以通过以下代码来实现这个逻辑;

	if( p==1 && q==0 ){
		
		condition = 0;
	}
	else{
		
		condition = 1;
	}


对应的真值表是:

p q p→q
0 0 1
0 1 1
1 0 0
1 1 1


(四)当condition变量为“我有一千万所以我能买房子”时并且求出真值后,再合取“我能买到房子”q,又可得出新的condition,意思变为了“我有一千万所以我能买房子,现在我没有一千万”。简单来说,condition变量就是根据p→q的值再求出并被赋值成(p→q)p的真值

	condition = condition && !p; 


(五)如果你没看懂以上四点,请先屡清楚逻辑。上面四点都只是针对某个确定的真值情况来求结果的,但是p和q的真值组合可以达到4种情况,所以,我要用for循环来把每一种真值情况都遍历一遍,才能推理出最终正确的结果

    //两层嵌套,嵌套内容语句最多执行四次,即可以把所有真值情况都遍历一遍
    for(int i=0; i<=1; i++){
        for(int j=0; j<=1; j++){
            
            p = i;    //i为遍历p的真值,0为假,1为真
            q = i;    //j为遍历q的真值,0为假,1为真

            /*其他内容。。。*/
        }
    }
    


(六)还记得还有一个变量result吗?默认为1,代表推理结果是正确的,但是在for循环中遍历的时候,如果result被修改为0,即已经计算出((p→q)p)→┐q的真值是0的时候,没有再循环的必要,所以要退出循环,最后将result值返回;

	if(condition==1 && !q==0){
		
		result = 0;
	}
	
	if(result == 0){
		break;
	}




(七)以上六步,就是应用离散数学到C语言代码中的思想,接下来直接上完整代码:


	#include <stdio.h>
	
	bool decude();
	
	int main(){
		
		bool result = decude();		//调用推理过程,获取返回值 
		
		if(result == 0){
			printf("经过推理后,得出结论不正确\n\n"); 
		}
		else{
			printf("经过推理后,得出结论正确\n\n");
		}
		
		return 0;
	}
	
	//推理过程 
	bool decude(){
		
		bool p;		//前提一:我有一千万
		bool q;		//前提二:我能买到房子 
		bool condition;		//前提三:如果我有一千万,我就能买到房子 
		
		
		bool result = 1;	// 结论:我能买到房子 
		
		
		for(int i=0; i<=1; i++){	//遍历p前提一的真值 
			
			if(result == 0){	//如果得出结论是错误的,没有再循环下去的必要 
				break;			//退出循环 
			}
			
			for(int j=0; j<=1; j++){	//遍历q前提二的真值 
				
				p = i;		//将遍历到的i值赋给p当真值 
				q = j;		//将遍历到的j值赋给q当真值 
				
						
				if( p==1 && q==0 ){		//如果p,则q的真值为假 
					
					condition = 0;		//前提三 " 如果我有一千万,我就能买到房子 " 的真值为假 
				}
				else{
					
					condition = 1;		//前提三 " 如果我有一千万,我就能买到房子 " 的真值为真 
				}
				
				//前提三变为前提四
				condition = condition && !p; 	//前提四: 如果我有一千万,我就能买到房子,现在我没有一千万 
		
		
				if(condition==1 && !q==0){		//如果 " 如果我有一千万,我就能买到房子,现在我没有一千万 ",则 " 我买不到房子 " 为假 
					
					result = 0;		//得出推理结果的错误的 
				}
				
				
				if(result == 0){	//如果得出结论是错误的,没有再循环下去的必要 
					break;			//退出循环 
				}
				
			}
		}
		
		return result;		//循环结束后,返回推理结果 
	}
	




正文结束


本人形式逻辑学学得不深,所以上述难免会有误之处,而且写作水平不高,许多地方表述不够清楚,代码方面也没有用上好的算法,还请看完本文的大神多多指点。




看过本文的人也看了:
发表评论

4个评论

  • qq_40625027

    真要算起来,没那么多纸给你写吖

    2017-10-25 14:04:57回复

  • a727911438

    用算卦来理解还真开阔了我的思路,原来还能这样啊哈哈

    2017-07-01 21:43:11回复

  • UncleJokerly

    哈哈哈哈哈,这画风才对嘛,好像找到了队友了说~个人理解因果关系那段可以这样理解:一个算卦的,他说结局是真的(p=1),如果结局是假的(q=0),那么他说得再对结局也是假的(结果为0)。同属小白,我只会这么生动形象的举例子帮助愚笨的自己理解了。。

    2017-06-18 17:49:50回复

  • labixiaoxinn

    回复UncleJokerly: 这思路清奇,赞一个

    2017-08-05 18:11:16回复

我要留言×

技术领域:

我要留言×

留言成功,我们将在审核后加至投票列表中!

提示x

人工智能规划与决策知识库已成功保存至我的图谱现在你可以用它来管理自己的知识内容了

删除图谱提示×

你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?

删除节点提示×

无法删除该知识节点,因该节点下仍保存有相关知识内容!

删除节点提示×

你确定要删除该知识节点吗?