结对项目-自动生成四则运算
这个作业属于哪个课程 | 计科国际班软工 |
---|---|
这个作业要求在哪里 | |
这个作业的目标 | 合作编写自动生成四则运算程序 |
1.结对成员:
叶永安 3119009472 github仓库·:https://github.com/yyya77/-/tree/master
粟云涛 3119009470 github仓库: https://github.com/XIMI666/SU/tree/master
2.PSP表格:
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 10 | 20 |
Development | 开发 | 890 | 1500 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 180 |
· Design Spec | · 生成设计文档 | 30 | 60 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 60 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 60 | 120 |
· Design | · 具体设计 | 60 | 100 |
· Coding | · 具体编码 | 600 | 900 |
· Code Review | · 代码复审 | 30 | 40 |
· Test | · 测试(自我测试,修改代码,提交修改) | 20 | 40 |
Reporting | 报告 | 50 | 110 |
· Test Repor | · 测试报告 | 20 | 30 |
· Size Measurement | · 计算工作量 | 10 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 60 |
Sum up | 合计 | 950 | 1630 |
3.效能分析:
用pycharm自带的分析工具我们得到:
代码覆盖率100%:
函数调用结构图:
函数调用次数及时间:
由图可知生成一万条式子时,Init了11444次,由此可知生成了1444次不符合条件的式子,同时剔除了这些不符合条件的式子,耗时最久的main函数耗时为38312ms,由此可知生成10000条式子耗时3.8s左右,效能还是比较不错的。因为在生成判断式子时反腐调用了很多循环,因此我们认为可以在结构上继续优化算法,使时间更快,代码更加简洁。
4.设计实现过程:
框架思路:
利用python列表的性质,可以在列表内任意地方使用insert()随机插入括号,我们想到了“套模板”的形式随机生成数组以及运算符号放入列表随机生成式子,为了让式子更加多样,我们想到运算符号随机缺失,从而决定式子一共做几次运算,即为几个数字和几个运算符。
算法是我们讨论得出,还没有查阅网上资料,因此可能算法上有所欠缺,但是依旧可以达到随机生成式子的效果。我们生成式子的大致流程如下:
5.代码说明:
初始化运算符号及真分数列表:我们想到因为一个数字列表是不可能又能真分数表示出来又能够计算的,因此我们想到用两个列表,一个存放用于计算的浮点数,一个用于存放便于用户观看的真分数字符串,实现代码如下
def Init(num1, ran, str): # 初始化
numerator = [] # 存放分子
denominator = [] # 存放分母
sym_local = 0
for i in range(4):
a = random.randint(1, ran) # 随机生成分子
b = random.randint(1, ran) # 随机生成分母
if a == 0:
str[sym_local] = '0'
elif a % b == 0:
str[sym_local] = ('%d' % (a / b))
elif a > b:
str[sym_local] = ("%d'%d/%d" % (a / b, (a % b) / math.gcd(a, b), b / math.gcd(a, b)))
else:
str[sym_local] = ("%d/%d" % (a / math.gcd(a, b), b / math.gcd(a, b)))
num1.append(a / b) #浮点数分数
numerator.append(a) #分子
denominator.append(b) #分母
sym_local += 2
sym1 = [None] * 3 # 存放运算符
sym1[0] = random.randint(0, 4) # 随机生成运算符,生成数为0代表运算符为空
sym1[1] = random.randint(1, 4)
sym1[2] = random.randint(0, 4)
# print(sym1)
return num1, sym1, numerator, denominator
浮点数计算及真分数计算:
def Calculate(num, sym, str, numerator, denominator): # 计算
answer_str = [None] * 4
result = 0
sym_local = 1
for i in [0, 2]:
if sym[i] == 0: # 运算符为空
result = num[i + 1]
str[sym_local] = None
str[sym_local - 1] = None
numerator[i] = numerator[i + 1]
denominator[i] = denominator[i + 1]
if sym[i] == 1: # 加
result = num[i] + num[i + 1]
str[sym_local] = '+'
numerator[i] = (numerator[i] * denominator[i + 1] + numerator[i + 1] * denominator[i])
denominator[i] = denominator[i] * denominator[i + 1]
if sym[i] == 2: # 减
if num[i] >= num[i + 1]:
result = num[i] - num[i + 1]
numerator[i] = (numerator[i] * denominator[i + 1] - numerator[i + 1] * denominator[i])
denominator[i] = denominator[i] * denominator[i + 1]
else:
temp = num[i + 1]
num[i + 1] = num[i]
num[i] = temp
result = num[i] - num[i + 1]
temp1 = str[sym_local - 1]
str[sym_local - 1] = str[sym_local + 1]
str[sym_local + 1] = temp1
numerator[i] = (numerator[i + 1] * denominator[i] - numerator[i] * denominator[i + 1])
denominator[i] = denominator[i] * denominator[i + 1]
str[sym_local] = '-'
if sym[i] == 3: # 乘
result = num[i] * num[i + 1]
str[sym_local] = '×'
numerator[i] = (numerator[i] * numerator[i + 1])
denominator[i] = denominator[i] * denominator[i + 1]
if sym[i] == 4: # 除
if num[i + 1] == 0:
num[i + 1] = None
str[sym_local] = None
else:
result = num[i] / num[i + 1]
str[sym_local] = '÷'
numerator[i] = (numerator[i] * denominator[i + 1])
denominator[i] = denominator[i] * numerator[i + 1]
sym_local += 4
sym[i] = result
if sym[1] == 1: # 整合运算结果
sym[1] = sym[0] + sym[2]
str[3] = '+'
numerator[1] = (numerator[0] * denominator[2] + numerator[2] * denominator[0])
denominator[1] = denominator[0] * denominator[2]
if sym[1] == 2:
sym[1] = sym[0] - sym[2]
str[3] = '-'
numerator[1] = (numerator[0] * denominator[2] - numerator[2] * denominator[0])
denominator[1] = denominator[0] * denominator[2]
if sym[1] == 3:
sym[1] = sym[0] * sym[2]
str[3] = '×'
numerator[1] = (numerator[0] * numerator[2])
denominator[1] = denominator[0] * denominator[2]
if sym[1] == 4:
if sym[2] == 0:
sym[1] = -1
str[4] = None
numerator[1] = 1
denominator[1] = 1
else:
sym[1] = sym[0] / sym[2]
numerator[1] = (numerator[0] * denominator[2])
denominator[1] = denominator[0] * numerator[2]
str[3] = '÷'
if denominator[1] == 0:
sym[1] = -1
answer_str.append("-1")
else:
if numerator[1] == 0:
answer_str.append("0")
elif numerator[1] % denominator[1] == 0:
answer_str.append("%d" % (numerator[1] / denominator[1]))
elif numerator[1] > denominator[1]:
answer_str.append("%d'%d/%d" % (
numerator[1] / denominator[1],
(numerator[1] % denominator[1]) / (math.gcd(numerator[1], denominator[1])),
denominator[1] / (math.gcd(numerator[1], denominator[1]))))
else:
answer_str.append("%d/%d" % (numerator[1] / (math.gcd(numerator[1], denominator[1])),
denominator[1] / (math.gcd(numerator[1], denominator[1]))))
str[7] = '='
# print(sym)
return sym[1], str, answer_str[4]
批改答案代码如下:
def Correcting(a, b): # 批改答案
result = open(a, encoding='utf-8')
correcting = open(b, encoding='utf-8')
check = open('check_result.txt', 'w', encoding='utf-8')
wrong = []
correct = []
count = len(open('Answers.txt', encoding='utf-8').readlines())
for i in range(count):
line1 = result.readline()
line2 = correcting.readline()
if line2 == line1:
correct.append(i + 1)
else:
wrong.append(i + 1)
check.write("%d correct:%s \n" % (len(correct), correct))
check.write("%d wrong:%s" % (len(wrong), wrong))
print("批改结果已放到check_result.txt")
result.close()
correcting.close()
check.close()
6.测试运行:
cmd命令:-r(生成真分数的范围) -n(生成题目数量) 批改:-e Answers.txt -a correcting.txt (-e后输入题目答案,-a后输入自己写的答案格式需要和题目答案一样)
生成10000道题:cmd输入
打开文件查看:题目生成成功!
生成10道题:
答题完毕后,进行批改:
答题情况如下:
程序批改成功!
参数输入错误报错:
8.项目小结:
叶永安小结:通过这次结对项目,我与粟云涛大佬一起编写程序,我充分体会到结对编程的好处,两个人的思想碰撞真的可以创造出火花,粟云涛大佬的想法总是直切主题,总能用更少量的代码实现和别人等效甚至更好的功能,同时两个人面对bug时,不会像一个人思考问题的时候一样陷入死循环,相互启发可以很快将问题解决,可惜就可惜在编写程序之前没有提前去查找资料了解相对应的算法,结构,而想着自己想算法,用自己的,因此有些功能并不是特别完善,吸取了这次的教训,以后编程项目一定会试着做得更加完美。
粟云涛小结:本次的任务是结对项目,这不仅仅考验我们的代码能力,还强调了团队合作。在和同学的讨论中,我们可以获得彼此的灵感也可以发现对方的不足,因此可以使设计的代码更加完善。在这个过程中,也学到了更多的知识,共同进步,受益良多。
9.算法改进:
在我们已经做出一个能满足作业要求的前提下,写了一个新算法的小demo,算法设计上对式子生成的效率和随机性应该会有所提升,但是由于时间问题,没能完全做出程序
样品主要函数如下:
def suiji():
a = ''
i = random.randint(1,3)
if i == 1 or 2 : #整数
a = str(random.randint(1,9))
t = 1 #整数
if i == 3:
a1 = random.randint(1,8)
a2 = random.randint(a1+1,9)
a = str(a1) + '/' + str(a2)
t = 0
return a,t
def kuohao():
k = random.randint(1,5)
if k == 1:
j = 1
else:
j = 0 #不加括号
return j
def szys():
kuo = 0
fen = 0
times = random.randint(1,3)
list = []
list.append(str(random.randint(1,9)))
for x in range(times):
sym1 = sym[random.randint(0,3)]
if sym1 == '+':
a,t = suiji()
j = kuohao()
if t == 1 and j == 1:
list += sym1 + a
list.insert(len(list)- 3 -kuo-fen,'(')
list.append(')')
kuo += 2
if t == 0 and j == 1:
fen += 2
list += sym1 + a
list.insert(len(list) - 3 - kuo-fen, '(')
list.append(')')
kuo += 2
if t == 1 and j == 0:
list += sym1 + a
if t == 0 and j == 0:
fen += 2
list += sym1 + a
if sym1 == '-':
a, t = suiji()
j = kuohao()
if t == 1 and j == 1:
list += sym1 + a
list.insert(len(list) - 3 - kuo - fen, '(')
list.append(')')
kuo += 2
if t == 0 and j == 1:
fen += 2
list += sym1 + a
list.insert(len(list) - 3 - kuo - fen, '(')
list.append(')')
kuo += 2
if t == 1 and j == 0:
list += sym1 + a
if t == 0 and j == 0:
fen += 2
list += sym1 + a
if sym1 == '*':
a,t = suiji()
if t == 1:
list += sym1 + a
if t == 0:
fen += 2
list += sym1 + a
if sym1 == '/':
a, i = suiji()
if i == 1 or 2:
list += sym1 + a
if i == 3:
fen += 2
list += sym1 + a
list += sym1 + a
if i == 3:
fen += 2
list += sym1 + a