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.  #随机生成一道题目中的符号和数字

  1. def random_list(self):
  2. char_list = ["+", "-", u"×", u"÷"]
  3. num_list = []
  4. char_choice = []
  5. cc = ""
  6. loop_times = random.randint(2,4)
  7. for i in range(loop_times):
  8. static = random.randint(1, self.num_range)
  9. if self.num_range > 1:
  10. float_n = produce_random.choose_num(self)
  11. choice = random.choice([static, float_n])
  12. else:
  13. choice = static
  14. cc += str(choice)
  15. num_list.append(choice)
  16. if i < (loop_times - 1):
  17. cha = random.choice(char_list)
  18. char_choice.append(cha)
  19. cc += cha
  20. jo = str(num_list+char_choice)
  21. if jo in dic_t.keys():
  22. self.random_list()
  23. else:
  24. dic_t[jo] = 0
  25. return char_choice, num_list

2.  #随机生成分数

  1. def choose_num(self):
  2. while(1):
  3. a = random.randint(1, self.num_range**2)
  4. b = random.randint(2, self.num_range)
  5. if Decimal(a/b) < self.num_range:
  6. return Fraction(a, b)

3.  #根据符号随机加括号

  1. def plus_(self,char_choice, num_list):
  2. numble = len(num_list) + len(char_choice)
  3. ccc = [""] * numble
  4. if len(char_choice) == 1:
  5. pass
  6. else:
  7. """括号对数"""
  8. n_kuo = random.randint(0, len(char_choice) - 1)
  9. if n_kuo != 0:
  10. p_kuo_l = []
  11. """设置list1初值"""
  12. list1 = []
  13. for i in range(0, len(char_choice)):
  14. z = 2 * i
  15. """改为append"""
  16. list1.append(z)
  17. p_kuo_l = random.sample(list1, 1) # 按照char的数量来存,2个就是[0,2],3个[0,2,4]
  18. ccc.insert(p_kuo_l[0], '(') # 插入1st左边的括号
  19. if len(char_choice) == 2:
  20. ccc.insert(p_kuo_l[i-1] + 4, ')')
  21. if len(char_choice) == 3:
  22. """第一个右括号"""
  23. if p_kuo_l[0] == 0:
  24. list1 = [4]
  25. if p_kuo_l[0] == 2:
  26. list1 = [p_kuo_l[0] + int(random.sample([4, 6], 1)[0])]
  27. if p_kuo_l[0] == 4:
  28. list1 = [8]
  29. p_kuo_r = list1[:]
  30. ccc.insert(p_kuo_r[0], ')')
  31. x = p_kuo_l + p_kuo_r
  32. if n_kuo == 2: # 加第二个右括号
  33. if x[0] == 2:
  34. if x[1]==x[0]+4:
  35. y = random.sample([0, x[0]], 1)
  36. ccc.insert(y[0], '(')
  37. if y[0] == 0:
  38. ccc.insert(x[1]+1, ')')
  39. else:
  40. ccc.insert(x[0] + 8, ')')
  41. else:
  42. y = random.sample([x[0], x[0] + 3], 1)
  43. ccc.insert(y[0], '(')
  44. if y[0] == 2:
  45. ccc.insert(x[0] + 5, ')')
  46. else:
  47. ccc.insert(x[0] + 7, ')')
  48. if x[0] == 0:
  49. y = x[0]
  50. ccc.insert(y, '(')
  51. ccc.insert(x[0] + 8, ')')
  52. if x[0] == 4:
  53. y = x[0]-2
  54. ccc.insert(y, '(')
  55. ccc.insert(x[0]+7, ')')
  56. num = 0
  57. cha = 0
  58. list_all = [] # 装数字+字符
  59. j = 0
  60. flag = True
  61. #标记乘号的个数
  62. multi_n = []
  63. #标记除号的个数
  64. divide_n = []
  65. for i in range(0, len(num_list)):
  66. if j == (len(num_list) - 1):
  67. j -= 1
  68. flag = False
  69. list_all.append(num_list[i])
  70. if i == j and flag == True:
  71. list_all.append(char_choice[j])
  72. j += 1
  73. j = 0
  74. for i in range(0, len(ccc)):
  75. if ccc[i] != '':
  76. continue
  77. if list_all[j]=='×':
  78. multi_n.append(i)
  79. if list_all[j]=='÷':
  80. divide_n.append(i)
  81. ccc[i] = list_all[j]
  82. j += 1
  83. return ccc, multi_n, divide_n

