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) 流程控制 缩进 ...
随机推荐
- Appium自动化(1) - 环境准备详细教程
Appium需要用到的工具 链接:https://pan.baidu.com/s/1od9x-1l0ALGRT5T6QFDHWg 提取码:bnhq 安装Appium Pyhton client包 1. ...
- 【原创】Linux RCU原理剖析(一)-初窥门径
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- Spring 中使用 WebSocket 笔记
编写 WebSocket 消息处理类,比较简单的方式就是直接继承AbstractWebSocketHandler,并覆写其中的处理方法,下面为一个简单的 demo public class WebSo ...
- urllib笔记
在Python 3中,urllib2被合并到了urllib中,叫做urllib.request 和 urllib.error .urllib整个模块分为urllib.request, urllib.p ...
- 搭建DVWA Web渗透测试靶场
文章更新于:2020-04-13 按照惯例,需要的文件附上链接放在文首. 文件名:DVWA-1.9-2020.zip 文件大小:1.3 M 文件说明:这个是新版 v1.9 (其实是 v1.10开发版) ...
- JAVA自动化之Junit单元测试框架详解
一.JUnit概述&配置 1.Junit是什么? Junit是一个Java 编程语言的开源测试框架,用于编写和运行测试.官网 地址:https://junit.org/junit4/ 2.Ma ...
- (js描述的)数据结构[链表](4)
(js描述的)数据结构 [链表](4) 一.基本结构 二.想比于数组,链表的一些优点 1.内存空间不是必须连续的,可以充分利用计算机的内存,事项灵活的内存动态管理. 2.链表不必再创建时就确定大小,并 ...
- python socket简介
一.socket是什么 socket是应用层与TCP/IP协议通信的中间软件抽象层,它是一组接口.在设计模式中,socket其实就是一个门面模式,它把复杂的TCP/IP协议隐藏在socket接口后面, ...
- 使用docker-compose编写常规的lnmp容器,pdo连接mysql失败。
问题的核心是yii2 是通过pdo的方式去连接数据的.但是我们通过容器去搭建lnmp环境时,nginx , php , mysql 这三个服务是独立的三个容器,彼此隔离.所以在yii2中连接mysql ...
- AJ学IOS(47)之网易彩票帮助界面UIWebView的运用
AJ分享,必须精品 效果: 制作过程 首先是帮助按钮那个地方的点击. 这里是用点击跳转的用的是 NJSettingArrowItem,前面的设置的,从字典通过模型转过来的. // 分享 NJSetti ...