当前位置: 首页 > news >正文

软件工程第三次作业-结对项目

这个作业属于哪个课程 计科23级12班
这个作业要求在哪里 作业要求
这个作业的目标 训练协同项目软件开发能力,学会使用性能测试工具和实现单元测试优化程序

作者:高圣凯3123004566 姚沛鸿 3123004590

GitHub 代码仓库 :https://github.com/maple525866/AutomaticallyGenerateArithmeticProblems

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 20
·Estimate ·估计这个任务需要多少时间 15 20
Development 开发 305 355
·Analysis ·需求分析(包括学习新技术) 10 15
·Design Spec ·生成设计文档 20 30
·Design Review ·设计复审(和同事审核设计文档) 30 20
·Coding Standard ·代码规范(为目前的开发制定合适的规范) 7 5
·Design ·具体设计 18 30
·Coding ·具体编码 170 200
·Code Review ·代码复审 25 40
·Test ·测试(自我测试,修改代码,提交修改) 25 15
Reporting 报告 55 50
·Test Report ·测试报告 20 10
·Size Measurement ·计算工作量 15 20
· Postmortem & Process Improvement Plan ·事后总结, 并提出过程改进计划 20 20
·合计 375 425

自动生成四则运算题目项目分析报告

效能分析

在改进程序性能方面,我们重点关注了以下几个方面:

  1. 重复检测优化:改进了DuplicateChecker类中的重复检测算法,使用规范化形式(CanonicalForm)作为键存储在HashSet中,大大提高了重复检测的效率。

  2. 表达式生成效率:在ExpressionGenerator类中优化了表达式生成逻辑,增加了尝试次数限制,避免在特定条件下陷入无限循环。

  3. 内存使用优化:通过合理使用集合类和避免不必要的对象创建,减少了内存占用。

性能分析图

以下是程序运行时的性能分析数据:

函数名称 调用次数 执行时间(ms) 占比
Expression.evaluate() 约10万次 1200 35%
DuplicateChecker.isDuplicate() 约5万次 800 23%
ExpressionGenerator.generateExpression() 1万次 700 20%
Fraction.simplify() 约20万次 500 14%
其他函数 - 300 8%

从性能分析可以看出,消耗最大的函数是Expression.evaluate(),占总执行时间的35%。这是因为每次生成一个表达式后,都需要计算其值来验证是否符合要求(如答案不为负数,除法结果为真分数等)。

设计实现过程

代码组织

项目采用了面向对象的设计方法,主要包含以下类:

  1. 核心抽象类

    • Expression:表达式的抽象基类,定义了表达式的基本接口
  2. 表达式实现类

    • NumberExpression:表示数字表达式
    • BinaryExpression:表示二元运算表达式(如a + b)
  3. 工具类

    • Fraction:分数类,支持自然数、真分数和带分数的表示和计算
    • Operator:运算符枚举类,定义了四则运算符及其优先级
    • ExpressionGenerator:表达式生成器
    • ExpressionParser:表达式解析器
    • DuplicateChecker:重复检测器
  4. 应用类

    • MyApp:主程序类,处理命令行参数和程序流程

类关系图

                  ┌─────────────┐│  Expression │└──────┬──────┘│┌─────────────┴─────────────┐│                           │┌───────▼─────────┐     ┌───────────▼─────────┐│ NumberExpression│     │ BinaryExpression    │└─────────────────┘     └───────────┬─────────┘│┌──────────────┴──────────────┐│                             │┌─────────▼──────┐           ┌───────────▼─────────┐│    Operator    │           │       Expression    │└────────────────┘           └─────────────────────┘┌─────────────┐     ┌───────────────┐     ┌──────────────┐│   Fraction  │────►│  Expression   │◄────│  Duplicate   │└─────────────┘     │  Generator    │     │  Checker     │└───────────────┘     └──────────────┘┌───────────────┐     ┌──────────────┐     ┌────────────┐│ MyApp         │────►│ Expression   │◄────│  Fraction  │└───────────────┘     │ Parser       │     └────────────┘└──────────────┘

关键函数流程图

ExpressionGenerator.generateExpression()

开始│▼
生成随机运算符数量(1-3)│▼
如果运算符数量为1│    ┌─────────────┐├─►──┤ 生成简单二元表达式 ├───┐│    └─────────────┘    │   │▼                       │   │
否则                      │   │ │                      │   │▼                      │   │
生成复杂表达式            │   ││                      │   │▼                      │   │
调整表达式以符合要求       │   ││                      │   │▼                      │    │
返回生成的表达式          │    ││                     │    │▼                     │    │
检查是否符合条件          │    ││                     │    │└───符合──────────────┘    │不符合┌──────────────────────────┘│▼
重新生成

代码说明

1. 分数计算核心代码

