一.实验内容

(1)求任意一个命题公式的真值表。

(2)利用真值表求任意一个命题公式的主范式。

(3)利用真值表进行逻辑推理。

注:(2)和(3)可在(1)的基础上完成。

二.实验目的

真值表是命题逻辑中的一个十分重要的概念,利用它几乎可以解决命题逻辑中的所有问题。例如,利用命题公式的真值表,可以判断命题公式的类型、求命题公式的主范式、判断两命题公式是否等价,还可以进行推理等。

本实验通过编写一个程序,让计算机给出命题公式的真值表,并在此基础上进行命题公式类型的判定、求命题公式的主范式等。目的是让学生更加深刻地理解真值表的概念,并掌握真值表的求解方法及其在解决命题逻辑中其他问题中的应用。

三.算法的主要思想

利用计算机求命题公式真值表的关键是:①给出命题变元的每一组赋值;②计算命题公式在每一组赋值下的真值。

真值表中命题变元的取值具有如下规律:每列中0和1是交替出现的,且0和1连续出现的个数相同。n个命题变元的每组赋值的生成算法可基于这种思想。

含有n个命题变元的命题公式的真值的计算采用的方法为“算符优先法”。

为了程序实现的方便,约定命题变元只用一个字母表示,非、合取、析取、条件和双条件联结词分别用!、&、|、-、+来表示。

算符之间的优先关系如表1-32所示:

表1-32 算符优先级

+   -    |    &    !    (   )   #

|

&

!

#

>   <   <   <   <    <  >   >

>   >   <   <   <    <  >   >

>   >   >   <   <    <  >   >

>   >   >   >   <    <  >   >

>   >   >   >   >    <  >   >

<   <   <   <   <    <  =    E

>   >   >   >   >    E   >   >

<   <   <   <   <   <   E    =

为实现算符优先算法,我们采用两个工作栈。一个称作OPTR,用以寄存运算符;另一个称作OPND,用以寄存操作数或运算结果。

四.算法的具体实现  

(1)定义全局的属性:

    (这里栈就直接调用C++有的库#include<stack>,就不用自己再写栈的代码)

     运算符栈OPTR

     操作数或运算结果栈OPND

     常量操作字符集合operateChar

     公式中的变元VarList  

stack<bool> OPND;//操作数或运算结果栈
stack<char> OPTR;//运算符栈
const char operateChar[8] = { '+', '-', '|', '&', '!', '(', ')','#' };//运算符(+:等价、-:蕴涵、|:析取、&:合取、!:否定
string VarList;//保存公式中的变元

(2)判断字符是否是运算符

//判断字符是否是运算符
bool In(char ch) {
for (int i = 0; i < (int)strlen(operateChar); i++)
if (operateChar[i] == ch)
return true;
return false;
}

(3)比较运算符的优先级

     这里可以直接用二维字符数组实现运算符优先级表,将OPTR的栈顶运算符(theta1)与新输入的运算符(theta1)作比较,各自按照operateChar的顺序赋值就可以得到优先级

//比较运算符的优先级
char Precede(char theta1, char theta2) {
//运算符优先级表
char operate_Table[8][9] = {
"><<<<<>>",
">><<<<>>",
">>><<<>>",
">>>><<>>",
">>>>><>>",
"<<<<<<=E",
">>>>>E>>",
"<<<<<<E="
};
int theta1_Index=0, theta2_Index=0;//定义运算符1和运算符2的索引
for (int i = 0; i < (int)strlen(operateChar); i++){
if (operateChar[i] == theta1)
theta1_Index = i ;
if (operateChar[i] == theta2)
theta2_Index = i ;
}
return operate_Table[theta1_Index][theta2_Index];
}

(4)计算表达式,并将结果返回(这里是计算双目的,在这次试验命题公式中只有!是单目运算符所以到时直接在计算表达式时直接计算)

//计算表达式,并将结果返回(双目)
bool Calculate(bool x, char operate, bool y) {
switch (operate)
{
case '+': return (((!x) || y) && (x || (!y))); break;
case '-': return ((!x) || y); break;
case '|': return x || y; break;
case '&': return x && y; break;
}
return -1;
}

(5)判断是否是字母(用来将公式中的命题变元提取出来),然后将变元按递增顺序赋值给VarList

     我就只做了小写字母的,大写字母可以自己改下判断条件

//判断是否是字母(仅小写字母)
bool isAlpha(char ch) {
if (((int)ch >= 97 && (int)ch <= 122)&&VarList.find(ch)==-1)//若字符的ascii码在97~122中则是字母
return true;
else return false;
}
//提取公式字符串中全部命题变元,并按递增顺序存放在VarList中
void createVarList(string source) {
int indexNum=0;//比较字母用的下标 for (auto ch:source) {
if (isAlpha(ch))
VarList += ch;
}
for (int i = 0; i < VarList.length()-1;i++) {
for (int j = 0; j < VarList.length() - i-1; j++) {
if ((int)VarList[j] > (int)VarList[j + 1]) {
char temp = VarList[j];
VarList[j] = VarList[j + 1];
VarList[j + 1] = temp;
}
}
}
}

