郑州师范学院信息科学与技术学院《简单计算器》课程设计报告设计题目:简单计算器班级: B15计科二班组长:组员:指导教师:完成日期: 2016 年 12 月 23 日成绩:摘要本次选做的课程设计是实现简单计算器的问题。
计算器是一个常用的运算工具,本次课题要求用程序语言的方式解决问题。
此问题仅使用数据结构中的栈操作就可以解决此问题。
而在为了方便使用,添加了easyx图形库实现了UI设计。
为了接近平常使用的计算器,特地创建死循环而且添加了“CE”清空输入和“<-”删除键来控制输入错误或者循环使用的问题。
在UI方面主要是实现按键和点击响应等交互,方便输入和修改,在程序框上面有输入和显示结果的文本框。
在计算过程中,以栈出栈进站的特性把中缀形式的算数表达式转化为计算机方便计算的后缀表达式,最后计算出结果以文本方式显示在结果输出框内。
目录摘要 (I)目录 ............................................................. I I 1需求分析. (3)1.1功能简介及分析 (3)1.2设计平台 (3)2概要设计 (3)2.1 Trans函数 (3)2.2 Compvalue 函数 (4)2.3 GetKey函数 (4)3详细设计和实现 (4)3.1转化为逆波兰式 (4)3.2计算逆波兰式 (6)3.3实现流程图 (7)3.3部分具体程序 (8)4调试与操作说明 (13)4.1调试情况 (13)4.2操作说明 (14)5设计总结 (15)参考文献 (16)1需求分析1.1功能简介及分析本次选做的课程设计是实现简单的计算器并且添加UI的交互。
此计算器是以软件的形式实现的计算器,运行在windows系统。
计算器在功能上分为三类,分别是:常见计算器,专用计算器,综合功能计算器。
常见的计算器又分为四种:①简单型计算器:只实现基本的加减乘除和括号运算。
②科学型计算器:可以进行乘方、开方、指数、对数、三角函数、统计等方面的运算,又称函数计算器。
③程序员计算器:专门为程序员设计的计算器, 主要特点是支持And, Or, Not, Xor:最基本的与或非和异或操作, 移位操作 Lsh, Rsh:全称是Left Shift和Right Shift,也就是左移和右移操作,你需要输入你要移动的位数(不能大于最大位数) RoL, RoR:全称是Rotate Left和Rotate Right,对于RoL来讲,就是向左移动一位,并将移出的那位补到最右边那位上,RoR类似。
④统计型计算器:为有统计要求的人员设计的设计的计算器。
本次课程设计只是实现了常见的简单计算器:在界面上:简单的计算器需要有简单的按键和按键响应,有输入和结果的显示。
在功能上:能进行加减乘除混合运算,可以使用括号,有“M”键可以存储结果,以便下次计算使用,可以对输入的文本删除和重置。
并且可以在重置后继续使用。
1.2设计平台Windows7操作系统;Visual Studio 20152概要设计2.1 Trans函数主要功能中缀算术表达式转化成后缀表达式,然后存到栈里,以便计算时使用,转化时包括对小括号的匹配。
2.2 Compvalue 函数主要功能是对栈中的后缀表达式进行计算,然后返回float类型的结果。
2.3 GetKey函数GetKey主要是在UI界面中获取按键然后保存成字符数组或者对字符数组的增减操作的函数。
此函数为内置死循环,可以重复使用。
3详细设计和实现实现软件形式的常用简单计算机,主要用到栈的特点,把平常使用的表达式,转化为能够让计算机计算的逆波兰表达式。
中缀表达式(或中缀记法)是一个通用的算术或逻辑公式表示方法,操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。
与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
与前缀或后缀记法不同的是,中缀记法中括号是必需的。
计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。
例:(1)8+4-6*2用后缀表达式表示为:62*84+-(2)2*(3+5)-4+7/1用后缀表达式表示为:35+2*71/4-+3.1转化为逆波兰式首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入逆波兰式的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。
可指定其他字符,不一定非#不可。
从中缀式的左端开始取字符,逐序进行如下步骤:(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级大于S1栈栈顶运算符优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,则将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈底。
(4)若取出的字符是“)”,则将距离S1栈栈底最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符。
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。
不过S2应做一下逆序处理。
便可以按照逆波兰式的计算方法计算了!例如转换:2-(1+2)*3+4转换后的逆波兰表达式是:2 1 2 + 3 * - 4 +3.2计算逆波兰式逆波兰式的计算同样用到了栈的特点,首先需要建立一个空栈T,然后从头遍历逆波兰式,如果是数字则直接放到栈顶,如果遇到操作符则连续取出两个栈顶数据,分别赋值给n1,n2,再根据操作符计算n1和n2,把得到的结果放到T 栈栈顶,继续操作,直到遍历完毕。
以上面的例子计算过程如图:最后得出的结果是-3,即2-(1+2)*3+4=-3;所以计算的具体过程是先转化中缀表达式为逆波兰表达式,然后由逆波兰表达式计算出结果,在转化的过程和最后的计算过程都用到了栈的思想,利用栈的进栈和出栈的特点实现转换。
3.3部分具体程序//界面显示文字,”$”表示结束位置char KeyStr[][4] = { { "CE"} ,{ "<-"} ,{ "M" } ,{ "/" },{ "(" } ,{ ")" } ,{ "^" } ,{ "^" },{ "7" } ,{ "8" } ,{ "9" } ,{ "*" },{ "4" } ,{ "5" } ,{ "6" } ,{ "+" },{ "1" } ,{ "2" } ,{ "3" } ,{ "-" },{ "00"} ,{ "0" } ,{ "." } ,{ "=" },{ "$" } };void Trans(STR *InStr , char Lasts[]){/*将算术表达式转化为后缀表达式*/int i = 1;char Stack[MAX];/*作为栈使用*/char ChStr = InStr->Str[i]; //用于保存数组里的临时元素i++;int LastStrPos = 1, StackTop = 0; //StackTop用于表示栈顶while (ChStr != '#'){switch (ChStr){case'(': /*判定为左括号*/StackTop++;Stack[StackTop] = ChStr;break;case')': /*判定为右括号*/while (Stack[StackTop] != '('){Lasts[LastStrPos] = Stack[StackTop];StackTop--;LastStrPos++;}StackTop--; //扔掉(break;case'+': /*判定为加减号*/case'-':while (StackTop != 0 && Stack[StackTop] != '('){Lasts[LastStrPos] = Stack[StackTop];StackTop--;LastStrPos++;}StackTop++; //保留(Stack[StackTop] = ChStr;break;case'*': /*判定为乘除号*/case'/':while (Stack[StackTop] == '*' || Stack[StackTop] == '/'){ Lasts[LastStrPos] = Stack[StackTop]; //如果栈顶是*或者/弹出,放到后缀数组里StackTop--;LastStrPos++;}StackTop++;Stack[StackTop] = ChStr;break;case' ':break; //忽略空格default:while (ChStr >= '0' && ChStr <= '9' || ChStr == '.'){ /*判定为数字*/Lasts[LastStrPos] = ChStr;LastStrPos++;ChStr = InStr->Str[i];i++;}i--;Lasts[LastStrPos] = ' '; //输出的时候隔开元素LastStrPos++;}ChStr = InStr->Str[i]; i++;}while (StackTop != 0){Lasts[LastStrPos] = Stack[StackTop];LastStrPos++;StackTop--;}Lasts[LastStrPos] = ' ';LastStrPosT = LastStrPos;}float Compvalue(char LastStrTemp[]){ /*计算后缀表达式的值*/float Stack[MAX]; /*作为栈使用*/char ChStr; //临时栈元素int StackTop = 0; /*LastStrPos为Lasts下标,StackTop为Stack 下标*/int LastStrPos = 1;ChStr = LastStrTemp[LastStrPos];LastStrPos++;while (ChStr != ' '){switch (ChStr){case'+':Stack[StackTop - 1] = Stack[StackTop - 1] + Stack[StackTop];StackTop--;break;case'-':Stack[StackTop - 1] = Stack[StackTop - 1] - Stack[StackTop];StackTop--;break;case'*':Stack[StackTop - 1] = Stack[StackTop - 1] * Stack[StackTop];StackTop--;break;case'/':if (Stack[StackTop] != 0)Stack[StackTop - 1] = Stack[StackTop - 1] /Stack[StackTop];else{exit(0);/*异常退出*/}StackTop--;break;default:float NumStr = 0; //把数字字符转化为数字bool FlNum = 0;while (ChStr >= '0' && ChStr <= '9' || ChStr == '.'){if (ChStr == '.') {FlNum = 1;}else if (!FlNum) {NumStr = 10 * NumStr + ChStr - '0';/*将数字字符转化为对应的数值*/}else if (FlNum) {NumStr += 0.1 * (ChStr - '0'); /*计算小数*/}ChStr = LastStrTemp[LastStrPos];LastStrPos++;}StackTop++;Stack[StackTop] = NumStr;}ChStr = LastStrTemp[LastStrPos];LastStrPos++;}return Stack[StackTop];}void GetKey() {/*FlushMouseMsgBuffer 清空鼠标消息缓冲区。