c++课程设计分数计算器.docx
- 文档编号:28416924
- 上传时间:2023-07-13
- 格式:DOCX
- 页数:19
- 大小:413.89KB
c++课程设计分数计算器.docx
《c++课程设计分数计算器.docx》由会员分享,可在线阅读,更多相关《c++课程设计分数计算器.docx(19页珍藏版)》请在冰豆网上搜索。
c++课程设计分数计算器
C++课程设计报告
题目:
分数计算器
年级:
专业:
通信工程
姓名:
指导老师:
难度B级
教师评语:
1.程序功能介绍
分数计算器及测试程序,具有对输入的运算进行“+,-,*,/,^”的功能
2.程序设计要求
(1)完成计算器程序,对main函数的结构进行改进,要求有详细的菜单选项界面,用户不选择退出就可以反复运算。
(2)完善程序,改为多操作数基本四则运算,遇#停止。
(3)增加函数,完成四则混合运算,注意算法要考虑运算符的优先级,对应增加主菜单选项。
(4)增加语句使四则运算具有测试功能,即计算机能够自动出题,并要求用户计算,同时计算机判断用户计算的对错并打分,要求十题一个单元,每题一个运算符,参与运算的分子分母均为一位数,运算符包括加,减,乘,除及大于小于等逻辑运算符。
3.基本数据结构
含有整型变量,字符变量,实型变量,还定义了一个分数类;
除此之外还有以下函数:
1。
分数转换为小数;2。
分数转换为带分数;3。
实现简单计算的函数;4。
混合运算函数;5。
随机测试题函数;6。
清屏函数。
此外还多处运用了运算符的重载
4.程序运行结果界面
1.初始界面
2.功能1
3.功能2
4.功能3
5.功能4
6.功能5
5.课程设计遇到的技术问题与解决思路
问题1:
分数的表示
解决办法:
建立函数,分别置分母,分子,同时构造约分函数
问题2:
真分数的表示
解决办法:
构造函数,置整数部分和分数部分
书本提供的源代码虽然较为完备,但也存在一些错误。
问题3:
乘方的函数功能实现,书本提供的原有的类中重载的“^”运算符无法实现乘方运算
解决办法:
考虑到“^”运算符作为位运算符,不能按照双目运算符的重载格式进行重载,故,将用于代码内部的“^”运算符改为“%”双目运算符进行重载,进行重载运算,但对外输入输出,仍使用作为字符常量的^,解决了源代码中,分数运算乘方无法实现的问题。
fractionoperator%(constfraction&base,intexp)//^运算符并非双目运算符
//不可按照双目运算的方法重载,故修改为%,进行内部操作
{
fractionreturnValue;
returnValue.setnum(pow(base.numerator(),exp));
returnValue.setden(pow(base.denominator(),exp));
returnValue.simplify();
returnreturnValue;
}
问题4:
输出运算符<<重载不完善,因为对于函数参数分数首先进行了取绝对值运算,从而导致对于输出负分数的时候,无法正确输出。
解决办法:
重新对重载函数进行改写,先判断原参数分数的正负,若为负,则先输出“-”后,再取绝对值,进行分子分母的分别输出操作。
而且原代码中对于分数正负的判断极为繁琐,故直接调用已经重载过的“>”进行判断。
ostream&operator<<(ostream&os,constfraction&f)
{
if(f.decimal()<0)//Thisextremelycomplexandseemingly
os<<"-";//uselessifstatementteststoseeif
//fractionfisnegative.现已修改
fractiontemp=f.absval();
intnumer=f.numerator();
intdenom=f.denominator();
if(temp.numerator()==0||temp.denominator()==1)
os< else os< returnos; } 问题5: 考虑到人性化的操作,实现用户不选择退出,就可以实现持续的操作,故设计了一系列的多级菜单,从而实现用户结束一个操作之后,可以选择继续本操作。 如果不继续操作,则可以选择回到上一个菜单,或者回到主菜单,或者直接退出。 但是为了实现这一系列的选择操作,可是费了一番功夫。 解决办法: (1)首先对于是否继续的选择操作,定义的字符型变量ch,为了防止变量名重复,主菜单对应的每一个操作,在ch后都设置了不同的数字,与主菜单后的每个操作前数字一致。 利用if语句进行判断。 如果,用户选择不继续本次操作,那么就输出另一个选择菜单,选择是返回上一级的菜单还是直接退出程序,并且具备了一定的异常处理功能,如果输入错误的指令,则会显示出来,要求用户重新输入代码,为了大大简化程序,此功能利用goto语句实现。 loop1: if(ch1=='N'||ch1=='n') { cout<<"1.返回主菜单;2,直接退出程序\n"; charch11; cin>>ch11; switch(ch11) { case'1': main(); case'2': exit(0); default: {cout<<"输入指令不正确,请重新输入! \n";gotoloop1;} } } (2)关于实现在函数执行过程中返回主函数,可谓大费周章了,首先通过查资料得知,在main()内部返回主函数开头,可以在语句中直接使用main();语句。 但是,在外部定义的函数中,不能使用该语句,否则将出现errorC2065: 'main': undeclaredidentifier errorC2373: 'main': redefinition;differenttypemodifiers 这两个语法错误,为了解决该问题,想到了使用goto语句,但是该语句无法在函数间跳跃,故而只得作罢。 然后又想到利用返回值进行判断,但是,每次判断是,则要执行被调函数,再一次运行一次混合运算函数,或者是测试函数,显然是不可以的。 最终,查了一些资料,获得启发。 无返回值类型的函数,通过return;语句可以直接跳出该函数。 于是定义了一个全局变量judgement,当遭遇需要返回主菜单时,便将judgement进行赋值为1,随后跳出,对judgement进行判断,从而判断是否返回主菜单,如是,则配合主函数中的main()返回到主函数开头。 (3)在随后要讲到的异常处理部分,当检测到被除数为0的时候,则弹出提示消息,并且可以选择是否重新输入该数字,或者直接返回上一级菜单。 if(f2==0) { cout<<"被除数不能为0! ! \n1.重新输入该数。 2.返回主菜单。 \n"; intk4; cin>>k4; if(k4==1) { cin>>f2; gotoloopsmall1; } else{judgement=1;return;}//由此实现由外部函数直接回到主函数头部 } if(judgement==1)main(); 问题6: 混合运算的核心问题即是优先级的控制; 解决办法: 为了实现运算的优先级,则需要综合判断前后的两个运算符,首先算出优先级较高的运算符两边的数字,再对剩余的那个数字和结果进行运算,算出新的结果。 在输入的同时进行运算。 为了将运算不断向前推进,则定义了3个分数类的对象result,f1,f2.以及两个代表前后运算符的字符型变量op1,op2。 并通过对其不断赋值,如op1=op2,实现运算的推进.具体操作通过switch的嵌套实现。 过程及其繁琐,而且一旦语句出现偏差,极易出现难以发现的运行错误,即最终计算结果不正确。 一下为函数的定义: //==========================================混合运算==================================================================== voidcomplex() { fractionf1,f2,result; charop1,op2; cout<<"ATTENTION: 为保证计算的准确性,若需要输入整数X进行计算,请将该整数以X/1的形式进行输入! ! ! "; cout<<"请依次输入分数(整数)和运算符,并以#结束~\n"; op1=''; cin>>f1>>op2; while(op2! ='#') { judgement=0; cin>>f2; switch(op1) { case'': result=f1;f1=f2;op1=op2;break; case'+': { switch(op2) { case'+': case'-': result=result+f1;f1=f2;op1=op2;break;// case'*': f1=f1*f2;break; loopsmall1: case'/': { if(f2==0) { cout<<"被除数不能为0! ! \n1.重新输入该数。 2.返回主菜单。 \n"; intk4; cin>>k4; if(k4==1) { cin>>f2; gotoloopsmall1; } else{judgement=1;return;}//由此实现由外部函数直接回到主函数头部1111 } f1=f1/f2;break;//op1=op2 } } }break; case'-': { switch(op2) { case'+': case'-': result=result-f1;f1=f2;op1=op2;break;// case'*': f1=f1*f2;break; loopsmall2: case'/': { if(f2==0) { cout<<"被除数不能为0! ! \n1.重新输入该数。 2.返回主菜单。 "; intk4; cin>>k4; if(k4==1) { cin>>f2; gotoloopsmall2; } else{judgement=1;return;}//1111 } f1=f1/f2;break; } } }break; case'*': result=result*f1;f1=f2;op1=op2;break;// case'/': { if(f1==0) {cout<<"倒数第二个数为0,不能作为被除数! ! ! 现在返回主菜单\n"; judgement=1;return;//11111 } result=result/f1; f1=f2;op1=op2;break;// } }//switch(op1)end cin>>op2; } switch(op1) { case'+': cout<<"结果为: "< case'-': cout<<"结果为: "< case'*': cout<<"结果为: "< loopsmall3: case'/': if(f1==0) { cout<<"被除数不能为0! ! \n1.重新输入该数。 2.回到主菜单。 "; intk4; cin>>k4; if(k4==1) { cin>>f1; gotoloopsmall3; } else{judgement=1;return;}//1111 }cout<<"结果为: "< } } //======================================混合运算=========================================================== 问题7: 异常处理,因为涉及四则运算,所以当出现被除数为0的情况,必须进行反应。 解决方案: (1)首先是分数分母赋值为0的情况,这个在分数类的成员函数定义时就设置了反应,结果是直接退出程序。 voidfraction: : setden(intnewden) { if(newden! =0) d=newden; else { cout<<"错误: 试图将分母设为零,不可以啊! ! 将直接退出程序! ! \n" <<"按任意键退出程序\n"; exit(0); } } (2)然后是在运算的计算过程中,当出现被除数为0的情况,会出现提示,并且选择是否重新输入,或者返回上级菜单,重新输入通过goto语句跳转到输入语句实现。 返回上级菜单一是通过goto语句实现,若要返回到主菜单,则需要用到上面返回主函数开头的程序代码。 ,其中特别注意,在混合运算函数中,需要特别设置标识loop的位置,否则经过运算符赋值,会导致计算结果错误。 (3)在随机测试的时候,取随机数的时候可能会在分母上取到0,为此,必须现在代入计算时进行检验,以防在测试过程中出现异常,而导致测试中断。 t1=rand()%10; t2=rand()%10; while(t1==0||t2==0) { t1=rand()%10; t2=rand()%10; } 问题8: 四则运算,菜单选择实现 都通过switch多分支语句实现,特别要注意大括号问题,嵌套一旦复杂,极易出现漏括号的现象。 因此需要注意括号的对齐,格式问题。 心得体会: 1.一个较复杂的,实现各种功能的程序,在设计的时候,可以将其不同的功能先单独书写,先行编译连接运行,调试过程中进行修改,这样比较清楚。 如果放在整个大程序中,时常会不知道问题出在哪里。 2.有时候,编译错误并不可怕,当编译没有错,但是运行结果不对时,找出BUG比较困难,必须重新从算法逻辑的角度考虑问题。 3.编写一个较大型的程序过程中,需要考虑的问题非常多,比如遇到异常输入,输入不符合规则该如何处理等等,细节问题太多了,这时,一个良好的编程习惯非常重要。 就像有时候会因为少括号而出现编译错误,括号加错地方而产生运行错误,但要是能养成括号书写对齐的习惯的话,很多这样的问题是能够避免的。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- c+ 课程设计 分数 计算器