需求分析
此次四则运算的要求如下:
1.由txt文档中逐行导入算式,算式中实型用分数形式表示。
2.算式中应涵盖加减乘除括号,真假分数,以及长度大于10的超长算式。
3.判断用户输入算式的值是否正确,如正确则提示,错误则显示正确答案。
总体设计
按照之前博客讲的,将一个大任务拆分成多个独立子任务的思路。我将四则运算的求解拆分成如下4个问题:
1.中缀表达式转后缀
2.后缀表达式求值
3.分式计算及化简
4.剔除错误算式
具体分析
1.中缀表达式转后缀
按照上学期数据结构所学的知识,开辟一个栈用来存储运算符号,并由一个字符串来将结果输出,具体算法可参照数据结构时的作业。这次项目较数据结构时的进步是我学会了C++中stringstream的用法,这个函数可以更简便地将大于10的数切分出来。
例:
stringstream str; int temp; str << "1000+2"; str >> temp; cout<
执行一遍代码之后,输出值1000。这样一来我们可以通过控制字符串的角标,来更方便地实现大于10的数的拆分。
2.后缀表达式求值
同样是数据结构的知识,开辟出一个存放中间结果的栈,通过执行类似calculate(num1,num2,operator)的函数,不断地将数存入取出,直到算出最终结果。由于此次项目主要的存储类型是分式,所以这个栈所存放的数据皆为分式,具体的分式运算方法将在下面介绍。
3.分式计算及化简
定义分式的存储类型为[fenzi,fenmu],即执行运算函数时对应的运算对象也为分式类型。
但实际传给计算函数的是一个字符串,例如:算式"1+1/3",转换后传给运算函数的是"1 1 3 /+"。此时可先将fenmu=1,即将字符串先"整理"(并未实际更改,只是在调用运算函数时令其符合格式)为"[1,1] [1,1] [3,1] / +"。在遇到除法符号时最终输出时可设定当fenmu=1时仅输出fenzi。这样就解决的分式运算的问题。
则具体对应的四个运算方式可表示为(令b,d的最大公倍数为lcm):
(1)加法:a/b+c/d = (a*lcm/b+c*lcm/d)/lcm
(2)减法:a/b-c/d = (a*lcm/b-c*lcm/d)/lcm
(3)乘法:(a/b)*(c/d) = (a*c)/(b*d)
(4)除法:(a/b)/(c/d) = (a*d)/(c*b)
其中最小公倍数lcm可利用循环如下求得:
int lcm(int a,int b) { //最小公倍数 int i; for(i = max(a,b);i <= a * b;i += max(a,b)){ if(i % min(a,b)== 0) break; } return i;}
运算之后需要将所得分式进行化简,通过辗转相除法求出分子和分母的最大公约数来,来得到最简分数。
int gcd(int a,int b) { //最大公约数 if(b == 0) return a; else return gcd(b,a % b);}
4.剔除错误算式
出于软件的健壮性考虑,需要将不规范的算式进行剔除,以免整个软件崩掉。我在除法和中缀变后缀转换时分别设置了判别错误算式的条件:如果被除数为0,则改变flag;如果转换时出现非法字符,则返回字符串"error",运算函数被输入"error"时将不做运算,转而改变flag。
功能测试
按照 易计算数据,典型数据,极端数据, 假数据 四个类型的数据测试如下:
由测试结果可知,该程序基本完成项目需求。
总结与展望
经过此次设计,我巩固了数据结构的知识,学习到了类似stringstream这样新的函数方法,并且基本掌握了软件开发的流程。
但是此次发布的软件还有些不足:
1.负数不能
2.图形化界面
3.此次开发基于Mac系统,txt必须要绝对路径,好久没有找到相对路径的方法。用户体验需提高。
4.算式判重未予考虑
总体来说这次项目让我收获到很多。
另在此特谢王宜鸣同学的指导。