结对项目
结对项目:四则运算
一.成员与作业要求
姓名 | 学号 | GitHUb地址 |
---|---|---|
李佳韩 | 3123004357 | https://github.com/Ljhwswa/SiZeYunSuan |
吴凯明 | 3123004326 | https://github.com/Ilya469/SiZeYunSuan2# |
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023 |
---|---|
这个作业的要求在哪里 | https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023/homework/13326 |
这个作业的目标 | 体会合作做项目的感受,体会整个项目开发的全过程 |
二.PSP2.1表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 40 | 40 |
· Estimate | · 估计这个任务需要多少时间 | 640 | 810 |
Development | ·开发 | 160 | 240 |
Analysis | ·需求分析 (包括学习新技术) | 30 | 30 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 | 30 | 30 |
Coding Standard | ·代码规范 (为目前的开发制定合适的规范) | 40 | 40 |
· Design | ·具体设计 | 60 | 60 |
· Coding | ·具体编码 | 100 | 180 |
·Code Review | · 代码复审 | 30 | 40 |
·Test | ·测试(自我测试,修改代码,提交修改) | 30 | 30 |
Reporting | 报告 | 30 | 30 |
· Test Repor | ·测试报告 | 10 | 10 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | ·事后总结, 并提出过程改进计划 | 30 | 30 |
· 合计 | 640 | 810 |
三.性能分析
分析:在该项目中,我们发现消耗性能最大的函数时用来实现生成答案的函数,同时在该函数上我们也花了很多心思去设计与实现,这个结果也在我们的预料之中。
四.设计实现过程
1. 代码组织
代码主要分为以下几个部分:
随机数生成器:用于生成随机数、随机分数和随机运算符。
表达式生成:生成随机的数学表达式。
表达式计算:计算生成的表达式的值。
文件操作:生成练习题文件、答案文件,并判断用户答案的正确性。
主函数:解析命令行参数并调用相应的函数。
2. 函数设计
代码中定义了多个函数,每个函数负责一个特定的任务。以下是主要函数及其功能:
(2.1) generateNaturalNumber(int max)
功能:生成一个随机的自然数,范围在 1 到 max-1 之间。
实现:使用 uniform_int_distribution 生成随机数。
(2.2) generateFraction(int max)
功能:生成一个随机的真分数。
实现:生成两个随机数作为分子和分母,确保分子小于分母。
(2.3) generateOperator()
功能:随机生成一个运算符(+, -, *, /)。
实现:从预定义的运算符列表中随机选择一个。
(2.4) generateExpression(int max, int depth = 0)*
功能:生成一个随机的数学表达式。
实现:
递归生成表达式,最多包含3个运算符。
随机选择生成自然数、真分数或子表达式。
确保减法不产生负数,除法结果为真分数。
(2.5) calculateExpression(const string& expr)
功能:计算表达式的值。
(2.6) generateExercisesAndAnswers(int numExercises, int maxNumber, const string& exerciseFile, const string& answerFile)
功能:生成指定数量的练习题和对应的答案,并写入文件。
实现:
使用 generateExpression 生成表达式。
使用 calculateExpression 计算答案。
确保生成的表达式唯一。
(2.7) gradeAnswers(const string& exerciseFile, const string& answerFile, const string& gradeFile)
功能:判断用户答案的正确性并统计结果。
实现:
读取练习题和用户答案。
使用 calculateExpression 计算正确答案。
比较用户答案和正确答案,统计正确和错误的题目。
五.关键代码
1.随机表达式生成
string generateExpression(int max, int depth = 0) {
if (depth >= 3) {
// 最多3个运算符
return to_string(generateNaturalNumber(max));
}
string expr;
int choice = generateNaturalNumber(3); // 随机选择生成自然数或真分数或子表达式
if (choice == 1) {
expr = to_string(generateNaturalNumber(max));
}
else if (choice == 2) {
expr = generateFraction(max);
}
else {
expr = "(" + generateExpression(max, depth + 1) + ")";
}
char op = generateOperator();
string nextExpr = generateExpression(max, depth + 1);
// 确保减法不产生负数
if (op == '-' && expr < nextExpr) {
swap(expr, nextExpr);
}
// 确保除法结果为真分数
if (op == '/' && expr >= nextExpr) {
swap(expr, nextExpr);
}
return expr + " " + op + " " + nextExpr;
}
功能:生成一个随机的数学表达式。
思路:
递归生成表达式,最多包含3个运算符。
随机选择生成自然数、真分数或子表达式。
确保减法不产生负数,除法结果为真分数。
2.生成练习题和答案
void generateExercisesAndAnswers(int numExercises, int maxNumber, const string& exerciseFile, const string& answerFile) {
ofstream exerciseOut(exerciseFile);
ofstream answerOut(answerFile);
set<string> uniqueExercises;
for (int i = 1; i <= numExercises; ++i) {
string expr;
do {
expr = generateExpression(maxNumber);
} while (uniqueExercises.count(expr));
uniqueExercises.insert(expr);
exerciseOut << expr << " =" << endl;
double answer = calculateExpression(expr);
answerOut << fixed << setprecision(2) << answer << endl;
}
}
功能:生成指定数量的练习题和对应的答案,并写入文件。
思路:
使用 generateExpression 生成随机表达式。
使用 set 确保生成的表达式唯一。
使用 calculateExpression 计算表达式的值。
将练习题和答案分别写入 exerciseFile 和 answerFile。
3.判断答案并统计结果
void gradeAnswers(const string& exerciseFile, const string& answerFile, const string& gradeFile) {
ifstream exerciseIn(exerciseFile);
ifstream answerIn(answerFile);
ofstream gradeOut(gradeFile);
vector<int> correct, wrong;
int index = 1;
string expr, answer;
while (getline(exerciseIn, expr) && getline(answerIn, answer)) {
double calculatedAnswer = calculateExpression(expr);
double givenAnswer = stod(answer);
if (abs(calculatedAnswer - givenAnswer) < 1e-6) {
correct.push_back(index);
}
else {
wrong.push_back(index);
}
++index;
}
gradeOut << "Correct: " << correct.size() << " (";
for (size_t i = 0; i < correct.size(); ++i) {
gradeOut << correct[i];
if (i < correct.size() - 1) gradeOut << ", ";
}
gradeOut << ")" << endl;
gradeOut << "Wrong: " << wrong.size() << " (";
for (size_t i = 0; i < wrong.size(); ++i) {
gradeOut << wrong[i];
if (i < wrong.size() - 1) gradeOut << ", ";
}
gradeOut << ")" << endl;
}
功能:判断用户答案的正确性并统计结果。
思路:
读取练习题文件和用户答案文件。
使用 calculateExpression 计算正确答案。
比较用户答案和正确答案,统计正确和错误的题目。
将结果写入** gradeFile**。
6.测试
7.项目小结
在这个项目中我们两个人,考虑了很多东西,从项目开始对整个项目的思考。首先考虑需求的实现,我们用c++的语言来实现,发现实现该项目需要用到几个关键的函数,上文也有提到这三个关键步骤。主要时间花费在技术实现上面,编写函数的时候总出现报错问题,反复改错,花费的时间最多。尽管还不太完善,比如表达式计算的改进等方面。
结对感受:合作过程中,可以共享很多对于该项目的想法,尽管有时候不同,不过总能取长补短,互相理解,最后达成一致。技术上我们也有很多讨论,对于关键技术的实现,在困难点的地方凯明有很多解决思路,思维很敏捷。佳韩能注意到很多细节,是很容易忽略的,很多细节实现帮了大忙。我们都认为实现一个项目,只靠一个人很容易走进死胡同,遇到困难其实一个人很容易放弃,有同伴的话就会有做下去的动力。对于一个大项目,肯定需要更多的人来一起齐心协力去实现。