软工第三次作业-结对作业

姓名:苏麦耶姆·阿卜杜克热木
学号:3223004731
github 地址: https://gitee.com/suzette11/the-third-assignment/tree/master/

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 45 30
- Estimate - 估计这个任务需要多少时间 60 70
Development 开发 180 180
- Analysis - 需求分析(包括学习新技术) 40 30
- Design Spec - 生成设计文档 45 45
- Design Review - 设计复审(和同事审核设计文档) 30 20
- Coding Standard - 代码规范(为目前的开发制定合适的规范) 25 30
- Design - 具体设计 60 90
- Coding - 具体编码 180 300
- Code Review - 代码复审 40 40
- Test - 测试(自我测试,修改代码,提交修改) 40 40
Reporting 报告 60 90
- Test Report - 测试报告 30 30
- Size Measurement - 计算工作量 40 30
- Postmortem & Process Improvement Plan - 事后总结,并提出过程改进计划 20 30
核心方法 功能
init 初始化并自动调用化简方法
simplify 分数化简(处理假分数、负号、公约数)
add/__sub__等 重载运算符,实现分数四则运算
to_string 转换为规定格式字符串(如2'3/8)
parse(静态方法) 从字符串解析为Fraction对象

表达式生成模块

核心函数 功能
generate_expressions(count, range_limit) 生成指定数量的不重复表达式
generate_expression(op_count, range_limit) 递归生成单个表达式(控制运算符数量 1-3 个)
is_valid_expression(expr) 验证表达式合法性(如减法非负、除法有效)
get_expression_fingerprint(expr) 生成表达式 “指纹” 用于去重(标准化后哈希)
normalize_expression(expr) 标准化表达式(移除括号、排序+/×操作数)

计算模块

核心函数 功能
calculate_expression(expr) 计算表达式结果(返回Fraction对象)
infix_to_postfix(infix) 中缀表达式转后缀表达式(Shunting-yard 算法)
evaluate_postfix(postfix) 计算后缀表达式结果(基于栈实现)

依赖关系:
main.py 依赖所有模块,是流程控制中心;
expression_generator.py 依赖 calculator.py(验证表达式合法性)和 fraction.py(生成随机分数);
calculator.py 依赖 fraction.py(所有计算基于Fraction类);
file_operate.py 依赖 calculator.py(验证答案时重新计算正确结果)。

关键函数流程图
image

1.分数类
class Fraction:
def init(self, numerator=0, denominator=1, integer=0):
self.integer = integer # 整数部分
self.numerator = numerator # 分子
self.denominator = denominator # 分母
self.simplify() # 初始化时自动化简

def simplify(self):
    """化简分数,处理假分数为带分数"""
    # 处理分母为0的情况
    if self.denominator == 0:
        raise ValueError("分母不能为0")
    
    # 确保分母为正数
    if self.denominator < 0:
        self.numerator *= -1
        self.denominator *= -1
    
    # 合并整数部分和分数部分(假分数处理)
    total_num = self.integer * self.denominator + self.numerator
    self.integer = 0
    self.numerator = total_num
    
    # 提取整数部分
    if abs(self.numerator) >= self.denominator:
        self.integer = self.numerator // self.denominator
        self.numerator = self.numerator % self.denominator
    
    # 化简分数部分
    if self.numerator != 0:
        gcd_val = self.gcd(abs(self.numerator), self.denominator)
        self.numerator //= gcd_val
        self.denominator //= gcd_val
    
    # 处理整体为0的情况
    if self.integer == 0 and self.numerator == 0:
        self.denominator = 1

@staticmethod
def gcd(a, b):
    """最大公约数计算"""
    while b:
        a, b = b, a % b
    return a

def __add__(self, other):
    """加法运算"""
    # 转换为假分数
    num1 = self.integer * self.denominator + self.numerator
    num2 = other.integer * other.denominator + other.numerator
    den1, den2 = self.denominator, other.denominator
    
    # 通分计算
    new_num = num1 * den2 + num2 * den1
    new_den = den1 * den2
    return Fraction(new_num, new_den)

# 其他运算符实现(减法、乘法、除法)类似

def __ge__(self, other):
    """大于等于比较,确保减法不出现负数"""
    num1 = self.integer * self.denominator + self.numerator
    num2 = other.integer * other.denominator + other.numerator
    return num1 * other.denominator >= num2 * self.denominator

def to_string(self):
    """转换为规定格式的字符串"""
    if self.integer != 0:
        if self.numerator == 0:
            return f"{self.integer}"
        else:
            return f"{self.integer}'{self.numerator}/{self.denominator}"
    else:
        if self.numerator == 0:
            return "0"
        else:
            return f"{self.numerator}/{self.denominator}"

2.表达式生成器
def generate_expression(operator_count, range_limit):
"""递归生成表达式"""
if operator_count == 0:
# 生成数字(自然数或分数)
return generate_number(range_limit)

# 随机选择运算符
op = random.choice(['+', '-', '×', '÷'])

# 分配运算符到左右子表达式
left_ops = random.randint(0, operator_count - 1)
right_ops = operator_count - 1 - left_ops

left_expr = generate_expression(left_ops, range_limit)
right_expr = generate_expression(right_ops, range_limit)

# 处理减法(确保被减数 >= 减数)
if op == '-':
    left_val = evaluate_expression(left_expr)
    right_val = evaluate_expression(right_expr)
    if left_val < right_val:
        left_expr, right_expr = right_expr, left_expr

# 处理除法(确保结果为真分数)
elif op == '÷':
    left_val = evaluate_expression(left_expr)
    right_val = evaluate_expression(right_expr)
    # 检查除法是否合法(结果为分数且除数不为0)
    if not is_valid_division(left_val, right_val):
        return generate_expression(operator_count, range_limit)

# 随机添加括号
if random.random() < 0.3 and left_ops > 0:
    left_expr = f'({left_expr})'
if random.random() < 0.3 and right_ops > 0:
    right_expr = f'({right_expr})'

# 对+和×进行排序,避免重复题目
if op in ['+', '×']:
    # 标准化处理,确保a+b和b+a被视为同一题目
    if should_swap(left_expr, right_expr):
        left_expr, right_expr = right_expr, left_expr

return f"{left_expr} {op} {right_expr}"

3.题目去重机制
def normalize_expression(expr):
"""将表达式标准化,用于去重判断"""
# 移除括号(简化处理)
expr = expr.replace('(', '').replace(')', '')

# 处理加法和乘法的交换性
tokens = expr.split()
if len(tokens) == 3 and tokens[1] in ['+', '×']:
    # 对操作数排序,确保a+b和b+a具有相同的标准化形式
    left, op, right = tokens
    if compare_expressions(left, right) > 0:
        return f"{right} {op} {left}"
return expr

def is_duplicate(expr, existing_exprs):
"""检查表达式是否重复"""
normalized = normalize_expression(expr)
return normalized in existing_exprs
4.答案验证功能
def validate_answers(exercise_file, answer_file):
"""验证答案并生成评分结果"""
correct = []
wrong = []

with open(exercise_file, 'r') as ef, open(answer_file, 'r') as af:
    exercises = [line.strip() for line in ef if line.strip()]
    answers = [line.strip() for line in af if line.strip()]

for i, (exercise, user_answer) in enumerate(zip(exercises, answers), 1):
    # 提取表达式部分
    expr = exercise.split('=')[0].strip()
    # 计算正确答案
    correct_answer = evaluate_expression(expr).to_string()
    # 比较答案
    if user_answer == correct_answer:
        correct.append(i)
    else:
        wrong.append(i)

# 写入评分结果
with open('Grade.txt', 'w') as f:
    f.write(f"Correct: {len(correct)} ({', '.join(map(str, correct))})\n")
    f.write(f"Wrong: {len(wrong)} ({', '.join(map(str, wrong))})\n")

性能分析图表

函数名 调用次数 累计时间 (秒) 占比
normalize_expression 45218 8.23 32.1%
evaluate_expression 38762 6.57 25.7%
generate_expression 15623 4.12 16.1%
Fraction.simplify 98342 3.26 12.7%
is_duplicate 10000 1.89 7.4%
其他函数 - 1.52 6.0%

总结
采用 "实现一个功能,测试一个功能" 的策略,例如先完成分数类,通过单元测试验证后再开发表达式生成,降低了集成风险。
通过性能分析工具定位瓶颈(去重和计算占 80% 耗时),针对性优化而非盲目重构,提升了优化效率。

posted @ 2025-10-21 00:35  sumayya  阅读(13)  评论(0)    收藏  举报