结对项目

软件工程第二周作业

这个作业属于哪个课程 软件工程
这个作业要求在哪里 作业要求
这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序
作业GitHub网址 https://github.com/ww7c/3124001541_project2
巫庆城 3124001541

一、psp表格

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

二、效能分析
测试调用:Project2.exe -n 10000 -r 100
性能分析图由VS 2022的性能分析工具自动生成:

屏幕截图 2026-09-21 234758

函数 CPU 总计 自 CPU
main 53(89.83%) 0
random_expression::getExpression 7(11.86%) 0
random_Fraction::tofraction 4(6.78%) 1.69%
random_num::getnumber 2(3.39%) 0

random_expression::getExpression() 的 CPU 总计为 11.86%,是目前显示的用户函数中 CPU 占用最高的。但getExpression() 本身没有明显耗时,但它调用的函数消耗了 CPU。故可优化其调用的函数random_Fraction::tofraction / random_num::getnumber

优化一:减少 getExpression() 中无意义的转换

Fraction prev_value = random_Fraction::tofraction(nums1);
//初始化运算结果为0
Fraction result (0,1);
//中间存储变量
Fraction temp = prev_value;
//改为
Fraction temp = random_Fraction::tofraction(nums1);

优化二:getnumber()中把随机引擎改成 static:

int random_num::getnumber(int max)
{
    random_device rd;
    mt19937 gen(rd());

    uniform_int_distribution<> dis(0, max - 1);

    return dis(gen);
}
改为
int random_num::getnumber(int max)
{
    static random_device rd;
    static mt19937 gen(rd());

    uniform_int_distribution<> dis(0, max - 1);

    return dis(gen);
}

优化三:程序运行过程中控制台输出占用了较多 CPU 时间,性能分析结果中 std::endl 等输出相关函数占比较高。因此首先减少不必要的调试输出。

优化后:

 运行时间:6.306 s            
getExpression:10.24%    
 tofraction:4.37%          
  getnumber:2.00%              

三、代码设计实现过程

类/模块 主要功能 主要函数
input_parameters 输入参数 void input()
random_num 生成随机整数 getnumber(int max)
random_operator 随机生成四则运算符 getoperator()
Fraction 表示和处理分数 +-*/、比较、约分等
random_Fraction 生成随机分数及进行字符串与分数转换 getFraction(int max)tofraction(string)
random_expression 生成完整算术表达式并计算结果 getExpression(int max)
check 对用户答案进行批改 答案读取、比较、统计

模块关系

input_parameter
       ↓
random_num
       ↓
random_operator
       ↓
random_expression
       ↓
  计算正确答案
       ↓
exercisefile.txt ─────→ 用户填写答案 ─────→ user_answerfile.txt
       │                                  ↓
       └→ proper_answerfile.txt ─────────→ 答案批改
                                          ↓
                                      Grade.txt

四、代码说明
(1)表达式生成

