此作业的要求参见:https://edu.cnblogs.com/campus/nenu/2020Fall/homework/11245
coding代码的地址:https://e.coding.net/xucancan1/sizeyunsuan/sizeyunsuan.git
程序使用说明:在功能1和功能4文件夹中f4.exe实现功能1和功能4,在功能2和功能3文件夹中f4.exe实现功能2和功能3
我的编程结对小伙伴是:史志腾同学
功能1. 四则运算
支持出题4个数的四则运算题目,所有题目要求作者有能力正确回答
> f4 1+2*3+4=
?11
答对啦,你真是个天才!
1+2*3+5=
?11
再想想吧,答案似乎是12喔!
1+2/4-5=
?-3.5
答对啦,你真是个天才!
...(一共20道题) 你一共答对4道题,共20道题。
重难点:
(一)如何随机生成表达式?
对于题意中,有四个操作数,三个操作符,我们要对这7个元素位置进行随机分配生成,我们对于操作数的随机生成开始使用的是 int(random.uniform(a,b)),其中random.uniform(a,b)会随机生成[a,b]范围的小数,所以把它强制转化成整数,其实对于整数的随机生成还可以使用random.randint()函数,至于操作符的随机生成,我们采用的是用列表来包含所有的操作符,通过随机生成列表的下标从而达到随机产生操作符。
关键代码如下:
1 #随机生成表达式 2 def Creat_exp(): 3 op=["+","-","*","/"] 4 num1=int(r.uniform(1,10)) #随机生成1-9的数字 等同于r.randint(1,9) 5 num2=int(r.uniform(1,10)) 6 num3=int(r.uniform(1,10)) 7 num4=int(r.uniform(1,10)) 8 nu1=r.randint(0,3) #randint(0,3)随机产生0,1,2,3 9 nu2=r.randint(0,2) 10 exp=str(num1)+op[nu2]+str(num2)+op[nu1]+str(num3)+op[nu1]+str(num4) 11 return exp
(二)如何将步骤1获得的中缀表达式字符串转化成后缀表达式字符串?
对于这个问题,我们首先定义一个ophead操作符的栈,还要定义一个存储输出的后缀表达式的字符串result,然后通过判断当前元素是否是操作符,如果是操作符,则与ophead操作符的栈顶进行优先级比较,如果小于栈顶优先级,则出栈,否则进栈;如果是操作数,则直接输出保存到后缀表达式的字符串中。
过程示例如下图:
关键代码如下:
1 #将中缀表达式转化成后缀表达式 2 def Reverse(s): 3 ophead=[] #类似于操作符栈 4 result="" #以字符串的形式保存后缀表达式 5 rank={"+":1,"-":1,"*":2,"/":2} #定义字符串的优先级 6 for x in s: 7 if x in ["+","-","*","/"]: #判断当前元素是否是操作符 8 if(len(ophead)==0): #如果栈为空,操作符进栈 9 ophead.append(x) 10 elif(rank[ophead[-1]]>=rank[x]): #如果当前操作符的优先级小于ophead栈顶的元素优先级,则出栈 11 while(len(ophead)>0 and rank[ophead[-1]]>=rank[x]): #出栈,直到栈为空或者当前元素优先级大于栈顶元素 12 op=ophead.pop() 13 result=result+op 14 ophead.append(x) #当前元素的优先级大于栈顶元素的优先级,当前元素进栈 15 else: #如果当前元素的优先级大于ophead栈顶的元素优先级,则操作符进栈 16 ophead.append(x) 17 else: #如果当前元素是操作数 18 result=result+x 19 while(len(ophead)>0):#当ophead栈不为空时,输出栈,直到为空 20 op=ophead.pop() 21 result=result+op 22 return result
(三)计算后缀表达式的字符串
通过步骤二得到的字符串,逐步进行分析;首先我们先定义一个操作数的headlist栈,通过扫描所得的字符串,如果当前元素是操作数,则推进headlist中,否则是操作符,则连续出两次栈,然后对这两个操作数进行运算,运算的结果重新进入到headlist栈中,重复以上操作,直至栈为空
关键代码如下:
1 #计算后缀表达式 2 def Countvalue(s): 3 headlists=[] 4 for i in s: 5 if i in ['+','-','*','/']: 6 b=float(headlists.pop())#栈顶元素出栈 7 a=float(headlists.pop()) #继续栈顶元素出栈 8 c=0 9 if i=='+':#两个操作数做四则运算 10 c=a+b 11 elif i=='-': 12 c=a-b 13 elif i=='*': 14 c=a*b 15 else: 16 c=a/b 17 headlists.append(c)#得到的结果压入栈中 18 else: 19 headlists.append(i) 20 return headlists[0]
(四)如何设计循环20次,如何对答案结果进行表达?
关键代码如下:
1 def main(argv): 2 #功能1或功能2: 3 if(len(argv)==1): 4 num=0 5 n=0 6 #for i in range(20): 7 while(n<20): 8 exp=Creat_exp() 9 print(exp+"=") 10 result_mid=Reverse(exp) 11 result=Countvalue(result_mid) 12 ans=input("?") 13 f=ans 14 if "-" in ans: #如果输入的是负数字字符串,isdigit()函数不能识别 15 f=ans[1:] #转化成正数数字字符串,再进行判断字符串是否是数字字符 16 if "." in ans: #如果输入的是小数数字字符串,isdigit()函数不能识别 17 f=f.replace(".","") #转化成整数数字字符串,再进行判断字符串是否是数字字符 18 if(f.isdigit()): 19 if float(ans) ==result: 20 print("答对了,你真是个天才!") 21 num+=1 22 n+=1 23 else: 24 print("再想想吧,答案似乎是",result,"喔!") 25 n+=1 26 else: 27 print("你输入的结果不是数字,请下一题重新输入数字") 28 print("你一共答对",num,"道题","一共20道题。")
功能1测试结果运行图如下:
功能2 支持括号> f4
1+2*(3+4)=
?15
答对啦,你真是个天才!
(1+2)*3+5=
?11
再想想吧,答案似乎是14喔!
((1/2)-4)*5=
?-17.5
答对啦,你真是个天才!
...(一共20道题)
你一共答对4道题,共20道题。
重难点:
(一)如何随机生成带括号的表达式?
对于带括号的表达式,其中对于有括号的表达式,表达式中可能有一个括号,两个括号,所以我们在草稿纸上全部列出来了,如下图:
比如输入:a + b * c + ( d * e + f ) * g
-
从左到右扫描每一个字符。如果扫描到的字符是操作数(如a、b等),就直接输出这些操作数。
-
如果扫描到的字符是一个操作符,分三种情况:
(1)如果堆栈是空的,直接将操作符存储到堆栈中(push it)
(2)如果该操作符的优先级大于堆栈出口的操作符,就直接将操作符存储到堆栈中(push it)
(3)如果该操作符的优先级低于堆栈出口的操作符,就将堆栈出口的操作符导出(pop it), 直到该操作符的优先级大于堆栈顶端的操作符。将扫描到的操作符导入到堆栈中(push)。
-
如果遇到的操作符是左括号"(”,就直接将该操作符输出到堆栈当中。该操作符只有在遇到右括号“)”的时候移除。这是一个特殊符号该特殊处理。
-
如果扫描到的操作符是右括号“)”,将堆栈中的操作符导出(pop)到output中输出,直到遇见左括号“(”。将堆栈中的左括号移出堆栈(pop )。继续扫描下一个字符
-
如果输入的中缀表达式已经扫描完了,但是堆栈中仍然存在操作符的时候,我们应该讲堆栈中的操作符导出并输入到output 当中。
关键代码如下:
1 #随机生成表达式 2 #对于有括号的表达式,表达式中可能有一个括号,两个括号,所以有括号的随机表达式总共有10种 3 def Creat_exp(): 4 op=["+","-","*","/"] #操作符 5 num1=int(r.uniform(1,10)) #随机生成1-9的数字 等同于r.randint(1,9) 6 num2=int(r.uniform(1,10)) 7 num3=int(r.uniform(1,10)) 8 num4=int(r.uniform(1,10)) 9 nu1=r.randint(0,3) #randint(0,3)随机产生0,1,2,3 10 nu2=r.randint(0,2) 11 #下面是10种随机的有括号表达式 12 exp={1:"("+str(num1)+op[nu2]+str(num2)+")"+op[nu1]+str(num3)+op[nu1]+str(num4), 13 2:"("+str(num1)+op[nu2]+str(num2)+op[nu1]+str(num3)+")"+op[nu1]+str(num4), 14 3:str(num1)+op[nu2]+"("+str(num2)+op[nu2]+str(num3)+")"+op[nu1]+str(num4), 15 4:str(num1)+op[nu2]+"("+str(num2)+op[nu2]+str(num3)+op[nu1]+str(num4)+")", 16 5:str(num1)+op[nu2]+str(num2)+op[nu2]+"("+str(num3)+op[nu1]+str(num4)+")", 17 6:"("+str(num1)+op[nu2]+str(num2)+")"+op[nu1]+"("+str(num3)+op[nu1]+str(num4)+")", 18 7:"("+"("+str(num1)+op[nu2]+str(num2)+")"+op[nu1]+str(num3)+")"+op[nu1]+str(num4), 19 8:"("+str(num1)+op[nu2]+"("+str(num2)+op[nu1]+str(num3)+")"+")"+op[nu1]+str(num4), 20 9:str(num1)+op[nu2]+"("+"("+str(num2)+op[nu2]+str(num3)+")"+op[nu1]+str(num4)+")", 21 10:str(num1)+op[nu2]+"("+str(num2)+op[nu2]+"("+str(num3)+op[nu1]+str(num4)+")"+")", 22 } 23 num5=r.randint(1,10) 24 exp1=exp[num5] 25 return exp1
(二)如何将步骤1获得的中缀表达式字符串转化成后缀表达式字符串?
由于增加了括号,所以转化成后缀表达式的代码与功能1有所不同,我们要考虑左括号和右括号的处理,左括号的优先级最低,右括号的优先级最高,对于当前元素是左括号,就直接进栈,如果是右括号,就直接出栈,直到遇到左括号为止,注意:这时左括号还在栈内,所以应该把它弹出。
关键代码如下:
1 #将中缀表达式转化成后缀表达式 2 def Reverse(s): 3 result="" #以字符串的形式保存后缀表达式 4 ophead=[] #类似于操作符栈 5 rank={"+":1,"-":1,"*":2,"/":2,"(":0,")":3} #定义操作符的优先级 6 for x in s: 7 if x in ["+","-","*","/","(",")"]: #判断当前元素是否是操作符 8 if (x=="("): #如果是左括号,直接进栈 9 ophead.append(x) 10 elif (x==")"): #如果是右括号,则出栈,直到遇到左括号停止 11 while(len(ophead)>0 and ophead[-1]!="("): 12 op=ophead.pop() 13 result=result+op #将出栈的元素保存至后缀表达式字符串中 14 ophead.pop() #把栈中的左括号弹出 15 elif(len(ophead)==0): #如果栈为空,操作符进栈 16 ophead.append(x) 17 elif(rank[ophead[-1]]>=rank[x]): #如果当前操作符的优先级小于ophead栈顶的元素优先级,则出栈 18 while(len(ophead)>0 and rank[ophead[-1]]>=rank[x]): #出栈,直到栈为空或者当前元素优先级大于栈顶元素 19 op=ophead.pop() 20 result=result+op 21 else: #如果当前元素的优先级大于ophead栈顶的元素优先级,则操作符进栈 22 ophead.append(x) 23 else: #如果当前元素是操作数 24 result=result+x 25 while(len(ophead)>0):#当ophead栈不为空时,输出栈,直到为空 26 op=ophead.pop() 27 result=result+op 28 return result
(三)计算后缀表达式的字符串
主要的功能与功能1的大致相同
主要代码如下:
1 #计算后缀表达式 2 def Countvalue(s): 3 headlists=[] 4 for i in s: 5 if i in ['+','-','*','/']: 6 b=float(headlists.pop())#栈顶元素出栈 7 a=float(headlists.pop()) #继续栈顶元素出栈 8 c=0 9 if i=='+':#两个操作数做四则运算 10 c=a+b 11 elif i=='-': 12 c=a-b 13 elif i=='*': 14 c=a*b 15 else: 16 c=a/b 17 headlists.append(c)#得到的结果压入栈中 18 else: 19 headlists.append(i) 20 return headlists[0]
(四) 如何设计循环20次,如何对答案结果进行表达?
这个问题与功能1也是类似,大体的设计一样。不过我加了一些功能,当我们输入的表达式答案不是数字字符时,程序会提醒你重新输入输入数字字符答案
关键代码如下:
1 def main(argv): 2 #功能1或功能2: 3 if(len(argv)==1): 4 num=0 5 n=0 6 #for i in range(20): 7 while(n<20): 8 exp=Creat_exp() 9 print(exp+"=") 10 result_mid=Reverse(exp) 11 result=Countvalue(result_mid) 12 ans=input("?") 13 f=ans 14 if "-" in ans: #如果输入的是负数字字符串,isdigit()函数不能识别 15 f=ans[1:] #转化成正数数字字符串,再进行判断字符串是否是数字字符 16 if "." in ans: #如果输入的是小数数字字符串,isdigit()函数不能识别 17 f=f.replace(".","") #转化成整数数字字符串,再进行判断字符串是否是数字字符 18 if(f.isdigit()): 19 if float(ans) ==result: 20 print("答对了,你真是个天才!") 21 num+=1 22 n+=1 23 else: 24 print("再想想吧,答案似乎是",result,"喔!") 25 n+=1 26 else: 27 print("你输入的结果不是数字,请下一题重新输入数字") 28 print("你一共答对",num,"道题","一共20道题。")
功能2的测试结果运行图如下:
功能3 限定题目数量,"精美"打印输出,避免重复
>f4 -c 3
1+2*(3+4)= 15
(1+2)*3+5= 14
((1/2)-4)*5= 17.5
>f4 -c -200
题目数量必须是 正整数。
>f4 -c 3.5
题目数量必须是 正整数。
>f4 -c test
题目数量必须是 正整数。
重难点:
(一)如何规范输出,避免重复?
对于规范输出这个问题,有两种方法,首先一种是print函数里面的格式,修改其中的输出的格式,如下:
print('%-20s %-20s' % (exp, result))
另一种是用的s.ljust()函数,s.rjust()函数,s.center()函数,在这里我使用的是s.ljust()函数,如下:
print(ex.ljust(30),result) #规范输出,使用了ljust()函数,该函数作用是字符靠左边,右边空多余的空格
至于避免重复的问题,我在功能1中就固定设置了10种表达式,存在着重复的表达式的概率很小,小到忽略不计
(二)如何控制题目个数且循环规范输出?
对于控制题目个数,我通过接收sys.argv[2]来获取想要的题目个数,然后通过这个数进行控制循环
关键代码如下:
1 a=Input(sys.argv[2]) #获取题目个数 2 if(a>=1): 3 num=0 4 n=0 5 #for i in range(20): 6 while(n<a): 7 exp=Creat_exp() 8 ex=exp+"=" 9 result_mid=Reverse(exp) 10 result=Countvalue(result_mid) 11 print(ex.ljust(30),result) #规范输出,使用了ljust()函数,该函数作用是字符靠左边,右边空多余的空格 12 n+=1
(三)如何判断输入的个数符合正整数数字?
这里我直接用了s.isdigit()函数,它的作用是判断该字符串是否全是数字字符;注意:它不能识别负数字符串和小数字符串,史志腾同学发现了这一点特性,刚好又作为我对个数定义条件的判断。
关键代码如下:
1 def Input(s): #判断是否是正整数,isidgit()函数是不能识别小数和负数字符串 2 if(s.isdigit()): 3 return int(s) 4 else: 5 return 0
1 2 #功能3 3 elif(sys.argv[1]=="-c"): 4 a=Input(sys.argv[2]) #获取题目个数 5 if(a>=1): 6 num=0 7 n=0 8 #for i in range(20): 9 while(n<a): 10 exp=Creat_exp() 11 ex=exp+"=" 12 result_mid=Reverse(exp) 13 result=Countvalue(result_mid) 14 print(ex.ljust(30),result) #规范输出,使用了ljust()函数,该函数作用是字符靠左边,右边空多余的空格 15 n+=1 16 17 else: 18 print("题目数量必须是正整数。")
(四)如何与功能2区分?
在主函数中判断‘-c’是否在输入的命令行参数里,在则功能3,否则功能2
关键代码如下:
1 #功能3 2 elif(sys.argv[1]=="-c"): 3 a=Input(sys.argv[2]) #获取题目个数 4 if(a>=1): 5 num=0 6 n=0 7 #for i in range(20): 8 while(n<a): 9 exp=Creat_exp() 10 ex=exp+"=" 11 result_mid=Reverse(exp) 12 result=Countvalue(result_mid) 13 print(ex.ljust(30),result) #规范输出,使用了ljust()函数,该函数作用是字符靠左边,右边空多余的空格 14 n+=1 15 16 else: 17 print("题目数量必须是正整数。") 18
功能3测试结果运行图如下:
功能4. 支持分数出题和运算
国庆节后,你终于又回到美丽优雅并且正常的东北师范大学净月校区,在去食堂的路上偶遇你心目中的女神 (或男神,请自行替换)。她说,"哎呀,这跟我们《构建之法》课上的题目要求一样啊,真是巧合。"
"不要客气,代码拿去!反正我也没用。"你说,"如果有需求变更或扩展,尽管找我。"
你伏笔埋得不错。女神马上说,"对啊,有一点儿点儿不一样,你午饭时间加加班帮我改出来吧。"
她的题目还要求支持分数运算,你不禁想到了功能1中你特意规避了一些题目不出。她想要的是下面的样子:
>f4 -c 3
1/3+2/3+1+1= 3
1/2+2/3+1+2= 4 1/6
7/5+3/4*2-3 -1/10
你想到越难的题目就越能表现你的能力,欣然应允了,转身跑向实验室,路上就开始给师兄打电话。背后传来女神的声音,"提示1:别忘了约分。提示2:带分数,即 一又二分之一 表示 1 1/2。"
完成这个功能,女神对你的青睐+200。
重难点:
(一)如何对分数表达式进行运算?
对于这个问题,困扰了我很久,我想要用后缀表达式计算的规则对分子分母逐个进行运算,但是由于本人python水平有限,花了4-5个小时还没搞定,然后我就放弃了,最后我解决这个难题使用了fractions模块和eval()函数,fractions模块中有一个Fraction()函数,它是专门用来表示分数和处理分数的问题的,而eval()函数的作用 是将字符串str当成有效的表达式来求值并返回计算结果。
关键代码如下:
1 def count(s): 2 result=f(eval(s)).limit_denominator(1000) #利用eval函数计算字符串表达式的值,并且分子分母均小于1000 3 4 return str(result) 5
fraction函数的详细用法参考链接:https://blog.csdn.net/u012949658/article/details/105837120
eval函数的详细用法参考链接:https://www.jianshu.com/p/b2d3a77f76f8
(二)如何设计有分数且带有括号的表达式?
对于有括号的表达式,表达式中可能有一个括号,两个括号,有分数或没有分数,所以我总共列出有括号且有分数的随机表达式有32种,其实还有很多,这里我省略了
关键代码如下:
1 def Creat_exp2(): 2 op=["+","-","*","/"] #操作符 3 num1=int(r.uniform(1,10)) #随机生成1-9的数字 等同于r.randint(1,9) 4 num2=int(r.uniform(1,10)) 5 num3=int(r.uniform(1,10)) 6 num4=int(r.uniform(1,10)) 7 nu1=ri(0,3) #randint(0,3)随机产生0,1,2,3 8 nu2=ri(0,2) 9 #下面是32种随机的有括号且有分数的表达式 10 exp={1:"("+str(num1)+op[nu2]+str(num2)+")"+op[nu1]+str(num3)+op[nu1]+str(num4), 11 2:"("+str(num1)+op[nu2]+str(num2)+op[nu1]+str(num3)+")"+op[nu1]+str(num4), 12 3:str(num1)+op[nu2]+"("+str(num2)+op[nu2]+str(num3)+")"+op[nu1]+str(num4), 13 4:str(num1)+op[nu2]+"("+str(num2)+op[nu2]+str(num3)+op[nu1]+str(num4)+")", 14 5:str(num1)+op[nu2]+str(num2)+op[nu2]+"("+str(num3)+op[nu1]+str(num4)+")", 15 6:"("+str(num1)+op[nu2]+str(num2)+")"+op[nu1]+"("+str(num3)+op[nu1]+str(num4)+")", 16 7:"("+"("+str(num1)+op[nu2]+str(num2)+")"+op[nu1]+str(num3)+")"+op[nu1]+str(num4), 17 8:"("+str(num1)+op[nu2]+"("+str(num2)+op[nu1]+str(num3)+")"+")"+op[nu1]+str(num4), 18 9:str(num1)+op[nu2]+"("+"("+str(num2)+op[nu2]+str(num3)+")"+op[nu1]+str(num4)+")", 19 10:str(num1)+op[nu2]+"("+str(num2)+op[nu2]+"("+str(num3)+op[nu1]+str(num4)+")"+")", 20 11:"("+str(f(ri(1,10),ri(1,10)))+op[nu2]+str(num2)+")"+op[nu1]+str(num3)+op[nu1]+str(num4), 21 12:"("+str(num1)+op[nu2]+str(f(ri(1,10),ri(1,10)))+")"+op[nu1]+str(num3)+op[nu1]+str(num4), 22 13:"("+str(num1)+op[nu2]+str(num2)+")"+op[nu1]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(num4), 23 14:"("+str(num1)+op[nu2]+str(num2)+")"+op[nu1]+str(num3)+op[nu1]+str(f(ri(1,10),ri(1,10))), 24 15:"("+str(f(ri(1,10),ri(1,10)))+op[nu2]+str(num2)+op[nu1]+str(num3)+")"+op[nu1]+str(num4), 25 16:"("+str(num1)+op[nu2]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(num3)+")"+op[nu1]+str(num4), 26 17:"("+str(num1)+op[nu2]+str(num2)+op[nu1]+str(f(ri(1,10),ri(1,10)))+")"+op[nu1]+str(num4), 27 18:"("+str(num1)+op[nu2]+str(num2)+op[nu1]+str(num3)+")"+op[nu1]+str(f(ri(1,10),ri(1,10))), 28 19:"("+str(f(ri(1,10),ri(1,10)))+op[nu2]+str(f(ri(1,10),ri(1,10)))+")"+op[nu1]+str(num3)+op[nu1]+str(num4), 29 20:"("+str(num1)+op[nu2]+str(f(ri(1,10),ri(1,10)))+")"+op[nu1]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(num4), 30 21:str(f(ri(1,10),ri(1,10)))+op[nu2]+"("+str(f(ri(1,10),ri(1,10)))+op[nu2]+str(num3)+")"+op[nu1]+str(num4), 31 22:str(num1)+op[nu2]+"("+str(num2)+op[nu2]+str(f(ri(1,10),ri(1,10)))+")"+op[nu1]+str(f(ri(1,10),ri(1,10))), 32 23:str(f(ri(1,10),ri(1,10)))+op[nu2]+"("+str(f(ri(1,10),ri(1,10)))+op[nu2]+str(num3)+op[nu1]+str(num4)+")", 33 24:str(num1)+op[nu2]+"("+str(num2)+op[nu2]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(f(ri(1,10),ri(1,10)))+")", 34 25:str(f(ri(1,10),ri(1,10)))+op[nu2]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(f(ri(1,10),ri(1,10))), 35 26:str(num1)+op[nu2]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(f(ri(1,10),ri(1,10))), 36 27:str(f(ri(1,10),ri(1,10)))+op[nu2]+str(num1)+op[nu1]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(f(ri(1,10),ri(1,10))), 37 28:str(f(ri(1,10),ri(1,10)))+op[nu2]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(num1)+op[nu1]+str(f(ri(1,10),ri(1,10))), 38 29:str(f(ri(1,10),ri(1,10)))+op[nu2]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(num1), 39 30:str(num1)+op[nu2]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(num1), 40 31:str(num1)+op[nu2]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(num1)+op[nu1]+str(num1), 41 32:str(num1)+op[nu2]+str(f(ri(1,10),ri(1,10)))+op[nu1]+str(num1)+op[nu1]+str(f(ri(1,10),ri(1,10))), 42 } 43 num5=ri(1,32) 44 exp1=exp[num5] 45 return exp1
(三)如何将大于1的分数转化成带分数,以带分数的形式输出?
对于这个问题,我们开始的思路是以为可以通过分子分母相除解决,后来我换了个思路,为啥要执着用结果的形式来表达分数或带分数呢?我们直接从print()函数下手,通过改变输出的格式来表达分数或者带分数。所以我们的思路一下子明朗了。
关键代码如下:
1 while(n<a): 2 exp=Creat_exp2() 3 ex=exp+"=" 4 result=count(exp) 5 if "/" in result: #处理分数部分 6 t,v=map(int,result.split("/")) #t为分子,v为分母 7 if(t>0 and t>v): #简化成正带分数 8 c=t//v #整除 9 d=t%v 10 e=v 11 print(ex.ljust(30),"%d %d/%d" %(c,d,e)) #输出带分数形式 12 elif(-t>v): #简化成负带分数 13 # print(t,v) 14 c=t/v 15 d=-t%v 16 e=v 17 print(ex.ljust(30),"%d %d/%d" %(c,d,e)) #输出带分数形式
(四)如何处理负大于1的分数,如何使用负带分数表达负分数?
这里是我们编程的时候遇到的一个坑,在处理分数部分时,由于负大于1的分数在判断的时候,分子是负数,所以它永远小于分母正数,哪怕是-100000,也比1小,所以我们需要把判断一下分子是否是小于0;如果小于0,则将它变成正数,然后分别进行分子,分母运算,最后通过修改print的输出格式形成带分数。
关键代码如下:
1 result=count(exp) 2 if "/" in result: #处理分数部分 3 t,v=map(int,result.split("/")) #t为分子,v为分母 4 if(t>0 and t>v): #简化成正带分数 5 c=t//v #整除 6 d=t%v 7 e=v 8 print(ex.ljust(30),"%d %d/%d" %(c,d,e)) #输出带分数形式 9 elif(-t>v): #简化成负带分数 10 # print(t,v) 11 c=t/v 12 d=-t%v 13 e=v 14 print(ex.ljust(30),"%d %d/%d" %(c,d,e)) #输出带分数形式 15 else: 16 print(ex.ljust(30),result) #规范输出,使用了ljust()函数,该函数作用是字符靠左边,右边空多余的空格 17 18 else: 19 print(ex.ljust(30),result) #规范输出,使用了ljust()函数,该函数作用是字符靠左边,右边空多余的空格 20
功能4测试结果运行图如下:
花费讨论解决问题时间较长的事件:
①在功能1生成表达式和中缀表达式转化成后缀表达式时,我们一直卡在这里,调试运行出来的后缀表达式总是错误的,我们经过手工一步一步的模拟最终找出了问题。
②在功能2中带括号的表达式中,我们讨论如何处理左括号和右括号,怎样合理分配设计优先级
③计算括号表达式的形式有多少种的时候,我们在草稿纸把所有情况都列出来,然后排除重复的情况,得出来了10种
④在处理带分数的时候,我们花了很长时间研究如何让结果显示出带分数形式,后来史志腾同学提醒我换个思路,然后我从print函数格式下手,解决了问题
⑤在功能4中将带分数输入到文件中并且同一排显示,我们讨论了很久,最后用了.join()函数解决了这个问题,我们都感叹python真的很nice!
总结:
通过这次作业,让我学习了python中很多内置模块和函数,比如fraction模块,eval()函数,ljust(),rjust(),center()函数等,这些都是在这次作业中,我所遇到的一个又一个令我困扰的难点,也是这些难点让我对python进一步的 认识。在此我特别感谢我的结对小伙伴史志腾同学,能在我遇到难题毫无思路的时候,给我启发,在我烦躁的时候,陪我一起学习,一起努力。