结对项目作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/homework/13479
这个作业的目标 了解结对项目开发,增强协同开发能力

1.项目信息

GitHub地址

https://github.com/1728391408/Pair-work

成员姓名 成员学号
罗锐楚 3123004989
苗新雨 3123004237

2.psp表格

PSP2.1 阶段 阶段说明 预估耗时(分钟) 实际耗时(分钟)
Planning(计划) 对整个开发任务的时间规划与估算 25 35
    · Estimate 估计完成该任务所需的总时间 35 35
Development(开发) 软件开发的核心执行环节 500 640
    · Analysis 需求分析(含新技术学习、需求梳理等) 65 85
    · Design Spec 生成详细的设计文档(如架构设计、模块设计等) 55 55
    · Design Review 设计文档复审(检查设计合理性、可行性等) 35 35
    · Coding Standard 制定适配当前项目的代码规范(命名、格式等) 25 25
    · Design 具体设计(如接口设计、数据库设计、算法设计等) 45 55
    · Coding 按照设计与规范进行具体编码实现 195 220
    · Code Review 代码复审(检查代码质量、规范性、逻辑正确性等) 55 55
    · Test 测试(含自我测试、Bug修复、版本提交等) 100 110
Reporting(报告) 开发完成后的总结与复盘 35 35
    · Test Report 编写测试报告(含测试用例、结果、问题总结等) 20 25
    · Size Measurement 计算项目工作量(如代码行数、功能点等) 30 30
    · Postmortem & Process Improvement Plan 事后总结(分析问题与经验)并制定过程改进计划 20 40
合计 所有阶段耗时总和 1240 1480

三、效能分析

1. 性能优化耗时

生成1000道题目,测试各个函数的调用次数和花费的时间。

3e55304c74b1c407184b80058ce043c0

通过得到的函数调用次数和运行时间,我们可以得到:

主要的性能瓶颈集中于

题目生成相关

generate_single_problem: 0.188秒
_generate_expression: 0.108
generate_number: 0.080秒
_is_valid: 0.065秒

这主要是由于生成1000道题目需要5108次尝试,重复率高达80%,每次尝试都需要完整的表达式生成和验证流程。

计算相关

calculate: 0.075秒
eval_recursive: 0.068秒

随机数生成

其中随机数相关函数被调用超过10万次,占用了相当比例的CPU时间。

2. 优化思路

通过修改关键代码来优化效能:
通过数值池预计算,预先计算所有可能的合法数值并缓存起来以避免重复生成和验证相同数值。
更加智能的表达式生成,通过数值兼容性选择和运算符安全选择减少无效尝试,提前过滤不安全操作。
同时系统在多个层次引入缓存如表达式、分数、计算结果。
在快速验证方面,通过分层验证,先进行廉价检查再进行昂贵计算
对于大批量题目生成,引入模板化方法,预生成常见模式,减少随机尝试次数

3. 性能分析图

image

消耗最大的函数:ProblemGenerator._is_valid(占总耗时 35%),该函数需调用Calculator.calculate验证表达式合法性,是题目生成的核心校验环节,优化后通过缓存常见合法表达式结果,耗时降低 15%。

四、设计实现过程

1. 代码组织架构

类名 所在文件 核心功能 依赖类
ArgParser arg_parser.py 命令行参数解析(生成/校验模式) -
Fraction fraction.py 分数的存储、化简与四则运算 -
Calculator calculator.py 表达式递归计算(含括号优先级) Fraction
ProblemGenerator problem_generator.py 题目生成与去重 Calculator, Fraction, DuplicateChecker
FileHandler file_handler.py 文件读写与答案校验 Calculator
DuplicateChecker problem_generator.py 题目去重(标准化表达式) -

2. 核心流程设计

(1)题目生成流程

image

(2)答案校验

image

五、代码说明

1. 核心类代码(Fraction 类)

class Fraction:
    def __init__(self, numerator, denominator=1, integer=0):
        """初始化分数:整数部分、分子、分母"""
        self.integer = integer  # 带分数整数部分
        self.numerator = numerator  # 分子
        self.denominator = denominator  # 分母
        self._simplify()  # 初始化时自动化简

    def _simplify(self):
        """化简分数:假分数转带分数,约分(最大公约数)"""
        if self.denominator == 0:
            raise ZeroDivisionError("分母不能为0")
        
        # 假分数转带分数(分子≥分母时)
        if self.numerator >= self.denominator:
            self.integer += self.numerator // self.denominator
            self.numerator = self.numerator % self.denominator
        
        # 约分(通过最大公约数)
        gcd_val = self._gcd(abs(self.numerator), self.denominator)
        if gcd_val != 0:
            self.numerator //= gcd_val
            self.denominator //= gcd_val

    @staticmethod
    def _gcd(a, b):
        """计算最大公约数(欧几里得算法)"""
        while b:
            a, b = b, a % b
        return a

    def __sub__(self, other):
        """减法重载:确保结果非负(符合需求3)"""
        if isinstance(other, int):
            other = Fraction(other)
        # 转为假分数计算
        self_total = self.integer * self.denominator + self.numerator
        other_total = other.integer * other.denominator + other.numerator
        if self_total < other_total:
            raise ValueError("减法结果不能为负数")  # 触发重试生成
        new_denominator = self.denominator * other.denominator
        new_numerator = self_total * other.denominator - other_total * self.denominator
        return Fraction(new_numerator, new_denominator)

    def __truediv__(self, other):
        """除法重载:确保结果为真分数(符合需求4)"""
        if isinstance(other, int):
            other = Fraction(other)
        other_total = other.integer * other.denominator + other.numerator
        if other_total == 0:
            raise ZeroDivisionError("除数不能为0")
        # 乘以倒数
        reciprocal = Fraction(other.denominator, other.numerator, other.integer)
        result = self * reciprocal
        # 检查是否为真分数
        if result.numerator % result.denominator == 0:
            raise ValueError("除法结果必须为真分数")  # 触发重试生成
        return result

    @staticmethod
    def from_str(s):
        """从字符串解析分数(支持自然数、真分数、带分数)"""
        if "'" in s:
            # 带分数(如2'3/8)
            integer_part, frac_part = s.split("'")
            numerator, denominator = map(int, frac_part.split("/"))
            return Fraction(numerator, denominator, int(integer_part))
        elif "/" in s:
            # 真分数(如3/5)
            numerator, denominator = map(int, s.split("/"))
            return Fraction(numerator, denominator)
        else:
            # 自然数(如5)
            return Fraction(int(s), 1)

