项目成员 | 汪雨嫣3223003305、沙吉旦·乃吉米丁3223004775 |
---|---|
GitHub地址 | https://github.com/wyy517/WYY517/tree/main/math |
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience |
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/homework/13479 |
这个作业的目标 | <实现小学四则运算题目生成器> |
一、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 45 |
·Estimate | ·估计这个任务需要多少时间 | 30 | 45 |
Development | 开发 | 515 | 600 |
·Analysis | ·需求分析 (包括学习新技术) | 60 | 75 |
·Design Spec | ·生成设计文档 | 45 | 60 |
·Design Review | ·设计复审 | 30 | 25 |
·Coding Standard | ·代码规范 (为目前的开发制定合适的规范) | 20 | 15 |
·Design | ·具体设计 | 60 | 80 |
·Coding | ·具体编码 | 240 | 300 |
·Code Review | ·代码复审 | 60 | 45 |
·Test | ·测试(自我测试,修改代码,提交修改) | 120 | 150 |
Reporting | 报告 | 150 | 165 |
·Test Repor | ·测试报告 | 90 | 120 |
·Size Measurement | ·计算工作量 | 20 | 15 |
·Postmortem & Process Improvement Plan | ·事后总结, 并提出过程改进计划 | 40 | 30 |
·合计 | 695 | 810 |
二、效能分析
性能改进过程
在开发过程中,我们主要在以下方面进行了性能优化:
1.表达式生成算法优化
- 初始版本使用深度递归,容易栈溢出
- 改进为迭代生成,限制递归深度
- 添加重复表达式检测,避免无限循环
2.分数计算优化
- 最初使用Python的eval函数,存在安全风险
- 改为自定义表达式解析器,提高安全性
- 实现分数约分缓存,避免重复计算
性能分析结果
通过cProfile进行分析,发现最耗时的函数:
性能优化思路
# 优化前:深度递归
def generate_expression(depth):if depth == 0: return numberreturn f"{generate_expression(depth-1)} op {generate_expression(depth-1)}"# 优化后:迭代生成
def generate_expression_iterative():numbers = generate_numbers()while len(numbers) > 1:# 随机组合数字和运算符# 检查约束条件# 构建表达式
三、设计实现过程
类设计图
├──小学四则运算题目生成器
├── main.py (主程序入口)
│ ├── 命令行参数解析
│ ├── 模式选择(生成/批改)
│ └── 模块协调
│
├── fraction.py (分数核心类)
│ ├── Fraction
│ │ ├── __init__(numerator, denominator) - 初始化并自动约分
│ │ ├── simplify() - 分数约分
│ │ ├── to_mixed_number() - 转换为带分数
│ │ ├── to_improper_fraction() - 转换为假分数
│ │ ├── __add__, __sub__, __mul__, __truediv__ - 运算符重载
│ │ ├── __lt__, __eq__, __le__ - 比较运算符
│ │ ├── random_fraction(max_value) - 生成随机分数
│ │ └── from_string(s) - 从字符串解析
│
├── expression.py (表达式生成类)
│ ├── Expression
│ │ ├── __init__(max_ops, number_range)
│ │ ├── generate() - 生成表达式
│ │ ├── _generate_expression_tree() - 递归生成表达式树
│ │ ├── _choose_operator() - 智能选择运算符
│ │ ├── _apply_operator() - 应用运算符计算
│ │ ├── _calculate_expression() - 计算表达式值
│ │ ├── _check_constraints() - 检查约束条件
│ │ └── get_value() - 获取表达式值
│
├── generator.py (题目生成器)
│ ├── ProblemGenerator
│ │ ├── __init__()
│ │ ├── generate_problems(count, number_range) - 生成题目
│ │ ├── _is_valid_answer() - 验证答案有效性
│ │ ├── _normalize_expression() - 表达式规范化去重
│ │ └── save_to_files() - 保存题目和答案
│
└── checker.py (答案批改器)├── AnswerChecker│ ├── __init__()│ ├── check_answers(exercise_file, answer_file) - 批改答案│ ├── _calculate_problem() - 计算题目答案│ ├── _evaluate_expression() - 表达式求值│ ├── _compare_answers() - 答案比较│ ├── _normalize_answer() - 答案规范化│ └── save_grade() - 保存批改结果
关键函数流程图
1.主程序执行流程图
2.题目生成流程图
3.表达式流程图
4.答案批改流程图
5.分数运算流程图
四、代码说明
关键代码1:Fraction类(分数运算核心)
class Fraction:def __init__(self, numerator, denominator=1):if denominator == 0:raise ValueError("分母不能为零")self.numerator = numeratorself.denominator = denominatorself.simplify() # 自动约分def simplify(self):"""约分方法,确保分数最简形式"""if self.numerator == 0:self.denominator = 1returngcd_val = math.gcd(abs(self.numerator), abs(self.denominator))self.numerator //= gcd_valself.denominator //= gcd_val# 确保分母为正if self.denominator < 0:self.numerator = -self.numeratorself.denominator = -self.denominator
关键代码2:表达式生成算法
def _generate_expression_tree(self, depth, operators, number_range):"""递归生成表达式树,确保题目多样性"""if depth == 0:num = Fraction.random_fraction(number_range)return str(num), num# 随机分配左右子树深度left_depth = random.randint(0, depth - 1)right_depth = depth - 1 - left_depthleft_expr, left_val = self._generate_expression_tree(left_depth, operators, number_range)right_expr, right_val = self._generate_expression_tree(right_depth, operators, number_range)# 智能选择运算符,满足约束条件op = self._choose_operator(left_val, right_val, operators)# 构建表达式并计算值current_value = self._apply_operator(left_val, right_val, op)return f"({left_expr} {op} {right_expr})", current_value
关键代码3:约束检查
def _check_constraints(self):"""检查题目约束条件"""if self.value is None:return False# 1. 无负数结果if self.value < Fraction(0):return False# 2. 除法结果为真分数if hasattr(self.value, 'denominator') and self.value.denominator != 1:if abs(self.value.numerator) >= abs(self.value.denominator):return False# 3. 数值范围检查return self._check_numbers_in_range()
五、测试运行
测试用例设计
基础功能测试:
python main.py -n 5 -r 10 # 生成5道10以内题目
python main.py -n 10000 -r 20 # 压力测试1万题目
python main.py -n 1 -r 1 # 边界值测试
分数运算测试:
1/2 + 1/3 = 5/6 # 基础分数加法
3/4 - 1/4 = 1/2 # 分数减法
1/2 × 2/3 = 1/3 # 分数乘法
1/2 ÷ 1/4 = 2 # 分数除法
复杂表达式测试:
(1/2 + 1/3) × 3/5 = 1/2 # 带括号表达式
2 × 3 + 4 ÷ 2 = 8 # 混合运算
1'1/2 + 2'1/3 = 3'5/6 # 带分数运算
批改功能测试
python main.py -e Exercises.txt -a Answers.txt # 正常批改
python main.py -e Exercises.txt -a WrongAnswers.txt # 错误答案检测
测试结果
Exercises.txt
1. 2 × 2/9 =
2. (7 + 1/2 × 1/3) =
3. 5/7 × 2 =
4. 5 × 5/6 =
5. 9/10 × 4/9 =
6. (1/2 × 1/2 ÷ 4 ÷ 8) =
7. 3/4 + 3 =
8. 2 - 8/9 + 2/9 =
9. 6 - 1/2 × 7 =
10. 3 ÷ 5 ÷ 1 =
Answers.txt
1. 4/9
2. 2'1/2
3. 1'3/7
4. 4'1/6
5. 2/5
6. 1/2
7. 3'3/4
8. 1'1/3
9. 2'1/2
10. 3/5
Grade.txt
Correct: 8 (1, 3, 4, 5, 7, 8, 9, 10)
Wrong: 2 (2, 6)
六、项目小结
项目成果
本项目成功实现了小学四则运算题目生成器的所有核心功能:
✅ 支持自然数、真分数、带分数
✅ 控制题目数量和数值范围
✅ 避免负数和假分数结果
✅ 题目去重功能
✅ 文件输入输出
✅ 答案批改统计
经验教训
1.成功经验:
· 模块化设计:将分数、表达式、生成器分离,便于测试和维护
· 约束驱动开发:先定义清楚所有约束条件,再实现功能
· 渐进式开发:从简单功能开始,逐步增加复杂度
2.遇到的问题:
· 表达式计算复杂性:递归生成容易栈溢出,改为迭代方法
· 分数运算精度:需要处理约分和规范化表示
· 去重算法设计:表达式规范化比较具有挑战性