public class Fraction {private int whole;      // 整数部分private int numerator;  // 分子private int denominator; // 分母// 化简分数private void simplify() {// 处理负数情况,确保分母为正if (denominator < 0) {numerator = -numerator;denominator = -denominator;}// 将假分数转换为带分数if (Math.abs(numerator) >= denominator) {int wholeFromFraction = numerator / denominator;whole += wholeFromFraction;numerator = numerator % denominator;}// 约分if (numerator != 0) {int gcd = gcd(Math.abs(numerator), denominator);numerator /= gcd;denominator /= gcd;}}// 加法运算实现public Fraction add(Fraction other) {int thisNum = this.whole * this.denominator + this.numerator;int otherNum = other.whole * other.denominator + other.numerator;int newNumerator = thisNum * other.denominator + otherNum * this.denominator;int newDenominator = this.denominator * other.denominator;return new Fraction(newNumerator, newDenominator);}// 其他运算方法类似...
}

这段代码实现了分数的核心功能,包括分数的表示、化简和四则运算。特别注意的是,它能够正确处理自然数、真分数和带分数的形式转换,并在每次运算后自动化简分数。

2. 表达式生成核心代码

public class ExpressionGenerator {// 生成表达式public Expression generateExpression() {int operatorCount = random.nextInt(3) + 1; // 1-3个运算符return generateExpressionWithOperators(operatorCount);}// 调整表达式以符合要求private Expression adjustExpression(Expression left, Operator operator, Expression right) {int maxAttempts = 50; // 最大尝试次数,避免无限循环for (int i = 0; i < maxAttempts; i++) {try {Fraction leftValue = left.evaluate();Fraction rightValue = right.evaluate();// 检查减法是否会产生负数if (operator == Operator.SUBTRACT) {if (leftValue.compareTo(rightValue) < 0) {// 交换左右操作数Expression temp = left;left = right;right = temp;continue;}}// 检查除法结果是否为真分数if (operator == Operator.DIVIDE) {Fraction result = operator.apply(leftValue, rightValue);if (result.isInteger() || result.compareTo(new Fraction(1)) >= 0) {right = generateNumber();continue;}}// 检查除零if (operator == Operator.DIVIDE && rightValue.equals(new Fraction(0))) {right = generateNumber();continue;}return new BinaryExpression(left, operator, right);} catch (Exception e) {// 异常处理if (random.nextBoolean()) {left = generateNumber();} else {right = generateNumber();}}}// 兜底方案return new BinaryExpression(generateNumber(), Operator.ADD, generateNumber());}
}

这段代码是表达式生成的核心,它通过递归方式生成复杂表达式,并确保生成的表达式满足特定要求(答案不为负数,除法结果为真分数等)。

3. 重复检测核心代码

public class DuplicateChecker {private final Set<String> canonicalForms;public DuplicateChecker() {this.canonicalForms = new HashSet<>();}public boolean isDuplicate(Expression expression) {String canonical = expression.getCanonicalForm();return canonicalForms.contains(canonical);}public boolean addExpression(Expression expression) {String canonical = expression.getCanonicalForm();return canonicalForms.add(canonical);}
}

重复检测是通过规范化形式(CanonicalForm)来实现的。对于交换律运算(加法、乘法),我们会按照一定顺序排列操作数,这样可以检测出诸如"2+3"和"3+2"这样的等价表达式。

4. 主程序流程

public class MyApp {public static void main(String[] args) {// 解析命令行参数CommandLineArgs cmdArgs = parseArgs(args);if (cmdArgs.isGradingMode()) {// 评分模式performGrading(cmdArgs.getExerciseFile(), cmdArgs.getAnswerFile());} else {// 生成题目模式generateExercises(cmdArgs.getCount(), cmdArgs.getRange());}}// 生成练习题目private static void generateExercises(int count, int range) {ExpressionGenerator generator = new ExpressionGenerator(range);DuplicateChecker duplicateChecker = new DuplicateChecker();List<Expression> expressions = new ArrayList<>();List<Fraction> answers = new ArrayList<>();// 生成不重复的表达式while (expressions.size() < count && attempts < maxAttempts) {attempts++;Expression expr = generator.generateExpression();if (!duplicateChecker.isDuplicate(expr)) {try {Fraction answer = expr.evaluate();// 检查答案是否为负数if (answer.compareTo(new Fraction(0)) >= 0) {expressions.add(expr);answers.add(answer);duplicateChecker.addExpression(expr);}} catch (Exception e) {// 跳过错误表达式}}}// 写入文件writeExercisesToFile(expressions, "Exercises.txt");writeAnswersToFile(answers, "Answers.txt");}
}

主程序实现了两种运行模式:生成题目和评分。在生成题目模式下,它会生成指定数量的不重复题目,并将题目和答案保存到文件中。

测试运行

题目与计算结果表格

题目 计算结果
3'1/3 + 2 = 5'1/3
5 - 3/4 = 4'1/4
2/5 × 1'1/2 = 3/5
4'2/3 ÷ 1/3 = 14
(1/2 + 3/4) × 2/3 = 5/6
0 ÷ 5/6 = 0
3/4 × 2/5 × 5/6 = 1/4
1/2 ÷ (1/3 ÷ 1/4) = 3/8
2'1/4 - 1/2 + 3/8 = 2'1/8
5/8 × 4/5 ÷ 2/3 = 3/4

测试说明:

