• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
笼中鸟
stay hungry stay foolish
博客园    首页    新随笔    联系   管理    订阅  订阅
20200924-5 四则运算试题生成,结对

此作业的要求参见: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
  1. 从左到右扫描每一个字符。如果扫描到的字符是操作数(如a、b等),就直接输出这些操作数。

    c++堆栈的应用:中缀表达式转化为后缀表达式

  2. 如果扫描到的字符是一个操作符,分三种情况:

    (1)如果堆栈是空的,直接将操作符存储到堆栈中(push it)

    (2)如果该操作符的优先级大于堆栈出口的操作符,就直接将操作符存储到堆栈中(push it)

    (3)如果该操作符的优先级低于堆栈出口的操作符,就将堆栈出口的操作符导出(pop it), 直到该操作符的优先级大于堆栈顶端的操作符。将扫描到的操作符导入到堆栈中(push)。

    c++堆栈的应用:中缀表达式转化为后缀表达式

    c++堆栈的应用:中缀表达式转化为后缀表达式

  3. 如果遇到的操作符是左括号"(”,就直接将该操作符输出到堆栈当中。该操作符只有在遇到右括号“)”的时候移除。这是一个特殊符号该特殊处理。

    c++堆栈的应用:中缀表达式转化为后缀表达式

    c++堆栈的应用:中缀表达式转化为后缀表达式

    c++堆栈的应用:中缀表达式转化为后缀表达式

  4. 如果扫描到的操作符是右括号“)”,将堆栈中的操作符导出(pop)到output中输出,直到遇见左括号“(”。将堆栈中的左括号移出堆栈(pop )。继续扫描下一个字符

    c++堆栈的应用:中缀表达式转化为后缀表达式

  5. 如果输入的中缀表达式已经扫描完了,但是堆栈中仍然存在操作符的时候,我们应该讲堆栈中的操作符导出并输入到output 当中。

    c++堆栈的应用:中缀表达式转化为后缀表达式

    c++堆栈的应用:中缀表达式转化为后缀表达式


关键代码如下:
 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进一步的 认识。在此我特别感谢我的结对小伙伴史志腾同学,能在我遇到难题毫无思路的时候,给我启发,在我烦躁的时候,陪我一起学习,一起努力。

    


  

 

  




 

 



 

posted on 2020-10-05 00:46  xucancan  阅读(238)  评论(5)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3