4. #符号转换,把list改为str来计算,分数周围有自己的括号(计算的时候将分数看成除法来计算)

  1. def join_c(self, ccc, multi_n, divide_n):
  2. list1 = ccc[:]
  3. ll = []
  4. for i in multi_n:
  5. list1[i]= '*'
  6. for j in divide_n:
  7. list1[j] = '/'
  8. for i in list1:
  9. if type(i) == Fraction:
  10. if i.denominator == 1:
  11. ll.append(str(i))
  12. else:
  13. ll.append('('+str(i)+')')
  14. elif type(i) == int:
  15. ll.append(str(i))
  16. else:
  17. ll.append(i)
  18. final = ''.join(ll)
  19. return final

5.   #计算

  1. def calculate(final):
  2. result = eval(final)
  3. return result
  1. 6. #查找小数循环,小数转分数
  1. def ff_c(self, demical): # 参数为小数
  2. for i in range(1, 16):
  3. cpart = demical[:i]
  4. if len(cpart) < 4:
  5. if (cpart * i * 4) == demical[:4 * i]: # 4次重复
  6. return cpart # 循环体
  7. return 0 # 找不到循环体,返回0
  8.  
  9. #小数转分数
  10. def demical_to_fraction(self, digi, back_num=0):
  11. digi = str(digi)
  12. if len(digi) <= 15: # 有限小数
  13. return Fraction(digi)
  14. real_num, dot_area = digi.split('.')
  15. float_num = float(digi)
  16. for i in range(len(digi)):
  17. cycle_start = dot_area[i:]
  18. result = self.ff_c(cycle_start)
  19. length = len(str(result)) # 循环体的长度
  20. if result: # 存在循环体
  21. if i != 0: # 不是小数点后第一位
  22. new_number = float_num * (10 ** i) # 移位数
  23. self.demical_to_fraction(new_number, i) # 递归
  24. break
  25. else: # 小数点后的第一位
  26. fraction = Fraction(int(result), int('9' * length)) # 小数转分数
  27. final_num = int(real_num) + fraction
  28. return final_num / (10 ** back_num) # 回退移的位数
  29. return False

7.  #最后转为真分数输出

  1. def change_l(self,li):
  2. hh = []
  3. for i in li:
  4. if type(i) == Fraction:
  5. hh.append(change_ff(i))
  6. hh.append(' ')
  7. continue
  8. else:
  9. hh.append(str(i))
  10. hh.append(' ')
  11. return hh

8. # 写入文件

  1. def write(self, f_line):
  2. self.glocount += 1
  3. count = int((self.glocount + 1) / 2)
  4. tihao = str(count) + '. '
  5. file = open('Exercise.txt', 'a')
  6. f_line = tihao + f_line + ' ='
  7. file.write(f_line + '\n')
  8. file.close()
  9.  
  10. def write_a(self, f_line):
  11. self.glocount += 1
  12. tihao = str(int(self.glocount / 2)) + '. '
  13. file = open('Answers.txt', 'a')
  14. f_line = tihao + f_line
  15. file.write(f_line + '\n')
  16. file.close()

功能10:

