目录
一、前言
好久没有写东西了,为了重新激起学习的动力,就先从复盘之前离散数学老师让写的实验开始“复健”吧。
二、实验描述
实验题目:含有一个联结词的命题公式的运算
输入:类似1∧1或T∧F这样含有一个联结词的命题运算式,其中的运算数为常量。
输出:运算结果。
要求:程序开始后,可以进行多次运算,直至结束。
(联结词符号自定)
三、题目分析
首先,我们要对“联结词”有个基础的了解
1.否定“┐”
设P为一命题,P的否定是一个新的命题,记作┐P 。若P为T,┐P为F;若P为F,则┐P为T。
P | ┐P |
T | F |
F | T |
2.合取“^”
两个命题P和Q的合取是一个复合命题,记作P^Q。当且仅当P,Q同时为T时,P^Q为T。在其他情况下,P^Q的真值为F。
P | Q | P^Q |
T | T | T |
F | T | F |
T | F | F |
F | F | F |
3.析取“v”
两个命题P和Q的析取是一个复合命题,基记作PvQ。当且仅当P,Q同时为F时,PvQ的真值为F,否则PvQ的真值为T。
P | Q | PvQ |
T | T | T |
F | T | T |
T | F | T |
F | F | F |
4.条件“→”
给定两个命题P和Q,其条件命题是一个复合命题,记作P→Q,当且仅当P的真值为T,Q的真值为F时,P→Q的真值为F,否则P→Q的真值为T。
P | Q | P→Q |
T | T | T |
F | T | T |
T | F | F |
F | F | T |
5.双条件"↔"
给定两个命题P和Q,其复合命题P↔Q,称作双条件命题;当P和Q的真值相同时,P↔Q的真值为T,否则P↔Q的真值为F。
P | Q | P↔Q |
T | T | T |
F | T | F |
T | F | F |
F | F | T |
当我们了解了命题联结词的基础知识后,我们就要考虑下一个问题:如何用计算机来实现这个逻辑?
作为一个简单的一个联结词的运算,首先是想到在每一个功能函数中运用多个if去进行判断属于哪一种情况,再输出对应的值。在这里,我想介绍以下我所了解的位运算的知识进行分析。
对于不了解位运算知识的同学可以去之前的两篇文章说一说位运算和位运算中的技巧中进行了解,相信你会收获的更多!
那么我们来分析一下各个联结词该如何解析成和位运算相关的逻辑呢?
四、函数分析
否定函数
根据前面的说明我们可以知道命题联结词中的“否定”和位运算中的“取反”很像,但在这里要注意,我们的数字在计算机储存中是以二进制储存的,如果我们简单的使用了取反符号的话会发现,“1”取反后不是“0”,“0”取反后也不是“1”,所以,我们要根据取反的思想进行一点变动。
代码块如下:
if(a[i]=='~') { //判断是否定运算
k=1;
b=(a[1]-'0');
if(b==1) //进行取反运算,1变为0,0变为1.
c=0;
else
c=1;}
合取函数
“合取”的思路和“按位与”的运算思路与方法是一致的,所以我们直接用即可。
代码如下:
if(a[i]=='&') { //判断为合取
k=1;
b=a[0]-'0'; //因为主函数是在字符数组中储存数据,因为需要将字符数转化为整数
c=a[2]-'0';
d=(b&c);
}
析取函数
“析取”的思路和“按位或”的运算思路与方法一致,所以和合取一样,直接引用即可。
代码如下:
if(a[i]=='|') { //判断为析取运算
k=1;
b=a[0]-'0'; //将字符数转换为整型数
c=a[2]-'0';
d=(b|c);
}
条件函数
根据基本等价公式我们可以知道P→Q=┐PvQ,也就是将前一个先取反再进行析取。
代码如下:
if(a[i]=='>') { //判断为条件
k=1;
b=a[0]-'0';
c=a[2]-'0';
if(b==1) //对第一个值进行取反
b=0;
else
b=1;
d=(b|c); //析取运算
}
双条件函数
根据基本等价公式可知P↔Q=(P→Q)^(Q→P)=(┐PvQ)^(┐QvP)依照之前条件函数和合取函数的逻辑,将两者进行结合就可以得到双条件函数的代码。
代码如下:
if(a[i]=='<') { //判断为双条件运算
b=a[0]-'0';
c=a[2]-'0';
if(b==1) //对第一个真值取反
e=0;
else
e=1;
if(c==1) //对第二个真值取反
f=0;
else
f=1;
d=((e|c)&(f|b)); //最后实现合取运算
}
五、整体代码
#include <stdio.h>
#include <string.h>
int main() {
void fouding(char a[]);
void hequ(char a[]);
void xiqu(char a[]);
void tiaojian(char a[]);
void shuangtiaojian(char a[]);
//开局定义,确定输入格式与相关符号
printf("输入格式:“真值运算符真值(1&1)”或“~真值(~1)”\n每一组数据用回车键隔开,输入“END”结束\n");
printf("否定符号: ~ \n合取符号: & \n析取符号: | \n排斥或符号: ^ \n条件符号: > \n双条件符号: < \n");
printf("请根据格式输入真值(1/0)及运算符:\n");
//使用字符数组读取所有数据
char p[100];
int i=0;
//为方便进行对于数组的判定以及读取,起始将所有数组进行赋值
for(int j=0; j<100; j++)
p[j]=2;
while(1) {
gets(p); //将数据读入到数组中
p[5]='\0';
while(p[i]!=2)
{printf("%c",p[i]);i++;}
//设置结束标志
if(p[0]=='E'&&p[1]=='N'&&p[2]=='D')
return 0;
//容错模块,一旦出现不符合要求的输入则显示"Input Error!",并强制退出
while(p[i]!=2) {
if(p[i]!='1' && p[i]!='0' && p[i]!='X' && p[i]!='~' && p[i]!='&' && p[i]!='|' && p[i]!='^' && p[i]!='<' && p[i]!='>'&& p[i]!='\0' && p[i]!=' ') {
printf("Input Error!");
return 0;
}
i++;
}
//为实现多次循环,直接调用所有函数,符合则在函数中输出结果,否则继续向下进行,直至找到对应函数
fouding(p);
hequ(p);
xiqu(p);
tiaojian(p);
shuangtiaojian(p);
}
}
void fouding(char a[]) {
int b=0,c,k=0;
for(int i=0; i<strlen(a); i++) {
if(a[i]=='~') {
k=1;
b=(a[1]-'0');
if(b==1)
c=0;
else
c=1;
}
}
if(k)
printf("结果:%d\n",c);
}
void hequ(char a[]) {
int b=0,c=0,k=0,d;
for(int i=0; i<strlen(a); i++) {
if(a[i]=='&') {
k=1;
b=a[0]-'0';
c=a[2]-'0';
d=(b&c);
}
}
if(k)
printf("结果:%d\n",d);
}
void xiqu(char a[]) {
int b=0,c=0,k=0,d;
for(int i=0; i<strlen(a); i++) {
if(a[i]=='|') {
k=1;
b=a[0]-'0';
c=a[2]-'0';
d=(b|c);
}
}
if(k)
printf("结果:%d\n",d);
}
void tiaojian(char a[]) {
int b=0,c=0,k=0,d;
for(int i=0; i<strlen(a); i++) {
if(a[i]=='>') {
k=1;
b=a[0]-'0';
c=a[2]-'0';
if(b==1)
b=0;
else
b=1;
d=(b|c);
}
}
if(k)
printf("结果:%d\n",d);
}
void shuangtiaojian(char a[]) {
int b=0,c=0,k=0,d,e,f;
for(int i=0; i<strlen(a); i++) {
if(a[i]=='<') {
k=1;
b=a[0]-'0';
c=a[2]-'0';
if(b==1)
e=0;
else
e=1;
if(c==1)
f=0;
else
f=1;
d=((e|c)&(f|b));
}
}
if(k)
printf("结果:%d\n",d);
}
六、实验总结
这个实验算是在离散课上老师布置的第一个实验。因为当时已经很久没有敲代码了。思路以及代码块的安排并不是很简洁合理,希望大家多批评多包涵。可以在原有基础上进行优化,变得更加简洁优美。
整理不易,看到这里就给孩子点个赞再走吧^-^