第三次作业-结对项目
个人项目
这个作业属于哪个课程 | 班级的链接 |
---|---|
这个作业要求在哪里 | 作业要求的链接 |
这个作业的目标 | 训练个人项目软件开发能力,学会使用性能测试工具和实现单元测试优化程序 |
作者:关健佳3121004072
PSP2表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 90 |
- Estimate | - 估计这个任务需要多少时间 | 30 | 20 |
Development | 开发 | 300 | 360 |
- Analysis | - 需求分析(包括学习新技术) | 60 | 90 |
- Design Spec | - 生成设计文档 | 30 | 30 |
- Design Review | - 设计复审(和同事审核设计文档) | 30 | 30 |
- Coding Standard | - 代码规范(为目前的开发制定合适的规范) | 30 | 20 |
- Design | - 具体设计 | 60 | 60 |
- Coding | - 具体编码 | 120 | 150 |
- Code Review | - 代码复审 | 30 | 30 |
- Test | - 测试(自我测试,修改代码,提交修改) | 60 | 90 |
Reporting | 报告 | 120 | 90 |
- Test Report | - 测试报告 | 30 | 30 |
- Size Measurement | - 计算工作量 | 30 | 20 |
- Postmortem & Process Improvement Plan | - 事后总结,并提出过程改进计划 | 60 | 40 |
合计 | 480 | 540 |
系统设计报告
1. 代码组织结构
本项目的代码组织如下:
Four_arithmetic_operations/
├── main.py # 核心代码文件,包含所有功能实现
├── Exercises.txt # 生成的练习题文件
├── Answers.txt # 练习题对应答案文件
├── Grade.txt # 答案检查结果文件
└── README.md # 项目说明文档
核心类设计:
ArithmeticExerciseGenerator
: 四则运算题目生成器主类generate_number()
: 生成随机数(自然数或真分数)format_number()
: 格式化数字显示parse_number()
: 解析数字字符串为分数对象generate_expression()
: 生成包含指定运算符数量的表达式evaluate_expression()
: 计算表达式的值is_duplicate()
: 检查表达式是否重复generate_exercises()
: 生成指定数量的题目save_exercises()
和save_answers()
: 保存题目和答案到文件
辅助函数:
check_answers()
: 检查答案文件中的对错main()
: 程序入口函数
2. 关键函数流程图
题目生成流程
graph TDA[开始生成题目] --> B{题目数量是否足够}B -- 否 --> C[随机选择运算符数量]C --> D[生成表达式]D --> E{表达式是否重复}E -- 是 --> BE -- 否 --> F[计算表达式结果]F --> G{结果是否有效}G -- 是 --> H[存储题目和答案]G -- 否 --> BH --> BB -- 是 --> I[结束]
表达式计算流程
graph TDJ[开始计算表达式] --> K[替换表达式中的分数]K --> L[标准化运算符]L --> M[使用eval计算结果]M --> N[转换为分数形式]N --> O[返回结果]
3. 算法关键与创新点
关键算法:
-
分数表示与计算
- 使用Python内置的Fraction类进行精确的分数运算,避免浮点数精度问题
- 实现了带分数的表示方法(如:1'1/2)和转换函数
-
题目去重机制
- 通过标准化表达式(去除空格和括号,统一运算符)后比较字符串来判断重复
- 保证生成的题目具有唯一性
-
负数和零值处理
- 在减法运算中确保被减数大于减数,避免出现负数结果
- 在除法运算中检查除数不为零,防止除零错误
-
表达式生成策略
- 支持1-3个运算符的表达式生成
- 随机生成自然数和真分数,增加题目多样性
创新点:
-
真分数支持
- 完整实现了真分数的生成、解析、计算和显示
- 支持带分数(如:1'1/2)的表示和运算
-
智能去重算法
- 通过对表达式进行标准化处理后比较来检测重复题目
- 相比简单的字符串比较更准确
-
灵活的命令行接口
- 使用[argparse](file:///Users/guanjianjia/Gjj/software-engineering-2025/Four_arithmetic_operations/main.py#L3-L3)模块实现命令行参数解析
- 支持生成题目和检查答案两种模式
4. 项目关键代码与解释
分数生成与处理
def generate_number(self):"""生成一个数字(自然数或真分数)"""if random.choice([True, False]):# 生成自然数return random.randint(0, self.range_limit - 1)else:# 生成真分数denominator = random.randint(2, self.range_limit - 1)numerator = random.randint(1, denominator - 1)# 简化分数frac = Fraction(numerator, denominator)if frac.numerator > frac.denominator:# 生成带分数whole_part = frac.numerator // frac.denominatorremainder = frac.numerator % frac.denominatorif remainder == 0:return whole_partelse:return f"{whole_part}’{remainder}/{frac.denominator}"elif frac.numerator == frac.denominator:return 1else:return f"{frac.numerator}/{frac.denominator}"
这段代码实现了随机数生成,能够平衡地生成自然数和真分数,其中真分数会自动简化并按需转换为带分数形式。
表达式计算
def evaluate_expression(self, expr):"""计算表达式的值"""# 替换分数def replace_fractions(match):frac_str = match.group(0)if "’" in frac_str:parts = frac_str.split("’")whole = int(parts[0])frac_part = parts[1]frac_parts = frac_part.split("/")numerator = int(frac_parts[0])denominator = int(frac_parts[1])return str(Fraction(whole * denominator + numerator, denominator))else:frac_parts = frac_str.split("/")numerator = int(frac_parts[0])denominator = int(frac_parts[1])return str(Fraction(numerator, denominator))try:# 处理带分数和分数expr = re.sub(r'\d+’\d+/\d+', replace_fractions, expr)expr = re.sub(r'\d+/\d+', replace_fractions, expr)# 替换运算符expr = expr.replace('×', '*').replace('÷', '/')result = eval(expr)return Fraction(result).limit_denominator()except Exception as e:# print(f"计算错误: {e}, 表达式: {expr}")return Fraction(0)
该函数负责计算表达式的值,通过正则表达式识别并转换分数,利用Python的eval函数计算表达式,并最终返回Fraction类型的精确结果。
题目去重
def normalize_expression(self, expr):"""标准化表达式用于查重"""# 移除空格和括号normalized = re.sub(r'[\s()]', '', expr)# 标准化运算符normalized = normalized.replace('×', '*').replace('÷', '/')return normalizeddef is_duplicate(self, expr):"""检查表达式是否重复简化版查重:仅检查标准化表达式是否相同"""normalized = self.normalize_expression(expr)return normalized in self.exercise_set
这两个函数实现了表达式的标准化和重复检查功能,通过移除无关字符并将运算符统一,使语义相同的表达式具有相同的标准化形式。
5. 测试用例与结果验证
功能测试
-
题目生成测试:
python main.py -n 10 -r 10
生成题目示例:
1. 5 × 9 - 5 - 5 = 2. 5 × 5÷8 = 3. 3÷5 + 6÷7 + 1÷3 × 1÷5 = 4. 1÷3 ÷ 6 + 9 = 5. 1÷2 ÷ 6 = 6. 1 + 9 - 3 ÷ 7 = 7. 1÷4 ÷ 1÷4 × 8 + 7 = 8. 1÷2 × 7 = 9. 1÷2 × 0 ÷ 1÷4 × 3÷8 = 10. 5÷6 + 1÷4 =
对应答案:
1. 35 2. 3’1/8 3. 1’11/21 4. 9’1/18 5. 1/12 6. 9’4/7 7. 7’1/2 8. 3’1/2 9. 0 10. 1’1/12
-
答案检查测试:
python main.py -e Exercises.txt -a Answers.txt
检查结果保存在Grade.txt中:
Correct: 10 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) Wrong: 0 ()
边界条件测试
-
零值处理测试:
- 表达式:
1÷2 × 0 ÷ 1÷4 × 3÷8 =
- 正确结果:
0
- 表达式:
-
最大范围测试:
- 当设置范围为10时,生成的数字不会超过10
-
分数计算测试:
- 表达式:
5 × 5÷8 =
- 正确结果:
3'1/8
- 表达式:
异常情况测试
-
除零保护测试:
- 系统会在生成除法运算时确保除数不为零
-
负数避免测试:
- 减法运算中会自动调整操作数顺序,确保结果非负
6. 结对开发经验总结
成功经验
-
分工明确
- 一人负责核心算法实现,另一人专注于测试和边界条件处理
- 定期交换角色,确保双方对整个项目都有深入了解
-
持续集成
- 每完成一个功能就立即进行测试,避免积累过多问题
- 使用版本控制系统记录每次重要变更
-
代码评审
- 每个功能完成后都要经过另一人审查才能合并
- 发现了不少潜在的逻辑错误和边界情况处理不当的问题
遇到的挑战
-
分数运算复杂性
- 分数的表示、计算和格式化涉及到多个细节处理
- 带分数的支持增加了额外的复杂度
-
题目去重难题
- 初期采用简单字符串比较无法识别语义相同的表达式
- 后续通过标准化处理解决了这一问题
-
命令行接口设计
- 需要同时支持题目生成和答案检查两种模式
- 使用argparse库很好地解决了这个问题
改进方向
-
增强去重算法
- 当前的去重算法只能识别完全相同的表达式
- 可以进一步实现基于运算规则的智能去重(如加法交换律)
-
优化表达式生成
- 当前的表达式生成较为简单,可以引入更多复杂的表达式结构
- 可以增加括号支持,提高题目难度层次
-
完善测试覆盖
- 增加更多的自动化测试用例
- 引入单元测试框架,提高测试效率和准确性
四、我的 GitHub 地址
https://github.com/JianjiaGuan
该作业备份仓库位置
https://github.com/JianjiaGuan/software-engineering-2025