(6)计算表达式

bool InfixValue(string source) {
OPTR.push('#');
char item = source[0];
bool OPNDtop2, OPNDtop1;
char OPTRtop;
int i = 1;
while (item != '#' || OPTR.top() != '#') {
if (!In(item)) {
if (item == '0')
OPND.push(false);
else
OPND.push(true);
item = source[i++];
}
else if (OPTR.top() == '!')
{
OPTR.pop();
OPNDtop1 = OPND.top();
OPND.pop();
OPND.push(!OPNDtop1);
}
else
{
switch (Precede(OPTR.top(), item))
{
case '<':
OPTR.push(item);
item = source[i++];
break;
case '>':
OPTRtop = OPTR.top();
OPTR.pop();
OPNDtop1 = OPND.top();
OPND.pop();
OPNDtop2 = OPND.top();
OPND.pop();
OPND.push(Calculate(OPNDtop2, OPTRtop, OPNDtop1));
break;
case '=':
OPTR.pop();
item = source[i++];
break;
}
}
}
return OPND.top();
}

(7)因为我们要获得变元所有的取值情况,所以可以当成二进制来依次递增

     比如  变元有 a b c 三个,就是从 000 开始依次取到111

     这就需要一个对二进制增值的方法

//依次取值的二进制值加1
void IncreaseVarValue(char(&v)[26], int& flag) {
int m = 1; int n = VarList.length();
for (int j = n - 1; j > -1; j--) {
int temp;
temp = int(v[j]) - 48;
flag = flag + temp;
if (flag == 2) {
v[j] = '0'; flag = 1;
}
else {
v[j] = '1'; flag = 0; break;
}
} }

(8)得到真值表

void TruthTable(string expression,bool * &truthTab,string *&expressionValueList,string *&trowList,int &CircleNum) {
int m = 1;
int n = VarList.length();
int flag;
char trow[26];//表达式中变元的依次取值
for (int i = 0; i < n; i++) { m *= 2; trow[i] = '0'; }
string* expressionValueList_IN = new string[m];
string* trowList_IN = new string[m];
bool *truthtable_IN=new bool[m];//真值表中的值
CircleNum = m; //转换成用0或1表示的表达式
for (int i = 0; i < m; i++) {
string value1 = expression;//因为公式是字符串无法直接计算,所以定义value1,将里面的命题变元变成0或1
//使表达式的变元用0或1表示
for (int j = 0; j < n; j++) {
char x = VarList[j];
for (int k = 0; k < expression.length(); k++) {
char a = value1[k];
if (value1[k] == x)
value1[k] =trow[j];
} }
trowList_IN[i] = trow;
expressionValueList_IN[i] = value1;
truthtable_IN[i] = InfixValue(value1);//将得出来的值依次给truthtable
flag = 1;
IncreaseVarValue(trow,flag);
}
truthTab = truthtable_IN;
expressionValueList = expressionValueList_IN;
trowList = trowList_IN;
}

(9)最后输出真值表

