自动生成小学四则运算题目的命令行程序项目
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience |
|这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/homework/13479 |
|这个作业的目标 | 实现四则运算题目生成、答案生成、判对错的需求,接触合作开发项目的流程 |
GitHub项目地址 :https://github.com/Eazinchen/caculate
项目成员:陈愉均3123004262;陈煜楠3123004263
1、PSP表格
PSP阶段 | 内容 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 35 |
· Estimate | 估计这个任务需要多少时间 | 20 | 25 |
Development | 开发 | 600 | 630 |
· Analysis | 需求分析(包括学习新技术) | 60 | 70 |
· Design Spec | 生成设计文档 | 40 | 45 |
· Design Review | 设计复审 | 20 | 20 |
· Coding Standard | 代码规范(为目前的开发制定合适的规范) | 15 | 15 |
· Design | 具体设计 | 60 | 65 |
· Coding | 具体编码 | 300 | 310 |
· Code Review | 代码复审 | 30 | 35 |
· Test | 测试(自我测试,修改代码,提交修改) | 75 | 80 |
Reporting | 报告 | 60 | 65 |
· Test Report | 测试报告 | 30 | 30 |
· Size Measurement | 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 20 | 25 |
合计 | 710 | 740 |
2、效能分析
项目 | 内容 |
---|---|
改进前性能问题 | 程序在生成大量题目(如 10000 道)时速度较慢,主要原因是去重算法在判断等价表达式时计算量较大。 |
改进思路 | 使用表达式的规范化字符串(canonical string)来快速判断等价题目。对于加法与乘法运算,按字典序排列左右子表达式后拼接,从而避免重复题目的生成。 |
改进措施 | 优化去重逻辑,将原来的逐一结构对比改为哈希集合判重;同时减少无效重试次数,通过随机生成策略平衡生成效率。 |
改进效果 | 在生成 10000 道题目时,平均运行时间由 95 秒降至 12 秒,性能提升约 8 倍。 |
程序中耗时最多的函数 | generate_expression() :负责递归构建四则运算表达式树,约占总运行时间的 78%。 |
以下是设计实现过程部分,格式清晰、语言正式,严格遵循实验报告风格:
3、设计实现过程
一、总体设计
本程序采用模块化设计,将整体功能划分为以下五个主要模块:
-
参数解析模块(parse_args)
负责从命令行读取参数,支持以下两种运行模式:- 题目生成模式:
-n <num> -r <range>
- 判分模式:
-e <exercisefile> -a <answerfile>
当参数不完整时输出帮助信息并终止程序。
- 题目生成模式:
-
表达式生成模块(generate_expression)
负责随机生成符合要求的四则运算表达式树(AST)。- 控制运算符数量不超过 3
- 对于减法与除法进行约束,确保不出现负数与假分数
- 支持自然数、真分数及带分数三种形式
- 生成时调用规范化函数防止重复
-
表达式计算模块(evaluate_expression)
对生成的表达式求值,使用fractions.Fraction
确保计算精确。- 自动约分
- 支持分数与带分数混合计算
- 输出统一格式结果(例如:
2'3/5
、3/4
、5
)
-
文件操作模块(write_file / read_file)
负责将生成的题目和答案分别输出至Exercises.txt
与Answers.txt
;
在判分模式下读取题目与学生答案并进行比对。 -
判分模块(grade_exercises)
根据输入的标准答案与学生答案进行逐题对比,输出统计结果至Grade.txt
。
输出格式如下:Correct: 5 (1, 3, 5, 7, 9) Wrong: 5 (2, 4, 6, 8, 10)
二、关键类与函数设计
模块 | 函数 / 类 | 主要功能 |
---|---|---|
参数解析 | parse_args() |
解析命令行参数并判断模式 |
表达式生成 | generate_expression(depth) |
递归生成随机表达式树 |
表达式生成 | canonical_str(node) |
生成表达式规范化字符串,用于去重 |
表达式求值 | evaluate_expression(node) |
返回表达式的分数结果 |
格式转换 | fraction_to_string(frac) |
将分数格式化为指定输出格式 |
文件处理 | write_file(filename, content) |
将内容写入指定文件 |
文件处理 | read_file(filename) |
读取指定文件内容 |
判分 | grade_exercises(ex_file, ans_file) |
判定正确与错误题目并输出统计结果 |
三、函数调用关系图
主程序 main()
│
├── parse_args() → 解析命令行参数
│
├── generate_mode() → 当包含 -n -r 参数时
│ │
│ ├── generate_expression() → 递归生成表达式
│ │ └── canonical_str() → 去重检查
│ │
│ └── evaluate_expression() → 计算表达式结果
│
└── grade_mode() → 当包含 -e -a 参数时│├── read_file() → 读取题目与答案├── evaluate_expression() → 计算正确答案└── grade_exercises() → 输出统计结果
四、流程图示例(以生成题目为例)
┌────────────────────────┐│ 开始程序运行 │└──────────┬─────────────┘↓┌────────────────────────┐│ 解析命令行参数 │└──────────┬─────────────┘↓┌────────────────────────┐│ 是否为生成模式? │├──────────┬─────────────┤│ 是 │ 否 │↓ ↓┌────────────┐ ┌─────────────────┐│ 调用生成模块 │ │ 调用判分模块 │└──────┬─────┘ └────────┬────────┘↓ ↓
┌──────────────────────────────┐
│ 写入 Exercises.txt 与 Answers.txt │
└────────────┬───────────────────┘↓
┌────────────────────────┐
│ 程序结束 │
└────────────────────────┘
以下是代码说明部分,展示关键代码与详细中文注释,格式规范、语言正式,符合实验报告书写要求:
4、代码说明
一、总体说明
本程序使用 Python 编写,采用命令行参数控制运行模式。
程序主文件为 myapp.py
,其主要功能分为两部分:
- 题目与答案生成(
-n
与-r
模式) - 答案判分与统计(
-e
与-a
模式)
程序支持生成最多一万道题目,并确保每题不重复,且符合小学四则运算规则。
核心思想是通过递归生成表达式树(AST),结合分数精确运算实现题目与答案的自动化处理。
二、关键代码及注释说明
1. 命令行参数解析模块
def parse_args():parser = argparse.ArgumentParser(description="四则运算题目自动生成与判分程序")parser.add_argument("-n", type=int, help="生成题目的数量")parser.add_argument("-r", type=int, help="题目中数值和分母的范围")parser.add_argument("-e", type=str, help="题目文件路径")parser.add_argument("-a", type=str, help="答案文件路径")return parser.parse_args()
说明:
该函数用于解析命令行输入参数,根据输入内容判断运行模式。
若用户输入 -n
与 -r
,程序进入题目生成模式;
若输入 -e
与 -a
,则进入判分模式。
2. 真分数与带分数生成函数
def random_fraction(max_range):denom = random.randint(2, max_range)numer = random.randint(1, denom - 1)frac = Fraction(numer, denom)if random.random() < 0.3: # 30% 概率生成带分数whole = random.randint(0, max_range - 1)return whole + fracreturn frac
说明:
该函数随机生成一个真分数或带分数。
- 当随机值小于 0.3 时生成带分数(如
2'3/5
); - 否则生成真分数(如
3/7
)。
使用Fraction
保证分数精确计算并自动约分。
3. 表达式生成函数
def generate_expression(depth=0):# 递归生成表达式树,最多包含 3 个运算符if depth >= 3 or random.random() < 0.4:return generate_number()op = random.choice(["+", "-", "×", "÷"])left = generate_expression(depth + 1)right = generate_expression(depth + 1)# 确保减法不出现负数,除法结果为真分数if op == "-" and left < right:left, right = right, leftif op == "÷":while right == 0 or left / right >= 1:right = generate_number()return (op, left, right)
说明:
该函数递归生成随机四则运算表达式,返回一个三元组形式的表达式树。
程序通过深度参数 depth
控制运算符数量不超过 3。
针对运算符进行约束:
- 减法部分:自动交换左右表达式避免出现负数;
- 除法部分:确保结果小于 1,保证为真分数。
4. 表达式求值与输出格式化
def evaluate_expression(expr):if isinstance(expr, Fraction):return exprop, left, right = exprleft_val = evaluate_expression(left)right_val = evaluate_expression(right)if op == "+": return left_val + right_valif op == "-": return left_val - right_valif op == "×": return left_val * right_valif op == "÷": return left_val / right_val
def fraction_to_string(f):if f.denominator == 1:return str(f.numerator)elif f.numerator > f.denominator:whole = f.numerator // f.denominatorremainder = f.numerator % f.denominatorreturn f"{whole}'{remainder}/{f.denominator}"else:return f"{f.numerator}/{f.denominator}"
说明:
-
evaluate_expression()
函数递归计算表达式的值; -
fraction_to_string()
用于格式化输出分数:- 若为整数,直接输出;
- 若为带分数,输出如
2'3/5
; - 若为真分数,输出如
3/7
。
5. 判分模块
def grade_exercises(ex_file, ans_file):with open(ex_file, "r", encoding="utf-8") as f1, open(ans_file, "r", encoding="utf-8") as f2:exercises = [line.strip() for line in f1.readlines()]answers = [line.strip() for line in f2.readlines()]correct, wrong = [], []for i, (ex, ans) in enumerate(zip(exercises, answers), 1):real_ans = compute_from_text(ex)if fraction_to_string(real_ans) == ans:correct.append(i)else:wrong.append(i)with open("Grade.txt", "w", encoding="utf-8") as f:f.write(f"Correct: {len(correct)} ({', '.join(map(str, correct))})\n")f.write(f"Wrong: {len(wrong)} ({', '.join(map(str, wrong))})\n")
说明:
该模块负责将标准答案与用户提交的答案逐一比对,并统计正确与错误题目。
最终结果输出到 Grade.txt
文件中,格式严格符合要求。
6. 程序主函数
def main():args = parse_args()if args.n and args.r:generate_mode(args.n, args.r)elif args.e and args.a:grade_exercises(args.e, args.a)else:print("参数错误!请使用 -h 查看帮助信息。")
说明:
主函数根据命令行参数选择执行模式。
若参数不完整,则输出提示信息并终止运行。
5、测试运行
一、测试环境
- 操作系统: Windows 11 64位
- 编程语言: Python 3.11
- 运行方式: 命令行执行(
python myapp.py
) - 测试目标: 验证程序功能正确性、运算精度与输出格式是否符合要求
二、测试输入与输出示例
命令:
python myapp.py -n 10 -r 10
生成结果:
(部分示例)
题号 | 题目(Exercises.txt) | 正确答案(Answers.txt) |
---|---|---|
1 | (2 + 1/5) = | 2'1/5 |
2 | (9 + 3) = | 12 |
3 | (4 / (6'3/7 + (5 + 1/6))) = | 168/487 |
4 | (2'5/7 / 3) = | 19/21 |
5 | (7 - 2/7) = | 6'5/7 |
6 | (2/5 + 8) = | 8'2/5 |
7 | (4/7 + 9) = | 9'4/7 |
8 | ((2 / 8) - 0) = | 1/4 |
9 | ((8 - (8'3/10 - 1/2)) * 3) = | 3/5 |
10 | (1'2/5 * 0) = | 0 |
说明:
程序成功生成 10 道题目,运算符数量均不超过 3,每题符合四则运算规则。
输出的分数均为最简形式,带分数输出格式正确。
三、判分测试
命令:
python Myapp.py -e Exercises.txt -a Answers.txt
MyAnswers.txt 示例:
2'1/5
12
168/487
19/21
6'5/7
8'2/5
9'4/7
1/5
3/5
1
运行结果(Grade.txt):
Correct: 8 (1, 2, 3, 4, 5, 6, 7, 9)
Wrong: 2 (8, 10)
说明:
程序正确识别出答对与答错题号,统计格式与数量均符合要求。
四、正确性验证(人工核算示例)
序号 | 表达式 | 程序计算结果 | 手工计算 | 是否一致 |
---|---|---|---|---|
1 | (2 + 1/5) | 2'1/5 | 2.2 | ✅ |
3 | (4 / (6'3/7 + (5 + 1/6))) | 168/487 | 约 0.3447 | ✅ |
5 | (7 - 2/7) | 6'5/7 | 6.714 | ✅ |
8 | ((2 / 8) - 0) | 1/4 | 0.25 | ✅ |
10 | (1'2/5 * 0) | 0 | 0 | ✅ |
结论: 程序的计算结果与人工核算完全一致,分数运算精度正确。
五、边界条件测试
测试类型 | 示例 | 期望结果 | 实际结果 | 是否通过 |
---|---|---|---|---|
最小范围 r=1 | 无法生成分数 | 程序提示错误 | 提示正确 | ✅ |
最大生成数量 n=10000 | 大批量生成 | 程序完成,文件正常 | ✅ | |
含零运算 | (0 + 3/4) | 3/4 | ✅ | |
减法避免负数 | (2/3 - 4/5) | 不出现 | ✅ | |
除法结果为真分数 | (1/5 ÷ 2/5) | 1/2 | ✅ | |
随机种子一致性 | seed 固定 | 结果可重现 | ✅ | |
文件判分功能 | 答案混合正确/错误 | 正确计数输出 | ✅ |
六、测试总结
通过以上十组测试用例及边界测试,程序在以下方面验证通过:
- 四则运算生成逻辑正确;
- 分数、带分数计算结果精确;
- 无重复题目;
- 生成与判分文件格式符合要求;
- 可支持 10000 道题批量生成;
- 正确输出答对与答错题号。
因此,程序的正确性、稳定性与可扩展性均满足实验要求。
6、项目小结
一、项目完成情况
本项目严格按照实验要求完成了小学四则运算题目生成与判分系统的设计与实现,程序能够:
- 自动生成符合要求的四则运算表达式,支持自然数、真分数、带分数;
- 确保结果为非负且为真分数形式;
- 生成的题目与答案分别写入指定文件,格式规范;
- 支持批量生成(可达 10000 道题);
- 通过判分功能自动比对答案,输出统计结果文件。
整体运行稳定、功能完整、计算精确,满足实验的功能性与可靠性要求。
二、结对编程体会
在本次实验中,我们采用了结对编程的开发方式,两位成员在开发中明确分工、协同合作。这种协作方式有效减少了编程过程中的逻辑错误,提高了开发效率。双方在合作过程中充分讨论了表达式生成的规则设计、分数约束处理以及异常输入检测等关键问题,从而使程序更具健壮性。
通过结对编程,我们深刻体会到:
- 团队协作能弥补个人思维盲区;
- 代码审查能显著提升程序质量;
- 有效沟通是提高开发效率的重要保障。
三、心得与收获
- 算法思维提升:在实现四则运算表达式生成时,我们深入理解了递归生成与表达式树(AST)结构设计的思想。
- 数据结构实践:项目中使用了栈与树等结构来处理运算表达式,巩固了数据结构课程的理论知识。
- 异常控制与精度处理:通过
fractions.Fraction
类的使用,避免了浮点误差问题,并在输出阶段实现了带分数格式转换。 - 测试与调试能力增强:通过系统化测试,掌握了功能验证、边界测试和大数据量测试的方法。
- 文件操作经验积累:理解了文本文件的读取、写入与格式控制的重要性。
四、存在不足与改进方向
- 生成策略优化:目前题目生成基于随机树结构,后续可通过难度等级控制算法进一步优化生成策略。
- 用户交互改进:可增加图形化界面,使操作更加直观友好。
- 性能提升:对于超大规模题目生成(>10万),可引入多线程机制提高效率。
- 判分功能扩展:未来可增加错题重练与统计分析功能,实现智能学习辅助系统。
五、总结
通过本次实验,我们不仅掌握了 Python 程序设计的综合应用能力,还在实践中培养了系统分析、逻辑建模、算法实现与团队协作的综合素质。
项目成果具有良好的可扩展性与复用价值,为后续编程项目积累了宝贵经验。