题目去重核心代码(DuplicateChecker 类)

class DuplicateChecker:
    def __init__(self):
        self.generated_set = set()  # 存储标准化后的表达式

    def is_duplicate(self, expr):
        """判断题目是否重复:标准化后比对"""
        standard_expr = self._standardize(expr)
        if standard_expr in self.generated_set:
            return True
        self.generated_set.add(standard_expr)
        return False

    def _standardize(self, expr):
        """标准化表达式:去空格、去括号、按交换律排序"""
        # 去空格和括号
        expr = expr.replace(" ", "").replace("(", "").replace(")", "")
        
        # 加法交换律:拆分后排序(如“3+2”→“2+3”)
        if '+' in expr and not ('-' in expr or '×' in expr or '÷' in expr):
            terms = sorted(expr.split('+'))
            return '+'.join(terms)
        
        # 乘法交换律:拆分后排序(如“6×8”→“8×6”)
        if '×' in expr and not ('-' in expr or '+' in expr or '÷' in expr):
            terms = sorted(expr.split('×'))
            return '×'.join(terms)
        
        # 多运算符场景:保持原顺序(如“1+2×3”不排序)
        return expr

六、测试运行

image

测试用例

1.参数解析测试(-n 和 -r)

运行命令 python main.py -n 10 -r 20。期望程序正确解析参数,生成10道题目,数值范围在20以内。
结果:程序成功生成题目,题目数量和数值范围均符合预期。

2.参数解析测试(-e 和 -a)

运行命令 python main.py -e exercises.txt -a answers.txt。期望程序正确解析参数,进入答案校验模式,读取指定文件进行答案校验。
结果:程序成功读取文件并完成答案校验,输出校验结果。

3.无效参数处理测试

运行命令 python main.py -n 10(缺少-r参数)。期望程序提示参数错误,要求提供完整的参数。
结果:程序正确提示参数错误,指引用户提供完整参数。

4.题目数量准确性测试

使用 ProblemGenerator 生成5道题目。期望成功生成5道题目,每道题目均以“=”结尾。
结果:生成的题目数量准确,格式正确。

5.数值范围控制测试

设置数值范围为5,生成题目并检查所有数值。期望题目中的所有数值均在5以内。
结果:所有数值均符合范围要求,无超出情况。

6.无负数结果测试

生成20道题目,计算结果并检查是否为负数。期望所有题目结果均为非负数。
结果:所有计算结果均非负,符合要求。

7.除法产生真分数测试

生成50道题目,检查除法运算结果。期望除法运算结果均为真分数或带分数的真分数部分。
结果:除法运算结果均符合真分数要求。

8.运算符数量限制测试

生成50道题目,检查每道题目中的运算符数量。期望每道题目中的运算符数量不超过3个。
结果:所有题目的运算符数量均在限制范围内。

9.题目不重复测试

使用 DuplicateChecker 生成20道题目,检查是否有重复。期望所有题目均不重复。
结果:题目均无重复,通过标准化检查。

10.大规模生成支持测试

使用 ProblemGenerator 生成1000道题目。期望成功生成1000道题目,程序运行稳定。
结果:程序成功生成题目,运行稳定,无崩溃或卡顿。

11.文件读写功能测试

创建临时文件,写入测试题目和答案,然后读取并验证。期望文件读写功能正常,数据一致。
结果:文件读写功能正常,数据完全一致。

12.答案检查功能测试

创建测试题目文件和答案文件,故意设置一个错误答案,运行答案检查功能。期望正确识别正确和错误答案。
结果:程序正确识别出2个正确答案和1个错误答案。

13.分数计算准确性测试

测试分数的加法、减法、乘法和除法运算。期望计算结果准确,符合分数运算规则。
结果:所有分数运算结果均正确。

14.表达式标准化测试

使用 DuplicateChecker 对表达式进行标准化处理,检查交换律和结合律的处理。期望标准化后的表达式能够正确识别等价表达式。
结果:标准化功能正常,能够正确识别等价表达式。

15.错误处理测试

测试程序对无效表达式(如除零、负数结果)的处理。期望程序能够正确捕获并处理这些错误。
结果:程序正确捕获并处理了所有测试的错误情况。
通过以上测试用例和验证方法,可以确定程序是正确的,并且能够稳定、高效地生成符合要求的四则运算题目。

posted @ 2025-10-22 11:16  罗锐楚  阅读(20)  评论(0)    收藏  举报