//输出真值表
void PrintTable(string expression) {
string* expressionValueList;//用来保存所有的表达式
string* trowList;//保存变元的所有取值
bool* truthtab;//保存所有的表达式的值
int CircleNum;//循环次数
createVarList(expression);
TruthTable(expression, truthtab, expressionValueList, trowList,CircleNum);
//打印真值表
for (int i = 0; i < VarList.length(); i++) {
cout << VarList[i] << "\t";
}
cout << expression <<"\t" <<"值"<<endl; for (int i = 0; i < CircleNum; i++) {
for (int j = 0; j < VarList.length(); j++) {
cout << trowList[i][j] << "\t";
}
cout << expressionValueList[i] << "\t" << truthtab[i] << endl;;
}
}

  

完整的代码:

#include<iostream>
#include<math.h>
#include<string.h>
#include<stack>
using namespace std; stack<bool> OPND;//操作数或运算结果栈
stack<char> OPTR;//运算符栈
const char operateChar[8] = { '+', '-', '|', '&', '!', '(', ')','#' };//运算符(+:等价、-:蕴涵、|:析取、&:合取、!:否定
string VarList;//保存公式中的变元 //判断字符是否是运算符
bool In(char ch) {
for (int i = 0; i < (int)strlen(operateChar); i++)
if (operateChar[i] == ch)
return true;
return false;
} //比较运算符的优先级
char Precede(char theta1, char theta2) {
//运算符优先级表
char operate_Table[8][9] = {
"><<<<<>>",
">><<<<>>",
">>><<<>>",
">>>><<>>",
">>>>><>>",
"<<<<<<=E",
">>>>>E>>",
"<<<<<<E="
};
int theta1_Index=0, theta2_Index=0;//定义运算符1和运算符2的索引
for (int i = 0; i < (int)strlen(operateChar); i++){
if (operateChar[i] == theta1)
theta1_Index = i ;
if (operateChar[i] == theta2)
theta2_Index = i ;
}
return operate_Table[theta1_Index][theta2_Index];
}
//计算表达式,并将结果返回(双目)
bool Calculate(bool x, char operate, bool y) {
switch (operate)
{
case '+': return (((!x) || y) && (x || (!y))); break;
case '-': return ((!x) || y); break;
case '|': return x || y; break;
case '&': return x && y; break;
}
return -1;
} //判断是否是字母(仅小写字母)
bool isAlpha(char ch) {
if (((int)ch >= 97 && (int)ch <= 122)&&VarList.find(ch)==-1)//若字符的ascii码在97~122中则是字母
return true;
else return false;
} //提取公式字符串中全部命题变元,并按递增顺序存放在VarList中
//比如 (!a-d)-(c+b) VarList值就是 "abcd"
void createVarList(string source) {
int indexNum=0;//比较字母用的下标 for (auto ch:source) {
if (isAlpha(ch))
VarList += ch;
}
for (int i = 0; i < VarList.length()-1;i++) {
for (int j = 0; j < VarList.length() - i-1; j++) {
if ((int)VarList[j] > (int)VarList[j + 1]) {
char temp = VarList[j];
VarList[j] = VarList[j + 1];
VarList[j + 1] = temp;
}
}
}
} //计算表达式
bool InfixValue(string source) {
OPTR.push('#');
char item = source[0];
bool OPNDtop2, OPNDtop1;
char OPTRtop;
int i = 1;
while (item != '#' || OPTR.top() != '#') {
if (!In(item)) {
if (item == '0')
OPND.push(false);
else
OPND.push(true);
item = source[i++];
}
else if (OPTR.top() == '!')
{
OPTR.pop();
OPNDtop1 = OPND.top();
OPND.pop();
OPND.push(!OPNDtop1);
}
else
{
switch (Precede(OPTR.top(), item))
{
case '<':
OPTR.push(item);
item = source[i++];
break;
case '>':
OPTRtop = OPTR.top();
OPTR.pop();
OPNDtop1 = OPND.top();
OPND.pop();
OPNDtop2 = OPND.top();
OPND.pop();
OPND.push(Calculate(OPNDtop2, OPTRtop, OPNDtop1));
break;
case '=':
OPTR.pop();
item = source[i++];
break;
}
}
}
return OPND.top();
} //依次取值的二进制值加1
void IncreaseVarValue(char(&v)[26], int& flag) {
int m = 1; int n = VarList.length();
for (int j = n - 1; j > -1; j--) {
int temp;
temp = int(v[j]) - 48;
flag = flag + temp;
if (flag == 2) {
v[j] = '0'; flag = 1;
}
else {
v[j] = '1'; flag = 0; break;
}
} } //得到真值表
void TruthTable(string expression,bool * &truthTab,string *&expressionValueList,string *&trowList,int &CircleNum) {
int m = 1;
int n = VarList.length();
int flag;
char trow[26];//表达式中变元的依次取值
for (int i = 0; i < n; i++) { m *= 2; trow[i] = '0'; }
string* expressionValueList_IN = new string[m];
string* trowList_IN = new string[m];
bool *truthtable_IN=new bool[m];//真值表中的值
CircleNum = m; //转换成用0或1表示的表达式
for (int i = 0; i < m; i++) {
string value1 = expression;//因为公式是字符串无法直接计算,所以定义value1,将里面的命题变元变成0或1
//使表达式的变元用0或1表示
for (int j = 0; j < n; j++) {
char x = VarList[j];
for (int k = 0; k < expression.length(); k++) {
char a = value1[k];
if (value1[k] == x)
value1[k] =trow[j];
} }
trowList_IN[i] = trow;
expressionValueList_IN[i] = value1;
truthtable_IN[i] = InfixValue(value1);//将得出来的值依次给truthtable
flag = 1;
IncreaseVarValue(trow,flag);
}
truthTab = truthtable_IN;
expressionValueList = expressionValueList_IN;
trowList = trowList_IN;
} //输出真值表
void PrintTable(string expression) {
string* expressionValueList;//用来保存所有的表达式
string* trowList;//保存变元的所有取值
bool* truthtab;//保存所有的表达式的值
int CircleNum;//循环次数
createVarList(expression);
TruthTable(expression, truthtab, expressionValueList, trowList,CircleNum);
//打印真值表
for (int i = 0; i < VarList.length(); i++) {
cout << VarList[i] << "\t";
}
cout << expression <<"\t" <<"值"<<endl; for (int i = 0; i < CircleNum; i++) {
for (int j = 0; j < VarList.length(); j++) {
cout << trowList[i][j] << "\t";
}
cout << expressionValueList[i] << "\t" << truthtab[i] << endl;;
}
}
void main() {
system("pause");
while (true) {
cout << "*****************************************************" << endl;
cout << "*** +表示等价 ***" << endl;
cout << "*** -表示蕴涵 ***" << endl;
cout << "*** &表示合取 ***" << endl;
cout << "*** |表示析取 ***" << endl;
cout << "*** 注:必须用#结束 ***" << endl;
cout << "*** 输入1退出程序 ***" << endl;
cout << "*****************************************************" << endl;
cout << "请输入命题公式:";
string expression;
cin >> expression;
if (expression == "1") {
break;
}
//如果没有#
if (expression.find('#') != expression.length() - 1)
{
cout << "请以#结束!" << endl;;
system("pause");
system("cls");
continue;
}
PrintTable(expression);
system("pause");
system("cls");
} }

