20200924-5 四则运算试题生成,结对
此作业的要求参见:https://edu.cnblogs.com/campus/nenu/2020Fall/homework/11245
结对伙伴:宫立秋
github中代码地址:https://github.com/amancer34/calculate.git
一、功能1 四则运算
支持出题4个数的四则运算题目,所有题目要求作者有能力正确回答 (提示:1/3 != 0.33333333333333333333333333333333,而是无限长)。
重点:要随机生成一个四则运算表达式,由作者从控制台输入答案,并判断答案是否与系统给出答案一致。
难点:判断作者输入的答案与系统给出的答案是否相等时,还要考虑结果是负数的情况,我们一开始没有考虑到,导致输入的负号程序接收不到,程序运行结果不对。
编程收获:
1、random.randint(a,b)函数中随机数是可以取到b的。
2、eval()函数可以用来执行一个字符串表达式,并返回表达式的值。
运行截图:
补充截图:
主要代码:
#产生四则运算表达式 def ques(): operators = ['+','-','*','/'] #随机产生运算符 i1 = random.randint(0,3) i2 = random.randint(0,3) i3 = random.randint(0,3) #随机产生四个数 number1 = random.randint(1,10) number2 = random.randint(1,10) number3 = random.randint(1,10) number4 = random.randint(1,10) ques = str(number1) + operators[i1] + str(number2) + operators[i2] + str(number3) + operators[i3] + str(number4) print(ques) return ques #判断输入的数据是否正确 def result(): total = 0 for i in range(20): question = ques() res = eval(question) ans = input("? ") if str(res) == str(ans): print("答对啦,你真是个天才!") total += 1 else: print("再想想吧,答案似乎是%f" %res) print("一共答对" + str(total) + "道题," + "共20道题!") if __name__ == "__main__": #创建对象 parser = argparse.ArgumentParser() #添加参数-c parser.add_argument("-c","--cin") #解析添加的参数 args = parser.parse_args()
if args.cin == None: result()
功能2 支持括号
重点: 随机生成括号,并添加在功能1中生成的四则运算表达式的所有可能位置。
难点:考虑到括号可能在表达式中出现的所有位置,以及左括号出现后与之所匹配的右括号可能出现的位置。
编程收获:
随机生成括号时也要加if判断确保左括号与右括号是相匹配的,如果只靠random函数随机生成,可能导致左右括号不匹配,使得运算结果不正确。
运行截图:
补充截图:
主要代码:
#产生四则运算表达式 def ques(): brackets = ['(','',')'] operators = ['+','-','*','/'] #随机产生运算符 i1 = random.randint(0,2) i2 = random.randint(0,3) i3 = random.randint(0,3) #随机产生四个数 number1 = random.uniform(0,1) number1 = Fraction(number1).limit_denominator(10) number2 = random.uniform(0,1) number2 = Fraction(number2).limit_denominator(10) number3 = random.randint(1,10) number4 = random.randint(1,10) #随机产生左括号 left1 = random.randint(0,1) left2 = random.randint(0,1) left3 = random.randint(0,1) #随机产生右括号 right1 = random.randint(1,2) right2 = random.randint(1,2) right3 = random.randint(1,2) #括号匹配 if left1 == 0: left2 = 1 left3 = 1 if right1 == 2: right2 = 1 right3 = 1 else: right2 = 2 right3 = 1 else: if left2 == 0: left3 = 1 right1 = 1 if right2 == 2: right3 = 1 else: right3 = 2 else: left3 = 0 right1 = 1 right2 = 1 right3 = 2 ques = brackets[left1] + str(number1) + operators[i1] + brackets[left2] + str(number2) ques += brackets[right1] + operators[i2] + brackets[left3] + str(number3) + brackets[right2] ques += operators[i3] + str(number4) + brackets[right3] ques = str(ques) return ques
功能3 限定题目数量,"精美"打印输出,避免重复
重点:由作者输入题目数量,程序生成相应数量的四则运算表达式,并将运算结果与题目对齐输出在屏幕及文件右边。
难点:在控制台输入题目数量时要用到argparse模块,通过其中的add_argument()函数将“-c”这个参数添加到命令行,否则会报错。
编程收获:
1、将表达式加等号后要将其赋给一个新的变量,加上等号后的字符串用eval()函数不能返回正确结果。
2、可以用isdigit()函数判断输入的是否为整数
3、用format()函数可以格式化输出,将运算结果输出在右端。
运行截图:
主要代码:
#命令行输入题目数目 def command_input(num): data = open('data.txt','w+') if num.isdigit(): for i in range(int(num)): question = ques() question1 = question + '=' res = Fraction(eval(question)).limit_denominator(100000) print('{:<50}{:<25}'.format(question1,str(res))) print('{:<50}{:<25}'.format(question1,str(res)),file = data) else: print("题目数量必须是正整数。")
if __name__ == "__main__": #创建对象 parser = argparse.ArgumentParser() #添加参数-c parser.add_argument("-c","--cin") #解析添加的参数 args = parser.parse_args() if args.cin == None: result() else: command_input(args.cin)
功能4 支持分数出题和运算
重点:将运算结果表示为一个分数,并约分。
难点:在得到运算结果后要分成分子、分母两个部分进行保存,同时对其进行输出时,要转换成十进制形式输出,如果直接输出会得到错误的结果。
编程收获:
1、将一个假分数转化为一个带分数的形式时使用“//”可以直接得到整数部分。
2、random.uniform(a,b)随机生成的实数范围是[a,b],random.random()函数的下限才无法取到。
3、Fraction()函数可以将随机生成的小数转化为分数,并对其进行自动约分。
4、limit_denominator(max_denominator)用于返回一个分母不大于max_denominator且最接近原值的分数,避免浮点数和有理数转化失真。
运行截图:
补充截图:
主要代码:
#将分子分母转换为十进制数 def take_decimalism(dicts = {}): j= len(dicts)-1 sum1 = 0 for i in range(0,len(dicts)): if j < 0: break sum1 = int(dicts[j]) * int(math.pow(10,i)) + sum1 j = j-1 return sum1 #遍历结果,将分子、分母存储到两个字典中并约分 def traversal_dist(res): d1={} d2={} count1=0 count2=0 flag=0 sign=0 for i in res: if i=='-': sign=i continue if i=='/': flag=1 continue if flag==0: d1[count1]=i count1=count1+1 else: d2[count2]=i count2=count2+1 #分子 numerator = take_decimalism(d1) #分母 denominator = take_decimalism(d2) if denominator == 0: return numerator else: w1=numerator // denominator w2=numerator % denominator answer=0 if sign=='-': if w1==0: answer=sign+str(w2)+"/"+str(denominator) else: answer=sign+str(w1)+" " +str(numerator)+"/"+str(denominator) else: if w1==0: answer=str(w2)+"/"+str(denominator) else: answer=str(w1)+" " +str(numerator)+"/"+str(denominator) return answer
二、结对编程体会:
1、能更快的解决问题。一个人编程时,如果遇到某些问题,需要反复琢磨,但是结对编程可以互相交流对问题的想法,能更快找到一个解决办法。
2、能更快的通过测试。测试时可能会有一些错误,自己挑错可能会有些费力,让对方给自己挑错,能更快找到出错的地方并修改,从而更快的通过测试。
3、有时编程会感到枯燥,但结对编程会相对减少枯燥感。
当然在编程时有时会因想法不同而产生一些争议,但我认为能更好的提高效率,优点是大于缺点的。
三、至少5项在编码、争论、复审等活动中花费时间较长,收获较大的事件:
1、在功能1中我们因为将用eval()函数返回的结果转化为了int及float导致对于负数的负号接收不到,运行结果不对。
2、在功能2中只随机生成了括号没用if判断做括号的匹配,导致括号不对,生成的表达式也不对,一直出错。
3、在功能3中因在生成的表达式中又添加了“=”,用eval()函数无法得到结果,需要将新的字符串重新赋给一个变量,再将原有的式子用eval()函数得到结果。
4、在功能4中需要将运算结果中的分子、分母分别遍历存储最后再转化为十进制输出。
5、在功能4中分子、分母转化为十进制时从列表或字典中取得第一个数是个位的数,也是最小的数,转化为十进制要乘10的0次方,我们在做的时候将顺序弄反,导致结果不对;输出时还要考虑到有负号和没负号两种情况。
四、结对编程截图: