结对作业:小学四则运算题目生成与判卷(Python + 可视化)
- 姓名/学号:翁广驰(3123004409)、关健佳(3121004072)
- Github项目地址:https://github.com/Gucvii/homework
PSP2.1 表格(实现前的预估)(1分)
PSP 阶段 |
预估耗时(分钟) |
计划(评估任务规模与交付物) |
30 |
需求分析(理解题目与约束) |
40 |
设计规格(模块划分与数据结构) |
45 |
设计复审(结对评审) |
20 |
代码规范(类型标注、命名、格式) |
15 |
详细设计(表达式树/生成/解析/判卷) |
60 |
编码实现(核心逻辑与CLI) |
120 |
代码复审(互相走查) |
30 |
测试(单元与端到端) |
60 |
测试报告与总结 |
20 |
工作量度量与过程改进计划 |
20 |
合计 |
460 |
效能分析(3分)
- 改进思路:
- 去重采用“交换 + 与 × 的左右操作数”的规范化签名(不做结合律扁平化),匹配题目对“有限次交换”的定义,显著减少重复冲突。
- 生成阶段对不合法的 - 与 ÷ 做就地校验与重试,避免回溯解析,提高成功率。
- I/O 批量写入
Exercises.txt
与 Answers.txt
,避免频繁磁盘操作。
- 耗时记录:约 40 分钟(包含基准与优化迭代)。
- 性能图:这是优化后的性能图
![截屏2025-10-22 11.16]()
![pipeline]()
![performance]()
设计与实现(5分)
- 代码组织:
arithmetic.py
:
- 表达式模型:
Number(Fraction)
、BinOp(op, left, right)
;Expr = Union[Number, BinOp]
。
- 评估:
evaluate(e) -> Fraction
,使用 fractions.Fraction
保证精确与类型安全。
- 格式化:
format_fraction(Fraction) -> str
,支持整数、真分数、带分数(a’b/c
)。
- 序列化:
expr_to_string(e)
,输出括号与空格,满足题干格式。
- 去重签名:
canonical_sig(e)
,对 +
/×
交换左右操作数并排序,其它运算保持序。
- 生成:
generate_unique_expressions(n, r, max_ops=3)
,满足约束与不重复。
- 解析:
parse_expression_line(line)
与分数解析,支持 a’b/c
、b/c
、整数。
- 文件:
write_exercises_and_answers(...)
、grade(...)
输出 Grade.txt
。
main.py
:CLI 接口,支持 -r
、-n
生成与 -e
-a
判卷。
app.py
:Streamlit 图形界面,含“生成题目 / 判卷统计”两页。
- 关键约束实现:
- 减法子表达式满足
e1 ≥ e2
;除法子表达式结果为真分数 0 < e1 ÷ e2 < 1
。
- 每题运算符个数 ≤ 3;输出与解析采用题干格式与空格规则。
- 不重复判定遵循“仅允许交换 +/× 的左右”规则(与题目示例一致)。
代码说明(4分)
@dataclass(frozen=True)
class Number:value: Fraction@dataclass(frozen=True)
class BinOp:op: strleft: Exprright: Expr# 求值
if e.op == '+': return l + r
if e.op == '-': return l - r
if e.op == '×': return l * r
if e.op == '÷': return l / r
if fr.denominator == 1: return str(fr.numerator)
sign = '-' if fr < 0 else ''
integer = fr.numerator // fr.denominator
remainder = Fraction(fr.numerator % fr.denominator, fr.denominator)
return f"{sign}{integer}’{remainder.numerator}/{remainder.denominator}" if integer else f"{sign}{remainder.numerator}/{remainder.denominator}"
if e.op in ['+', '×']:s1, s2 = sorted([canonical_sig(e.left), canonical_sig(e.right)])return f"({s1}{e.op}{s2})"
测试运行(3分)
- 正确性说明:
- 使用
Fraction
保证四则运算精确无误差;解析与格式化相互可逆,答案与判卷一致。
- 生成阶段保证减法与除法的约束,避免负数与除零;题目不重复由签名集判定。
- 测试用例(节选 10 个):
1/6 + 1/8 =
→ 7/24
2 + 3/4 =
→ 2’3/4
(3 × 1/2) + 1/3 =
→ 5/6
(5 ÷ 8) =
→ 5/8
(3 ÷ 2)
不生成(结果>1),生成器约束生效。
(3 - 5)
不生成(中间负数),生成器约束生效。
1 + 2 + 3
与 3 + (2 + 1)
判为重复;与 3 + 2 + 1
不重复。
0 ÷ 3 =
→ 0
(不会生成,因需真分数,生成器约束生效)。
- 混合数解析:
2’3/8
→ 19/8
。
- 大规模生成:
-r 10 -n 10000
正常完成,且去重与约束保持。
实际耗时记录(1分)
PSP 阶段 |
实际耗时(分钟) |
计划 |
25 |
需求分析 |
45 |
设计规格 |
40 |
设计复审 |
20 |
代码规范 |
10 |
详细设计 |
60 |
编码实现 |
130 |
代码复审 |
30 |
测试 |
70 |
报告与总结 |
30 |
改进计划 |
20 |
合计 |
480 |
项目小结(2分)
- 结对感受:两人分工明确(一人核心逻辑与CLI,另一人GUI与文档)。在签名判重策略上充分讨论并依据题目示例确定“不做结合律扁平化,仅交换 +/× 左右”。
- 闪光点与建议:
- 闪光点:类型标注完整、解析鲁棒、约束严格、界面简洁。
- 建议:后续可增加“自定义操作符权重”“更多括号形态”与更细致的性能图。
使用说明(加分)
- 生成题目:
python main.py -r 10 -n 10
- 当前目录输出:
Exercises.txt
与 Answers.txt
- 判卷统计:
python main.py -e Exercises.txt -a Answers.txt
- 当前目录输出:
Grade.txt
- 图形界面:
streamlit run app.py
- 页面含“生成题目 / 判卷统计”,支持预览与统计输出。
- 图形化界面预览:
![截屏2025-10-22 11.36]()
![截屏2025-10-22 11.36]()
![截屏2025-10-22 11.36]()