C++实现求离散数学命题公式的真值表的更多相关文章

  1. 构造命题公式的真值表--biaobiao88

    对给出的任意一个命题公式(不超过四个命题变元),使学生会用C语言的程序编程表示出来,并且能够计算它在各组真值指派下所应有的真值,画出其真值表. #include<iostream> usi ...

  2. 求pi 的公式

    pi = 3.1415926..... 下面用c 语言来求解PI 现有公式 (pi*pi)/6 = 1 + 1/(2*2) + 1/(3*3) + ... + 1/(n*n); #include &l ...

  3. POJ 3047 Bovine Birthday 日期定周求 泽勒公式

    标题来源:POJ 3047 Bovine Birthday 意甲冠军:.. . 思考:式 适合于1582年(中国明朝万历十年)10月15日之后的情形 公式 w = y + y/4 + c/4 - 2* ...

  4. Excel公式-求最低价网站名字

    p{ font-size: 15px; } .alexrootdiv>div{ background: #eeeeee; border: 1px solid #aaa; width: 99%; ...

  5. NewtonPrincipia_物体的运动_求向心力

    NewtonPrincipia_物体的运动_求向心力 让我们看一下十七世纪的被苹果砸中的艾萨克,是怎样推导出向心力公式的 在现在的观点看来,其中涉及到的很多没有符号表示的微分量.下面的内容只是叙述了推 ...

  6. 大数求模 sicily 1020

        Search

  7. fzu 1330:Center of Gravity(计算几何,求扇形重心)

    Problem 1330 Center of Gravity Accept: 443    Submit: 830Time Limit: 1000 mSec    Memory Limit : 327 ...

  8. Harmonic Number 求Hn; Hn = 1 + 1/2 + 1/3 + ... + 1/n; (n<=1e8) T<=1e4; 精确到1e-8; 打表或者调和级数

    /** 题目:Harmonic Number 链接:https://vjudge.net/contest/154246#problem/I 题意:求Hn: Hn = 1 + 1/2 + 1/3 + . ...

  9. HDU 5159 Card (概率求期望)

    B - Card Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Sta ...

随机推荐

  1. 血的教训!千万别在生产使用这些 redis 指令

    哎,最近小黑哥又双叒叕犯事了. 事情是这样的,前一段时间小黑哥公司生产交易偶发报错,一番排查下来最终原因是因为 Redis 命令执行超时. 可是令人不解的是,生产交易仅仅使用 Redis set 这个 ...

  2. redhat中的RHCS双机配置

    1. 主机概述 主机名 主机IP 备注 node1 192.168.1.101 模拟fence设备 node2 192.168.1.102 rhcs双机节点 node3 192.168.1.103 r ...

  3. Vue环境搭建、创建与启动、案例

    vue环境搭建 """ 1) 安装node 官网下载安装包,傻瓜式安装:https://nodejs.org/zh-cn/ 2) 安装cnpm npm install - ...

  4. Unity3D 一、游戏

    3D游戏编程第一次作业 作业要求 阅读 Tracy Fullerton, *GAME DESIGN WORKSHOP* 第2-4章(游戏结构.基本元素.戏剧元素).选择一款你喜欢的中等规模游戏如&qu ...

  5. Ubuntu16.04 Nvidia显卡驱动简明安装指南

    简单得整理了一下Ubuntu16.04 Nvidia显卡驱动的安装步骤: 查看当前系统显卡参数: sudo lspci | grep -i nvidia 删除之前的驱动: sudo apt-get - ...

  6. java 判断jsonObject 对象为null的天坑问题

    jsonObject = {"mmbRetrieveBookingResponse":{"bookingData":null,"isAfterTran ...

  7. C++练习案例1.计算机类(利用多态实现)

    c++简单计算机类 简介 大家好,这里是天天like的博客,这是我发的第一篇随笔,用来记录我的学习日程,大家可以相互学习,多多交流,感谢 今天我要记录的随笔是在学习c++多态的知识点练习改进的一个案例 ...

  8. 升​级​到​w​i​n​8​.​1​导​致​o​r​a​c​l​e​服​务​丢​失​的​处​理

    针对升级到win8.1导致oracle服务丢失的处理 1.首先保证oracle相关程序能够运行,如net manager,如果能够运行,说明oracle安装仍然有效,只是因为服务被"净化&q ...

  9. mysql-2-where

    #进阶2:条件查询 /* 语法: SELECT 查询列表 FROM 表名 WHERE 筛选条件 分类: 1.按条件表达式筛选:> < = != <> >= <= 2 ...

  10. 编写一个Open Live Writer的VSCode代码插件

    起因 又是一年多没有更新过博客了,最近用Arduino做了一点有意思的东西,准备写一篇博客.打开尘封许久的博客园,发现因为Windows Live Writer停止更新,博客园推荐的客户端变为了Ope ...