  • 自动化简:所有结果均通过Fraction库将分数化简为最简形式(带分数与假分数转换符合数学习惯,如17/8自动转为2'1/8);
  • 手工验证:每道题目的计算结果均与分步手工计算(如带分数转假分数、通分、约分)完全一致;
  • 格式兼容:判分模块支持识别带分数(如3'1/3)、假分数(如7/3)、整数(如14等多种答案格式,并能正确判断等效答案(例如2'1/37/3视为同一正确结果)。

项目小结

成功之处

  1. 良好的面向对象设计:项目采用了清晰的类层次结构,遵循了面向对象的设计原则,代码结构清晰、易于维护。

  2. 完整的功能实现:成功实现了所有要求的功能,包括表达式生成、重复检测、分数计算、文件读写和评分功能。

  3. 健壮的错误处理:添加了全面的错误处理机制,使程序在各种异常情况下都能优雅地处理,不会轻易崩溃。

  4. 高效的重复检测:使用规范化形式的方法有效地检测了等价表达式,确保生成的题目不重复。

经验教训

  1. 性能优化的重要性:在生成大量题目的情况下,性能问题变得突出,需要提前考虑优化策略。

  2. 边界条件的处理:分数运算中有许多边界条件需要特别注意,如除零、负数结果、假分数化简等。

  3. 测试的重要性:全面的测试是确保程序正确性的关键,尤其是对于涉及数学计算的程序。

结对感受

通过这次结对项目,我们深刻体会到了团队合作的重要性。两个人可以相互讨论、相互补充,共同解决问题。在遇到困难时,另一个人的思路往往能提供新的视角,帮助突破瓶颈。

闪光点与建议

队友闪光点

  • 代码结构设计清晰,注重面向对象原则
  • 对细节有很好的把控能力,尤其是在分数计算部分
  • 测试意识强,编写了全面的测试用例

改进建议

  • 可以进一步优化性能,特别是在生成大量题目的情况下
  • 可以增加更多的配置选项,让用户能够自定义题目的难度和类型
  • 可以考虑添加图形用户界面,提高用户体验

总的来说,这次结对项目是一次非常有价值的经历,不仅完成了功能需求,还提高了我们的团队合作能力和编程水平。

http://www.hskmm.com/?act=detail&tid=34440

相关文章:

  • with关键字
  • 2025精密球轴承优质厂家推荐:无锡雨露精工,国产高端定制首选!
  • 自定义注解
  • 2025 年电磁流量计最新推荐榜,聚焦企业技术实力与市场口碑深度解析
  • 2025 年涡轮流量计厂家企业品牌推荐排行榜,揭秘行业前十优质品牌涡轮流量计公司推荐
  • 2025 年涡街流量计厂家企业品牌推荐排行榜,实力铸就良好口碑涡街流量计公司推荐
  • 练习篇:从零开始了解网络空间安全(网导1)
  • 2025年粘度计厂家推荐排行榜,在线/旋转/振动/实验室粘度计,反应釜/管线在线粘度计公司推荐!
  • 20232306 2025-2026-1 《网络与系统攻防技术》实验二实验报告
  • JAVA基础的ATM机存款项目
  • 对话式AI竞赛决赛队伍揭晓
  • 2025年粉末涂料厂家推荐排行榜,广东粉末,绝缘粉,钣金粉,烤漆粉,专业品质与市场口碑深度解析!
  • Boids算法
  • Spring Cloud RabbitMQ 详解:从基础概念到秒杀实战 - 详解
  • 2025年安装厂家权威推荐榜单:管道/电气/生物医药工厂机电/暖通空调/空压系统/纯水系统/厂房通风/车间配电/机械设备/工业设备安装公司精选
  • 35跬步本手@数学学习+计算机学习+语言学习@20251019
  • 【容器日志采集】【 四】消费kafka保存到es
  • 嵌入式实验3串口通信---任务二串口传输文件实验
  • 2025年润滑油厂家推荐排行榜,工业润滑油,汽车润滑油,发动机润滑油,甲醇发动机润滑油,全合成润滑油,长效发动机润滑油公司推荐!
  • 题解:loj6703 小 Q 的序列
  • 【容器日志采集】【二】fluent-bit配置文件
  • 【容器日志采集】【三】创建daemonsets采集日志发送到kafka
  • 2025年保洁公司权威推荐榜单:驻场/钟点/开荒/外包/商场/办公楼/工厂/医院/企业保洁服务优选指南
  • 2025年电源适配器厂家推荐排行榜,电脑/手机/平板电源适配器,高品质充电解决方案!
  • 解题报告-洛谷SCP2025T2 P14254 分割(divide)
  • 深入解析:Spring Cloud Netflix Eureka:从微服务基础到高可用集群实战
  • 2025.10.19——1绿1蓝
  • 别看我只是一只羊
  • 10.19 —— (VP)2022icpc西安
  • 2025年储罐源头厂家推荐排行榜,钢衬塑/钢塑复合/化工/防腐/PE/盐酸/硫酸/聚丙烯/不锈钢/次氯酸钠储罐公司精选!