• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

wswa

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

结对项目

结对项目:四则运算

一.成员与作业要求

姓名 学号 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++的语言来实现,发现实现该项目需要用到几个关键的函数,上文也有提到这三个关键步骤。主要时间花费在技术实现上面,编写函数的时候总出现报错问题,反复改错,花费的时间最多。尽管还不太完善,比如表达式计算的改进等方面。
结对感受:合作过程中,可以共享很多对于该项目的想法,尽管有时候不同,不过总能取长补短,互相理解,最后达成一致。技术上我们也有很多讨论,对于关键技术的实现,在困难点的地方凯明有很多解决思路,思维很敏捷。佳韩能注意到很多细节,是很容易忽略的,很多细节实现帮了大忙。我们都认为实现一个项目,只靠一个人很容易走进死胡同,遇到困难其实一个人很容易放弃,有同伴的话就会有做下去的动力。对于一个大项目,肯定需要更多的人来一起齐心协力去实现。

posted on 2025-03-21 01:48  wswa  阅读(25)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3