1. # 支持读取给定的文件

  1. def read_f(name):
  2. with open(name) as Re:
  3. file = Re.readlines()
  4. return file

  2. #检查文件名是否符合格式

  1. def check_file(file_name):
  2. if re.match(r"[a-zA-Z0-9]*\..", file_name):
  3. return True
  4. print("The file name is not right.")
  5. return False

  3. #转换分数AND真分数

  1. def change_re_fra(expre):
  2. if re.search("[1-9]\'[1-9]/[1-9]", expre):
  3. l1 = expre.split("\'")
  4. l2 = l1[1].split("/")
  5. num_1 = eval(l1[0])
  6. num_2 = eval(l2[0])
  7. num_3 = eval(l2[1])
  8. middle_p = num_3*num_1
  9. num_2 += middle_p
  10. return str(Fraction(num_2,num_3))
  11. if expre == '×':
  12. expre = '*'
  13. if expre == '÷':
  14. expre = '/'
  15. return expre
  16.  
  17. def change_ff(fra):
  18. d = fra.denominator
  19. n = fra.numerator
  20. midde = n // d
  21. if midde == 0:
  22. return str(n)
  23. cha = n - d * midde
  24. if cha == 0:
  25. return str(midde)
  26. return str(midde)+'\''+str(Fraction(cha,d))

  4. #比对提交的和user答案一致性

  1. def bidui(ans,user):
  2. corr,wrong = [],[]
  3. a_line = read_f(ans)
  4. user_line = read_f(user)
  5. for i in range(0,len(a_line)):
  6. if a_line[i] == user_line[i]:
  7. corr.append(str(i))
  8. corr.append(',')
  9. else:
  10. wrong.append(str(i))
  11. wrong.append(',')
  12. u1 = ''.join(corr)
  13. u2 = ''.join(wrong)
  14. co = 'Correct:'+str(len(corr)//2)+'('+u1+')'
  15. w = 'Wrong:'+str(len(wrong)//2)+'('+u2+')'
  16. write_Grade(co,w,'Grade.txt')
  1. def compare(file_list):
  2. file = read_f(file_list[0])
  3. gloc = 0
  4. for i in file:
  5. i = i.rstrip()
  6. lii = i.split('.')
  7. c = lii[1].split(' ')
  8. strr = ''
  9. for j in c:
  10. if j != '=':
  11. str = change_re_fra(j)
  12. strr += str
  13. result = calculate(strr)
  14. f_result = demical_to_fraction(result)
  15. ff_result = change_ff(f_result)
  16.  
  17. write1(ff_result, 'answer2.txt',gloc)
  18. gloc += 1
  19. bidui('answer2.txt',file_list[1])

  5.  #写入文件

  1. def write1(result, name,glocount):
  2. glocount += 1
  3. count = glocount
  4. tihao = str(count) + '. '
  5. file = open(name, 'a')
  6. f_line = tihao + result
  7. file.write(f_line + '\n')
  8. file.close()
  9.  
  10. def write_Grade(c,w,name):
  11. file = open(name, 'a')
  12. file.write(c+'\n'+w)
  13. file.close()

  main函数:

  1. if __name__ == '__main__':
  2.  
  3. file = open('Exercise.txt', 'r+')
  4. file.truncate()
  5. file.close()
  6. file = open('Answers.txt', 'r+')
  7. file.truncate()
  8. file.close()
  9. sys.setrecursionlimit(10000)
  10. dic_t = {}
  11. if len(sys.argv)>2:
  12. num_range, ti_num = menu()
  13. if num_range > 0 and ti_num > 0:
  14. instance = produce_random(num_range, ti_num)
  15. instance.running()
  16. else:
  17. print("输入命令不足")
  1. def menu():
  2. flag = 0
  3. compare_arg = 0
  4. file_rrlist = []
  5. for i in range(len(sys.argv)):
  6. if sys.argv[i]=='-e':
  7. if check_file(sys.argv[i+1]):
  8. file_rrlist.append(sys.argv[i+1])
  9. compare_arg += 1
  10. continue
  11. elif sys.argv[i]=='-a':
  12. if check_file(sys.argv[i+1]) and compare_arg==1:
  13. file_rrlist.append(sys.argv[i+1])
  14. compare(file_rrlist)
  15. flag = -1
  16. elif sys.argv[i]=='-n' and compare_arg==0:
  17. ti_num = input("请输入题目数量:")
  18. ti_num = int(ti_num)
  19. if ti_num<=0:
  20. print("数量过少,请重试")
  21. break
  22. flag += 1
  23. elif sys.argv[i]=='-r' and compare_arg==0:
  24. num_range = input("请输入数值范围:")
  25. num_range = int(num_range)
  26. if num_range<=1:
  27. print("数值范围不存在")
  28. continue
  29. else:
  30. break
  31. flag +=1
  32. if flag == 1:
  33. return num_range, ti_num
  34. elif flag==-1:
  35. return -1,-1
  36. else:
  37. print("输入不正确")
  38. return 0, 0
  1. def running(self):
  2. #利用for循环输出多道题
  3. for i in range(self.num):
  4. while True:
  5. char_choice, num_list = self.random_list()
  6. k, multi_n, divide_n = self.plus_(char_choice, num_list)
  7. new_title = self.join_c(k, multi_n, divide_n)
  8. z = calculate(new_title)
  9. if z < 0:
  10. continue
  11. final_result = demical_to_fraction(z)
  12. if type(final_result) == float or final_result==False:
  13. continue
  14. if final_result.denominator > self.num_range:
  15. continue
  16. else:
  17. break
  18. nn_tt = self.change_l(k)
  19. final_result = change_ff(final_result)
  20. nn_tt = ''.join(nn_tt)
  21. print(nn_tt)
  22. self.write(nn_tt)
  23. 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-四则运算-蔡晓晴,杜婷萱的更多相关文章

  1. python四则运算2.0

    github项目地址: https://github.com/kongkalong/python PSP 预估耗时(分钟) Planning .Estimate 48*60 Development . ...

  2. python四则运算

    源代码已上传至Github,https://github.com/chaigee/arithmetic,中的python_ari.py文件 题目: (1)能自动生成小学四则运算题目,并且不能出现负数: ...

  3. 团队合作项目—(GG队)

    团队展示 一.队名:GG 二.队员信息 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 311600 ...

  4. 团队项目第六周——事后诸葛亮分析(GG队)

    一.总结: 本次项目作为我们第一次团队集体开发的项目,使我们在项目开发以及团队合作方面都有了宝贵的 经验以及初步的认识: 从项目开发的方面来看: 通过本次项目,我们更进一步加强了自己的前端知识,并初步 ...

  5. 团队项目(第四周冲刺之二)—GG队

    项目冲刺: 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 3116004661 (先把帅气的合照不 ...

  6. 团队项目(第四周之一)—GG队

    Alpha认领任务: 叶尚文:对应键盘监听结果的动画以及计算 于泽浩:制作背景gif图,并保证能在程序中循环播放 龙剑初:项目进度跟进及博客更新 杜婷萱:把图片结合起来,设置云朵透明度的变化 蔡晓晴: ...

  7. 团队项目(第三周)—GG队

    需求改进&系统设计 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 3116004661 一 ...

  8. 团队项目(第二周)—GG队

    项目需求规格分析 队员信息 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 3116004661 项 ...

  9. [Day01] Python基础

    明天要完成的任务如下:  Python 四则运算 Python 数据结构 Python 元算符(in.not in.is.and.or) 用户输入 (input.raw_input) 流程控制 缩进 ...

随机推荐

  1. 从一个慢查询到MySQL字符集编码

    从一个慢查询到MySQL字符集编码 目录 从一个慢查询到MySQL字符集编码 1. 问题起源 2. MySQL字符集和字符集排序规则 2.1 字符集相关概念 2.2 MySQL中的字符集和字符集排序规 ...

  2. 微信小程序之界面交互反馈

    交互反馈就是在用户出发某事件之后,给用户一个反馈信息,这要是一个很友好的习惯. 在小程序中是通过一下几种方式实现的: 1.wx.showToast()方法 showToast: function (p ...

  3. 记一次mysql多表查询(left jion)优化案例

    一次mysql多表查询(left jion)优化案例 在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时, ...

  4. kali2016&2019的安装使用

    先解释一下,为什么要说2016&2019哪,这是因为有一些测试靶机环境在2016以上的系统安装不通过,所以有时候会特意找2016的镜像来用. 一.下载镜像 1.下载镜像当然要到官方去下载了: ...

  5. 基于 Spring Cloud 的微服务架构实践指南(下)

    show me the code and talk to me,做的出来更要说的明白 本文源码,请点击learnSpringCloud 我是布尔bl,你的支持是我分享的动力! 一.引入 上回 基于 S ...

  6. flask from_object和from_pyfile的区别

    flask  from_object和from_pyfile的区别 from_object接受的是一个模块对象,需求导入 from_pyfile接受的是一个文件名的字符串,文件可以不是py文件也可以是 ...

  7. ubuntu18.04配置宽带上网

    1.将 /etc/NetworkManager 目录下的 managed标签改为true 2.将 /etc/network/ 目录下的 interfaces文件只留下前两行: auto lo ifac ...

  8. C++ memset函数用法

    #include<stdio.h>#include<string.h>int main(){ char buffer[] = "I love you!"; ...

  9. html字体大小与颜色设置

    代码架构:<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> //浏览器识 ...

  10. C - Sweets Eating

    规律题 前缀和+规律 先求前缀和...答案为c[i]=arr[i]+c[i-m]//i>m时. #include<bits/stdc++.h> using namespace std ...