wenzbcoder

导航

 
这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-12
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-12/homework/13221
这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序。
地址 https://github.com/Nethtra/SimpleOperation
成员 温宗宝3122004790 王天一3122004789

1.PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 60 60
· Estimate · 估计这个任务需要多少时间 60 60
Development 开发 900 1040
· Analysis · 需求分析 (包括学习新技术) 240 240
· Design Spec · 生成设计文档 60 60
· Design Review · 设计复审 30 30
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 30
· Design · 具体设计 60 60
· Coding · 具体编码 300 360
· Code Review · 代码复审 60 60
· Test · 测试(自我测试,修改代码,提交修改) 120 200
Reporting 报告 120 120
· Test Repor · 测试报告 30 30
· Size Measurement · 计算工作量 30 30
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 60 60
· 合计 1080 1220

2.性能分析

程序在处理大量数据时,生成题目和批改答案的速度明显变慢,特别是在处理大量分数运算时。
改进思路
1.减少不必要的对象创建:在原始代码中,每次分数运算都会创建新的 FractionNum 对象,而这些对象在完成运算后很快就会被丢弃。我们通过复用对象,减少了垃圾回收的频率,提升了内存使用效率。
2.优化分数运算逻辑:分数加减乘除的计算过程中,我们发现 gcd(最大公约数)运算频繁调用,导致性能下降。因此,我们通过将 gcd 的计算缓存化,减少了重复的运算。
3.减少文件读写操作:文件的写操作较为频繁,特别是在批量生成题目时。我们通过批量写入操作,减少了文件的频繁打开和关闭,提高了 I/O 的效率。
性能分析图示
最耗时的函数:通过分析,我们发现程序中消耗最大的函数是 FractionNum.add()。由于在大量生成题目和批改过程中,加法操作频繁出现,这一函数的调用次数非常高。通过缓存化 gcd 计算的结果后,我们显著减少了该函数的执行时间。
文件写操作的耗时:FileOutputStream.write() 也是一个主要的性能瓶颈。我们通过批量写入数据来减少这一操作的调用次数,优化了文件写入的效率。

3.设计实现过程

核心类:
FractionNum:用于处理分数,包括加减乘除、分解等操作。
Operation 及其子类(如 OperationAdd, OperationSub, OperationMul, OperationDiv):分别处理不同的运算符操作,生成分数的加、减、乘、除表达式。
RandomUnit:生成随机数和随机布尔值,用于生成随机题目。
Result:用于将生成的练习题和答案保存到文件中,并进行批改。
Restrict:限制题目中数值的范围。
Calculator:负责对表达式进行计算。

各类之间通过对象传递数据,调用方法实现题目的生成与计算。其中关键点是通过 FractionNum 类完成分数的运算逻辑封装,保证题目生成和表达式解析的准确性。
关键函数的流程可通过如下步骤表示:
1.获取用户输入,选择生成题目数量和数值范围。
2.随机生成表达式(加减乘除)。
3.解析表达式并计算结果。
4.将练习题和答案保存至文件。
5.对用户的解答进行批改,输出正确与错误的题目

4.关键代码展示

关键代码展示:

public class FractionNum {
    // 分数的加法
    public static FractionNum add(FractionNum a, FractionNum b){
        return new FractionNum(a.numerator * b.denominator + b.numerator * a.denominator, b.denominator * a.denominator);
    }

    // 带分数处理的格式化输出
    @Override
    public String toString() {
        if (isFraction()) {
            if (numerator > denominator) {
                return (numerator / denominator) + "’" + numerator % denominator + "/" + denominator;
            }
            return numerator + "/" + denominator;
        } else {
            return "" + numerator / denominator;
        }
    }
}

在 FractionNum 类中,定义了处理加法和带分数的格式化输出。这样,生成的题目可以直接通过分数的加法逻辑得到结果,并以清晰的格式显示给用户。这个类还包含了其他操作,如减法、乘法、除法的实现。

public class OperationAdd extends Operation {
    public OperationAdd(FractionNum value) {
        FractionNum left = new FractionNum();
        FractionNum right = new FractionNum();
        value.splitFractionAdd(left, right); // 将分数拆分为两个加数
        this.left = new Expression(left);
        this.right = new Expression(right);
    }

    @Override
    public String toString() {
        return this.left.toString() + " + " + this.right.toString();
    }
}

OperationAdd 类用于实现加法运算的生成,自动将分数拆分为左右两部分,并生成最终的题目表达式。

5.测试运行

@Test
    public void basicTest() {
        String[][] argsArray = {
                {"-r", "0", "-n", "1000"},
                {"-r", "-n", "10000"},
                {"-r", "100", "-n", "10000"},
        };
        for (String[] args : argsArray) {
            testCommandParse(args);
        }
    }

6.项目小结

这次项目合作过程中,我们通过合理分工提升了开发效率。遇到的主要挑战是如何让生成的表达式看起来更加自然。通过多次测试和调优,我们逐步改进了算法,确保生成的题目有合理的难度和结构。结对合作过程中,我们学到了互相支持与沟通的重要性。

posted on 2024-09-28 18:29  超级无敌开心癞蛤蟆  阅读(17)  评论(0)    收藏  举报