string random_expression::getExpression(int max)
{
	//随机生成运算符数量,范围为1-3
	int operator_count = random_num::getnumber(3) + 1; 
	//生成第一个数
	string nums1 = random_Fraction::getFraction(max);
	Fraction prev_value = random_Fraction::tofraction(nums1);
	//初始化运算结果为0
	Fraction result (0,1);
	//中间存储变量
	Fraction temp = prev_value;
	//表达式变量
	string expression = nums1;
	//存储变量前的运算符号
	string prev_op = "+";

	for(int i=0;i<operator_count;i++)
	{
		string next_op = random_operator::getoperator();//随机生成运算符
		//生成下一个数
		string nums2= random_Fraction::getFraction(max);
		Fraction next_value = random_Fraction::tofraction(nums2);
      //后面符号判定代码
    }

getExpression() 是程序的核心函数。首先调用random_num、random_Fraction和random_operator模块生成表达式中的各个部分,然后使用 tofraction 函数转为fraction型的数据,再进行相应的计算。

(2)重构运算符

//重构运算符
//分数加法
Fraction Fraction::operator+(const Fraction& other) const {
	int new_numerator = numerator * other.denominator + other.numerator * denominator;
	int new_denominator = denominator * other.denominator;
	Fraction result(new_numerator, new_denominator);
	return result;
}
//分数减法
Fraction Fraction::operator-(const Fraction& other) const {
	int new_numerator = numerator * other.denominator - other.numerator * denominator;
	int new_denominator = denominator * other.denominator;
	Fraction result(new_numerator, new_denominator);
	return result;
}	
//分数乘法
Fraction Fraction::operator*(const Fraction& other) const {
	int new_numerator = numerator * other.numerator;
	int new_denominator = denominator * other.denominator;
	Fraction result(new_numerator, new_denominator);
	return result;
}
//分数除法
Fraction Fraction::operator/(const Fraction& other) const {
	int new_numerator = numerator * other.denominator;
	int new_denominator = denominator * other.numerator;
	Fraction result(new_numerator, new_denominator);
	return result;
}	
//分数比较
bool Fraction::operator<(const Fraction& other) const {
	return numerator * other.denominator < denominator * other.numerator;
}

bool Fraction::operator==(const Fraction& other)const {
	return numerator * other.denominator == denominator * other.numerator;
}

对fraction型数据的运算符进行重构,用于后面运算符优先性判定、结果计算。

(3)答案批改

    // 比较两个 Fraction
    if (proper == user)
    {
        // 答案正确
        correctCount++;

        if (!correctQuestions.empty())
        {
            correctQuestions += ", ";
        }

        correctQuestions += to_string(questionNumber);
    }
    else
    {
        // 答案错误
        wrongCount++;

        if (!wrongQuestions.empty())
        {
            wrongQuestions += ", ";
        }

        wrongQuestions +=to_string(questionNumber);
    }
}
else
{
    // 用户没有填写答案
    wrongCount++;

    if (!wrongQuestions.empty())
    {
        wrongQuestions += ", ";
    }

    wrongQuestions += to_string(questionNumber);
}

批改模块逐行读取标准答案和用户答案,并按照题目顺序进行比较。如果两行答案相同,则记录为正确,否则记录为错误,最后生成 Grade.txt。

五、测试运行

编号 测试内容 输入/操作 预期结果
1 生成少量题目 Myapp.exe -n 10 成功生成10道四则运算题目
2 生成1道题 Myapp.exe -n 1 成功生成1道题目,程序正常结束
3 生成100道题 Myapp.exe -n 100 成功生成100道题目,无程序崩溃
4 生成10000道题 Myapp.exe -n 10000 成功生成10000道题目,满足题目数量要求
5 整数运算 随机生成包含整数的题目 操作数格式正确,计算结果正确
6 真分数运算 随机生成包含 1/22/3 等分数的题目 分数格式正确,计算结果正确
7 带分数运算 随机生成包含 1'1/2 等带分数的题目 带分数格式正确,能够正确计算
8 除法运算 随机生成包含 / 的题目 除数不为0,不出现除零情况
9 减法运算 随机生成包含 - 的题目 被减数一定大于减数
10 运算优先级 测试类似 8 - 3 × 2 - 4 的表达式 先计算乘除,再计算加减,运行优先级正确
11 批改正确答案 proper_answerfile文件 + user_answerfile文件 Grade.txt 中正确题数与实际一致
12 批改错误答案 proper_answerfile文件 + 部分错误答案的user_answerfile文件 正确、错误题目分别统计,题号正确
13 用户答案数量不足 user_answerfile文件少于exercise题目数 程序能够识别未提供答案的题目
14 用户答案数量过多 user_answerfile文件多于exercise题目数 程序不会错误地将多余答案判为正确
15 参数错误 输入错误的命令行参数 程序进行参数判断,不正常执行错误功能

六、项目小结
本次结对项目主要完成了小学四则运算题目生成程序的设计与实现。项目采用模块化的方式进行开发,将随机数生成、运算符生成、分数处理、表达式生成以及答案检查等功能分别实现,并通过 Git 对项目代码进行版本管理。

过程难点:
在实现表达式计算过程时需考虑运算符优先性问题,这部分花了较长时间.其次在随机生成表达式时需考虑边界条件,如除数不能为0,被减数需大于减数,随机生成的题目可能重复等问题。

项目中也存在一些不足。开始编写代码时对整体结构考虑得不够充分,没有在表达式生成中实现括号()这一符号。项目实现没有用图形化界面展示出来

当然通过这次项目作业,提升我在开发过程对整体结构划分的能力,积累了完成相应的模块划分,功能实现整合这些方面的经验。

posted @ 2026-09-22 00:22  www7c  阅读(12)  评论(0)    收藏  举报