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) 流程控制 缩进 ...
随机推荐
- 安装elasticsearch-head(源码安装方式)
gitHub 地址 https://github.com/mobz/elasticsearch-head 克隆到本地 进行npm 安装运行 git clone git://github.com/mob ...
- 写一个TODO App学习Flutter本地存储工具Moor
写一个TODO App学习Flutter本地存储工具Moor Flutter的数据库存储, 官方文档: https://flutter.dev/docs/cookbook/persistence/sq ...
- Linux 下如何隐藏自己不被发现?
可能在某些情况下,自己运行的程序不想或者不方便被其他人看到,就需要隐藏运行的进程.或者某些攻击者采用了本文介绍的隐藏技术,也可以让大家看到如何进行对抗. 隐藏有两种方法: kernel 层面,不对用户 ...
- python3(二十) module
# 在Python中,一个.py文件就称之为一个模块(Module) # 1.最大的好处是大大提高了代码的可维护性. # 2.可以被其他地方引用 # 3.python内置的模块和来自第三方的模块 # ...
- not found 什么时候触发
eq: BEGIN DECLARE EXIT HANDLER FOR NOT FOUND SET o_state = 999; select count(1) into ...
- sql 自增序列
一.使用set identity_insert [database][owner][table]on设置时,要在插入语句中显示列出插入的列;
- Gitflow分支管理策略
Gitflow存在两个记录项目历史的分支 Master分支:存储(官方的,正式的)项目发布历史记录的分支. develop分支:充当功能的集成分支. Develop分支将包含项目的完整历史记录,而ma ...
- E - Farthest Nodes in a Tree
Given a tree (a connected graph with no cycles), you have to find the farthest nodes in the tree. Th ...
- Docker-None & Host 网络
本节介绍None&Host网络. 1.前言 点击此处回到docker系列文章目录 前面我们介绍了bridge network,本小节继续介绍none和host.这两个比较简单,也不太常用.安装 ...
- 使用GML的八方向自动寻路
使用GML的八方向自动寻路 本教程适合无基础人员使用. 提示 本教程中仅使用了最简单的方法,并且有一些错误和不规范之处.请谅解一下,在评论区提出,我会修改.古人曰"教学相长",希望 ...