Github: 稍后上传再贴
小组:龙天尧(代码实现),林毓植(浮点转分数函数,代码审查)
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 | 30 |
· Estimate |
· 估计这个任务需要多少时间 |
30 | 30 |
Development |
开发 |
540 | 540 |
· Analysis |
· 需求分析 (包括学习新技术) |
60 | 60 |
· Design Spec |
· 生成设计文档 |
30 | 30 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
60 | 60 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
30 | 30 |
· Design |
· 具体设计 |
120 | 120 |
· Coding |
· 具体编码 |
240 | 240 |
· Code Review |
· 代码复审 |
60 | 60 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
60 | 60 |
Reporting |
报告 |
90 | 90 |
· Test Report |
· 测试报告 |
30 | 30 |
· Size Measurement |
· 计算工作量 |
30 | 30 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 | 30 |
合计 |
780 | 780 |
设计实现过程:思路:计算器功能应该包括 出题,计算答案, 对比答案 这三个主要功能。
代码说明:
题目生成函数:problem()
def problem(area=10): # 随机生成一道题目(自然数四则运算或分数运算),运算符不超过3个 global sequence operator_num = random.randint(1, 3) # 随机运算符 flag = random.randint(1, 2) # 随机生成 自然或分数 四则运算 try: if flag == 1: # 自然数运算 expression = print_expression = str(random.randint(1, area)) # 第一个数 bracket = (random.choice(['(', '']) if not operator_num == 1 else '') # 非单运算符 可加括号 for i in range(operator_num): # 随机个运算符 op = str(random.choice(operators)) # 随机选择运算符 (+ - * /) num = str(random.randint(1, area)) # 随机数值,不超过area if bracket == ')': # 右括号在数字右边 print_expression += ' ' + change(op) + ' ' + num + bracket # 用于输出的表达式 例:1×2 expression += op + num + bracket # 用于eval()计算的表达式 例:1*2 else: # 左括号在数字左边 print_expression += ' ' + change(op) + ' ' + bracket + num expression += op + bracket + num bracket = (')' if bracket == '(' else '') # 左括号配右括号, 空配空 results = demical_to_fraction(eval(expression)) # 运算结果通过demical_to_fraction()转成分数 else: # 分数运算 和上面流程大致相同 expression = print_expression = str(Fraction(random.randint(1, area), random.randint(1, area))) # 第一个分数 bracket = (random.choice(['(', '']) if not operator_num == 1 else '') for i in range(operator_num): op = str(random.choice(operators)) num = Fraction(random.randint(1, area), random.randint(1, area)) # 生成随机分数 if bracket == ')': if float(num) > 1 and not str(num - int(num)) == '0': # 假分数转带分数 print_expression += ' ' + change(op) + ' ' + str(int(num)) + "'" + str(num - int(num)) + bracket elif float(num) > 1: print_expression += ' ' + change(op) + ' ' + str(int(num)) + bracket else: print_expression += ' ' + change(op) + ' ' + str(num) + bracket expression += op + str(num) + bracket else: if float(num) > 1 and not str(num - int(num)) == '0': # 假分数 例:8/3 print_expression += ' ' + change(op) + ' ' + bracket + str(int(num)) + "'" + str(num - int(num)) elif float(num) > 1: # 回炉重造 例:9/3 problem(area) return else: print_expression += ' ' + change(op) + ' ' + bracket + str(num) expression += op + bracket + str(num) bracket = (')' if bracket == '(' else '') # 左括号配右括号 results = demical_to_fraction(eval(expression)) if results >= 0 and results not in open('Answers.txt', 'a+'): # 结果不为负, 答案不重复 # print(expression) with open('Exercises.txt', 'a+') as f: f.write(str(sequence) + '. ' + print_expression+' = '+'\n') # 存放题目 with open('Answers.txt', 'a+') as f: f.write(str(sequence) + '. ' + str(results) + '\n') # 存放答案 sequence += 1 print(print_expression+' = ') # 例:1+2= else: # 去重复 problem(area) except Exception as e: # 过滤分母为0的错误 problem(area)
转符号函数 change():
def change(a): # *,/ 转成 ×,÷ if a == '*': a = '×' elif a == '/': a = '÷' return a
eval函数处理的结果出来是浮点数,不符合要求,苦想不解,让毓植写了个浮点转化分数的函数
def find_cycle(demical): # 参数为小数部分 for i in range(1, 17): cycle_part = demical[:i] # 截取小数部分的前i位,假设为循环体 if len(cycle_part) < 4: # 如果循环体较短 if (cycle_part*i*4) == demical[:4*i]: # 需要满足4次重复 return cycle_part # 满足才认定为循环体 else: # 如果循环体较长 if (cycle_part*i*2) == demical[:2*i]: # 满足2次重复 return cycle_part return 0 # 找不到循环体,返回0 def demical_to_fraction(n, zero_num=0): n = str(n) # 规范输入为字符串形式 if len(n) < 16: # 如果是有限小数,直接返回 return Fraction(n) real_num, dot_area = n.split('.') # 获取整数 和 小数 float_num = float(n) # 转化一个浮点数用于计算 for i in range(len(n)): cycle_start = dot_area[i:] # 从第i位开始,开始截取字符串 result = find_cycle(cycle_start) # 从截取的字符串中找到循环体 length = len(str(result)) # 判断循环体的长度 if result: # 如果存在循环体 if i != 0: # 如果循环体的开始不是小数点后第一位 eg 0.13888888 new_number = float_num*(10**i) # 移位数使循环体是小数点后的开始 eg 13.8888 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**zero_num) # 回退移的位数
以上是主要函数
具体源码后面会上传到github
运行结果:
生成一万道题:
小学生就可以在记事本上做题啦
一年后。。
开始对答案
好了。。。
项目小结:这个项目挺有意思的,主要运用到”随机性“,小逻辑特别多,主要思路还是有迹可循的,继续努力,加油。