Python-四则运算-蔡晓晴,杜婷萱
github链接:https://github.com/Amy-CC/Arithmetic-Operation
一、需求
1.使用-n 参数控制生成题目的个数
2.使用-r 参数控制题目中数值(自然数、真分数和真分数分母)的范围
3.生成的题目中计算过程不能产生负数
4. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。
5. 每道题目中出现的运算符个数不超过3个。
6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。
7.生成的题目存入执行程序的当前目录下的Exercises.txt文件
8.在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件
9. 程序应能支持一万道题目的生成。
10. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:
Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt
统计结果输出到文件Grade.txt,格式如下:
Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
二、PSP2.1表格
PSP:
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 20 | 30 |
Development | 开发 | 1230 | 1665 |
· Analysis | · 需求分析 (包括学习新技术) | 120 | 300 |
· Design Spec | · 生成设计文档 | 60 | 60 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 50 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 5 |
· Design | · 具体设计 | 30 | 40 |
· Coding | · 具体编码 | 900 | 1100 |
· Code Review | · 代码复审 | 40 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 40 | 80 |
Reporting | 报告 | 50 | 70 |
· Test Report | · 测试报告 | 10 | 10 |
· Size Measurement | · 计算工作量 | 10 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 40 |
合计 | 1300 | 1765 |
三、设计实现过程:
1.功能1~9的实现步骤
· 一开始题目运行采用递归的方法,后来调用的函数过多,递归函数太复杂,于是改成for生成题目
· 查重用了字典的方法
· 随机括号的生成费时良久,考虑到随机的各种情况,左括号和右括号的定位问题,存储结构等等问题。
· 在寻找计算的简便方法的时候,我们找到一个函数eval(string)可以直接识别并计算一整条string。
· 减号的判断,由于计算的方法不是根据括号从内到外计算的,要一个个计算却会使得函数过于复杂,向同学取经后,我们还是采用了负数舍去的方法。
2.功能10的实现过程:
· 用正则表达式检查输入的文本格式是否正确
· 根据空格split分别存储真分数等各个数值
· 调用两个函数进行,分数与真分数互相转换
效能分析:
CPU运行时间:
10000道题的生成时间:
100道题的时间:
功能10:
可以看出来到了大量题目的时候,由于查重,时间复杂度成指数级上升。
代码说明:
功能1~9:
1. #随机生成一道题目中的符号和数字
- def random_list(self):
- char_list = ["+", "-", u"×", u"÷"]
- num_list = []
- char_choice = []
- cc = ""
- loop_times = random.randint(2,4)
- for i in range(loop_times):
- static = random.randint(1, self.num_range)
- if self.num_range > 1:
- float_n = produce_random.choose_num(self)
- choice = random.choice([static, float_n])
- else:
- choice = static
- cc += str(choice)
- num_list.append(choice)
- if i < (loop_times - 1):
- cha = random.choice(char_list)
- char_choice.append(cha)
- cc += cha
- jo = str(num_list+char_choice)
- if jo in dic_t.keys():
- self.random_list()
- else:
- dic_t[jo] = 0
- return char_choice, num_list
2. #随机生成分数
- def choose_num(self):
- while(1):
- a = random.randint(1, self.num_range**2)
- b = random.randint(2, self.num_range)
- if Decimal(a/b) < self.num_range:
- return Fraction(a, b)
3. #根据符号随机加括号
- def plus_(self,char_choice, num_list):
- numble = len(num_list) + len(char_choice)
- ccc = [""] * numble
- if len(char_choice) == 1:
- pass
- else:
- """括号对数"""
- n_kuo = random.randint(0, len(char_choice) - 1)
- if n_kuo != 0:
- p_kuo_l = []
- """设置list1初值"""
- list1 = []
- for i in range(0, len(char_choice)):
- z = 2 * i
- """改为append"""
- list1.append(z)
- p_kuo_l = random.sample(list1, 1) # 按照char的数量来存,2个就是[0,2],3个[0,2,4]
- ccc.insert(p_kuo_l[0], '(') # 插入1st左边的括号
- if len(char_choice) == 2:
- ccc.insert(p_kuo_l[i-1] + 4, ')')
- if len(char_choice) == 3:
- """第一个右括号"""
- if p_kuo_l[0] == 0:
- list1 = [4]
- if p_kuo_l[0] == 2:
- list1 = [p_kuo_l[0] + int(random.sample([4, 6], 1)[0])]
- if p_kuo_l[0] == 4:
- list1 = [8]
- p_kuo_r = list1[:]
- ccc.insert(p_kuo_r[0], ')')
- x = p_kuo_l + p_kuo_r
- if n_kuo == 2: # 加第二个右括号
- if x[0] == 2:
- if x[1]==x[0]+4:
- y = random.sample([0, x[0]], 1)
- ccc.insert(y[0], '(')
- if y[0] == 0:
- ccc.insert(x[1]+1, ')')
- else:
- ccc.insert(x[0] + 8, ')')
- else:
- y = random.sample([x[0], x[0] + 3], 1)
- ccc.insert(y[0], '(')
- if y[0] == 2:
- ccc.insert(x[0] + 5, ')')
- else:
- ccc.insert(x[0] + 7, ')')
- if x[0] == 0:
- y = x[0]
- ccc.insert(y, '(')
- ccc.insert(x[0] + 8, ')')
- if x[0] == 4:
- y = x[0]-2
- ccc.insert(y, '(')
- ccc.insert(x[0]+7, ')')
- num = 0
- cha = 0
- list_all = [] # 装数字+字符
- j = 0
- flag = True
- #标记乘号的个数
- multi_n = []
- #标记除号的个数
- divide_n = []
- for i in range(0, len(num_list)):
- if j == (len(num_list) - 1):
- j -= 1
- flag = False
- list_all.append(num_list[i])
- if i == j and flag == True:
- list_all.append(char_choice[j])
- j += 1
- j = 0
- for i in range(0, len(ccc)):
- if ccc[i] != '':
- continue
- if list_all[j]=='×':
- multi_n.append(i)
- if list_all[j]=='÷':
- divide_n.append(i)
- ccc[i] = list_all[j]
- j += 1
- return ccc, multi_n, divide_n
4. #符号转换,把list改为str来计算,分数周围有自己的括号(计算的时候将分数看成除法来计算)
- def join_c(self, ccc, multi_n, divide_n):
- list1 = ccc[:]
- ll = []
- for i in multi_n:
- list1[i]= '*'
- for j in divide_n:
- list1[j] = '/'
- for i in list1:
- if type(i) == Fraction:
- if i.denominator == 1:
- ll.append(str(i))
- else:
- ll.append('('+str(i)+')')
- elif type(i) == int:
- ll.append(str(i))
- else:
- ll.append(i)
- final = ''.join(ll)
- return final
5. #计算
- def calculate(final):
- result = eval(final)
- return result
- 6. #查找小数循环,小数转分数
- def ff_c(self, demical): # 参数为小数
- for i in range(1, 16):
- cpart = demical[:i]
- if len(cpart) < 4:
- if (cpart * i * 4) == demical[:4 * i]: # 4次重复
- return cpart # 循环体
- return 0 # 找不到循环体,返回0
- #小数转分数
- def demical_to_fraction(self, digi, back_num=0):
- digi = str(digi)
- if len(digi) <= 15: # 有限小数
- return Fraction(digi)
- real_num, dot_area = digi.split('.')
- float_num = float(digi)
- for i in range(len(digi)):
- cycle_start = dot_area[i:]
- result = self.ff_c(cycle_start)
- length = len(str(result)) # 循环体的长度
- if result: # 存在循环体
- if i != 0: # 不是小数点后第一位
- new_number = float_num * (10 ** i) # 移位数
- self.demical_to_fraction(new_number, i) # 递归
- break
- else: # 小数点后的第一位
- fraction = Fraction(int(result), int('9' * length)) # 小数转分数
- final_num = int(real_num) + fraction
- return final_num / (10 ** back_num) # 回退移的位数
- return False
7. #最后转为真分数输出
- def change_l(self,li):
- hh = []
- for i in li:
- if type(i) == Fraction:
- hh.append(change_ff(i))
- hh.append(' ')
- continue
- else:
- hh.append(str(i))
- hh.append(' ')
- return hh
8. # 写入文件
- def write(self, f_line):
- self.glocount += 1
- count = int((self.glocount + 1) / 2)
- tihao = str(count) + '. '
- file = open('Exercise.txt', 'a')
- f_line = tihao + f_line + ' ='
- file.write(f_line + '\n')
- file.close()
- def write_a(self, f_line):
- self.glocount += 1
- tihao = str(int(self.glocount / 2)) + '. '
- file = open('Answers.txt', 'a')
- f_line = tihao + f_line
- file.write(f_line + '\n')
- file.close()
功能10:
1. # 支持读取给定的文件
- def read_f(name):
- with open(name) as Re:
- file = Re.readlines()
- return file
2. #检查文件名是否符合格式
- def check_file(file_name):
- if re.match(r"[a-zA-Z0-9]*\..", file_name):
- return True
- print("The file name is not right.")
- return False
3. #转换分数AND真分数
- def change_re_fra(expre):
- if re.search("[1-9]\'[1-9]/[1-9]", expre):
- l1 = expre.split("\'")
- l2 = l1[1].split("/")
- num_1 = eval(l1[0])
- num_2 = eval(l2[0])
- num_3 = eval(l2[1])
- middle_p = num_3*num_1
- num_2 += middle_p
- return str(Fraction(num_2,num_3))
- if expre == '×':
- expre = '*'
- if expre == '÷':
- expre = '/'
- return expre
- def change_ff(fra):
- d = fra.denominator
- n = fra.numerator
- midde = n // d
- if midde == 0:
- return str(n)
- cha = n - d * midde
- if cha == 0:
- return str(midde)
- return str(midde)+'\''+str(Fraction(cha,d))
4. #比对提交的和user答案一致性
- def bidui(ans,user):
- corr,wrong = [],[]
- a_line = read_f(ans)
- user_line = read_f(user)
- for i in range(0,len(a_line)):
- if a_line[i] == user_line[i]:
- corr.append(str(i))
- corr.append(',')
- else:
- wrong.append(str(i))
- wrong.append(',')
- u1 = ''.join(corr)
- u2 = ''.join(wrong)
- co = 'Correct:'+str(len(corr)//2)+'('+u1+')'
- w = 'Wrong:'+str(len(wrong)//2)+'('+u2+')'
- write_Grade(co,w,'Grade.txt')
- def compare(file_list):
- file = read_f(file_list[0])
- gloc = 0
- for i in file:
- i = i.rstrip()
- lii = i.split('.')
- c = lii[1].split(' ')
- strr = ''
- for j in c:
- if j != '=':
- str = change_re_fra(j)
- strr += str
- result = calculate(strr)
- f_result = demical_to_fraction(result)
- ff_result = change_ff(f_result)
- write1(ff_result, 'answer2.txt',gloc)
- gloc += 1
- bidui('answer2.txt',file_list[1])
5. #写入文件
- def write1(result, name,glocount):
- glocount += 1
- count = glocount
- tihao = str(count) + '. '
- file = open(name, 'a')
- f_line = tihao + result
- file.write(f_line + '\n')
- file.close()
- def write_Grade(c,w,name):
- file = open(name, 'a')
- file.write(c+'\n'+w)
- file.close()
main函数:
- if __name__ == '__main__':
- file = open('Exercise.txt', 'r+')
- file.truncate()
- file.close()
- file = open('Answers.txt', 'r+')
- file.truncate()
- file.close()
- sys.setrecursionlimit(10000)
- dic_t = {}
- if len(sys.argv)>2:
- num_range, ti_num = menu()
- if num_range > 0 and ti_num > 0:
- instance = produce_random(num_range, ti_num)
- instance.running()
- else:
- print("输入命令不足")
- def menu():
- flag = 0
- compare_arg = 0
- file_rrlist = []
- for i in range(len(sys.argv)):
- if sys.argv[i]=='-e':
- if check_file(sys.argv[i+1]):
- file_rrlist.append(sys.argv[i+1])
- compare_arg += 1
- continue
- elif sys.argv[i]=='-a':
- if check_file(sys.argv[i+1]) and compare_arg==1:
- file_rrlist.append(sys.argv[i+1])
- compare(file_rrlist)
- flag = -1
- elif sys.argv[i]=='-n' and compare_arg==0:
- ti_num = input("请输入题目数量:")
- ti_num = int(ti_num)
- if ti_num<=0:
- print("数量过少,请重试")
- break
- flag += 1
- elif sys.argv[i]=='-r' and compare_arg==0:
- num_range = input("请输入数值范围:")
- num_range = int(num_range)
- if num_range<=1:
- print("数值范围不存在")
- continue
- else:
- break
- flag +=1
- if flag == 1:
- return num_range, ti_num
- elif flag==-1:
- return -1,-1
- else:
- print("输入不正确")
- return 0, 0
- def running(self):
- #利用for循环输出多道题
- for i in range(self.num):
- while True:
- char_choice, num_list = self.random_list()
- k, multi_n, divide_n = self.plus_(char_choice, num_list)
- new_title = self.join_c(k, multi_n, divide_n)
- z = calculate(new_title)
- if z < 0:
- continue
- final_result = demical_to_fraction(z)
- if type(final_result) == float or final_result==False:
- continue
- if final_result.denominator > self.num_range:
- continue
- else:
- break
- nn_tt = self.change_l(k)
- final_result = change_ff(final_result)
- nn_tt = ''.join(nn_tt)
- print(nn_tt)
- self.write(nn_tt)
- self.write_a(str(final_result))
测试结果分析:
生成题目:
10000道题,范围为1000:
测试文件查错:
总结:
我们采取的分工合作是蔡同学先负责写随机数、menu等等,杜同学写加括号、功能10的实现,之后由于加括号出现了很多bug,两人都在这个函数上掉了大把的头发,前期代码在后期测试时很多地方的需要上有较多的调整,对于有些功能比如查重用了比较暴力的删除法,增加了不少运行时间。
——蔡晓晴:我觉得这次结对编程还是获益良多的,例如我们开始没找到合适的方法来沟通、设计,到后面逐步完善我们的设计方案,修改bug。我觉得这其中彼此的思想碰撞有很大的作用,也谢谢同伴的帮助!(^-^)V
——杜婷萱: 一开始我们采取两个人一边写一边看的形式让我略感压力的同时,双人互挑bug的讨论比一个人的思路更广阔,纸上谈兵也能发现很多的问题,我学习到思路理清楚很重要,如果仅仅只是有个想法而不做深入思考就写代码就会写的很乱,不仅浪费时间,还会难以让同伴理解。而且双方的沟通很重要,两人最好尽量同步,现实代码总比理想的冗余了许多,结对其实更考验写代码的速度和质量。作为一个messy coder蔡同学帮助了我非常多,感谢ヽ( ̄▽ ̄)و
转载于:https://www.cnblogs.com/dududu7/p/9721651.html
Python-四则运算-蔡晓晴,杜婷萱的更多相关文章
- python四则运算2.0
github项目地址: https://github.com/kongkalong/python PSP 预估耗时(分钟) Planning .Estimate 48*60 Development . ...
- python四则运算
源代码已上传至Github,https://github.com/chaigee/arithmetic,中的python_ari.py文件 题目: (1)能自动生成小学四则运算题目,并且不能出现负数: ...
- 团队合作项目—(GG队)
团队展示 一.队名:GG 二.队员信息 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 311600 ...
- 团队项目第六周——事后诸葛亮分析(GG队)
一.总结: 本次项目作为我们第一次团队集体开发的项目,使我们在项目开发以及团队合作方面都有了宝贵的 经验以及初步的认识: 从项目开发的方面来看: 通过本次项目,我们更进一步加强了自己的前端知识,并初步 ...
- 团队项目(第四周冲刺之二)—GG队
项目冲刺: 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 3116004661 (先把帅气的合照不 ...
- 团队项目(第四周之一)—GG队
Alpha认领任务: 叶尚文:对应键盘监听结果的动画以及计算 于泽浩:制作背景gif图,并保证能在程序中循环播放 龙剑初:项目进度跟进及博客更新 杜婷萱:把图片结合起来,设置云朵透明度的变化 蔡晓晴: ...
- 团队项目(第三周)—GG队
需求改进&系统设计 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 3116004661 一 ...
- 团队项目(第二周)—GG队
项目需求规格分析 队员信息 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 3116004661 项 ...
- [Day01] Python基础
明天要完成的任务如下: Python 四则运算 Python 数据结构 Python 元算符(in.not in.is.and.or) 用户输入 (input.raw_input) 流程控制 缩进 ...
随机推荐
- 从一个慢查询到MySQL字符集编码
从一个慢查询到MySQL字符集编码 目录 从一个慢查询到MySQL字符集编码 1. 问题起源 2. MySQL字符集和字符集排序规则 2.1 字符集相关概念 2.2 MySQL中的字符集和字符集排序规 ...
- 微信小程序之界面交互反馈
交互反馈就是在用户出发某事件之后,给用户一个反馈信息,这要是一个很友好的习惯. 在小程序中是通过一下几种方式实现的: 1.wx.showToast()方法 showToast: function (p ...
- 记一次mysql多表查询(left jion)优化案例
一次mysql多表查询(left jion)优化案例 在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时, ...
- kali2016&2019的安装使用
先解释一下,为什么要说2016&2019哪,这是因为有一些测试靶机环境在2016以上的系统安装不通过,所以有时候会特意找2016的镜像来用. 一.下载镜像 1.下载镜像当然要到官方去下载了: ...
- 基于 Spring Cloud 的微服务架构实践指南(下)
show me the code and talk to me,做的出来更要说的明白 本文源码,请点击learnSpringCloud 我是布尔bl,你的支持是我分享的动力! 一.引入 上回 基于 S ...
- flask from_object和from_pyfile的区别
flask from_object和from_pyfile的区别 from_object接受的是一个模块对象,需求导入 from_pyfile接受的是一个文件名的字符串,文件可以不是py文件也可以是 ...
- ubuntu18.04配置宽带上网
1.将 /etc/NetworkManager 目录下的 managed标签改为true 2.将 /etc/network/ 目录下的 interfaces文件只留下前两行: auto lo ifac ...
- C++ memset函数用法
#include<stdio.h>#include<string.h>int main(){ char buffer[] = "I love you!"; ...
- html字体大小与颜色设置
代码架构:<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> //浏览器识 ...
- C - Sweets Eating
规律题 前缀和+规律 先求前缀和...答案为c[i]=arr[i]+c[i-m]//i>m时. #include<bits/stdc++.h> using namespace std ...