题目1:完成一个命令行的四则运算程序

前言

  刚刚看到这个题目的时候,我在想,不就是一个加减乘除的程序么?分分钟就写完了。等我看到需求的时候,我头都大了一圈……。我将需求分成了几个需要解决的问题:

  1:支持分数运算。

  2:表达式生成与计算。

  3:判断正误。

正文

  首先,是如何支持分数运算。既然要支持分数运算,那么肯定要表示分数,所以就要创建一个分数类。而分数和整数是要混合运算的,那么显然,整数其实也是可以表现成分数。于是有了下面的类。在类中对操作符进行重载,便于计算表达式。在运算时自动执行transFrac()成员函数以保证计算后得到分数分子分母都不可再约分,以便输出时判断是按整数输出还是按分数输出。

class Num{
public:
    Num(int numerator=0, int denominator = 1){
        a = numerator;
        b = denominator;
        int p;
        p = (a + b - abs(a - b)) / 2;
        for (int i = 2; i <= p; ++i){
            if (a%i == 0 && b%i == 0){
                a /= i;
                b /= i;
                i = 2;
            }
        }
    }

    int getNume(){
        return a;
    }

    int getDeno(){
        return b;
    }

    void transFrac(Num &fra){
        int p;
        p = (fra.a + fra.b - abs(fra.a - fra.b)) / 2;
        for (int i = 2; i <= p; ++i){
            if (fra.a%i == 0 && fra.b%i == 0){
                fra.a /= i;
                fra.b /= i;
                i = 2;
            }
        }

    }

    Num operator+(const Num rhs){
        Num result;
        result.b = b*rhs.b;
        result.a = a*rhs.b + rhs.a*b;
        transFrac(result);
        return result;
    }

    Num operator-(const Num rhs){
        Num result;
        result.b = b*rhs.b;
        result.a = a*rhs.b - rhs.a*b;
        transFrac(result);
        return result;
    }

    Num operator*(const Num rhs){
        Num result;
        result.a = a*rhs.a;
        result.b = b*rhs.b;
        transFrac(result);
        return result;
    }

    Num operator/(const Num rhs){
        Num result;
        result.a = a*rhs.b;
        result.b = b*rhs.a;
        transFrac(result);
        return result;
    }

    bool operator==(const Num rhs){
        if (a == rhs.a&&b == rhs.b)
            return true;
        else
            return false;
    }

    Num operator=(const int rhs){
        a = rhs;
        b = 1;
        return *this;
    }
    Num operator=(const Num rhs){
        a = rhs.a;
        b = rhs.b;
        return *this;
    }
private:
    int a;
    int b;

};

classNum

  其次,是表达式生成与计算。如果是任意生成的表达式,那么在计算表达式的值的时候,就需要在表达式求值上做大量的工作,如判断优先级,通过栈等转化表达式,最后才是计算得到结果。时间有限,我就使用了比较低端的方法,那就是固定表达式的格式,然后通过分配各个位置上的值和运算符来完成简易的表达式生成,并通过检查结果来判断两个表达式是否重复。将生成的表达式存储在题库中等待完成。

void setProbAndAns(int proNum, int proLevel){
    ofstream ofsQues;
    ofstream ofsAnsw;
    ofsQues.open("Questions.txt", ofstream::out);
    ofsAnsw.open("Answer.txt", ofstream::out);
    char Expression[100];
    char Answer[10];
    srand((unsigned)time(NULL));
    int a, b, c, d, e1, e2, e3;
    Num lhs, rhs, res;
    for (int i = 0; i < proNum; ++i){
        vector<Num>A(proNum);
        vector<Num>B(proNum);
        vector<Num>C(proNum);
        vector<Num>D(proNum);  //4 position of number
        vector<Num>R(proNum);  //result
        a = rand() % proLevel;
        b = rand() % proLevel+1;
        c = rand() % proLevel;
        d = rand() % proLevel+1;
        A[i] = a;
        B[i] = b;
        C[i] = c;
        D[i] = d;

        vector<char>E1(proNum);
        vector<char>E2(proNum);
        vector<char>E3(proNum);
        e1 = rand() % 4;
        e2 = rand() % 2;
        e3 = rand() % 4;

        switch (e1){
        case 0:
            E1[i] = ‘+‘;
            lhs = A[i] + B[i];
            break;
        case 1:
            E1[i] = ‘-‘;
            lhs = A[i] - B[i];
            break;
        case 2:
            E1[i] = ‘*‘;
            lhs = A[i] * B[i];
            break;
        case 3:
            E1[i] = ‘/‘;
            lhs = A[i] / B[i];
            break;
        }
        switch (e3){
        case 0:
            E3[i] = ‘+‘;
            rhs = C[i] + D[i];
            if (e2 == ‘-‘)
                rhs = C[i] - D[i];
            break;
        case 1:
            E3[i] = ‘-‘;
            rhs = C[i] - D[i];
            if (e2 == ‘-‘)
                rhs = C[i] + D[i];
            break;
        case 2:
            E3[i] = ‘*‘;
            rhs = C[i] * D[i];
            break;
        case 3:
            E3[i] = ‘/‘;
            rhs = C[i] / D[i];
            break;
        }
        switch (e2){
        case 0:
            E2[i] = ‘+‘;
            res = lhs + rhs;
            break;
        case 1:
            E2[i] = ‘-‘;
            res = lhs - rhs;
            break;
        }
        if (res.getNume() < 0){
            i -= 1;
            continue;
        }
        else{
            R[i] = res;
        }
        //ganrantee no repeat
        int flag = 0;
        for (int j = 0; j < i; ++j){
            if (R[i] == R[j]){
                flag = 1;
                break;
            }
        }
        if (flag == 1){
            i -= 1;
            continue;
        }

        sprintf_s(Expression, "%d %c %d %c %d %c %d = ", A[i].getNume(), E1[i], B[i].getNume(), E2[i], C[i].getNume(), E3[i], D[i].getNume());
        if (R[i].getDeno() == 1||R[i].getNume() == 0)
            sprintf_s(Answer, "%d:%d", i + 1, R[i].getNume());
        else
            sprintf_s(Answer, "%d:%d/%d", i + 1, R[i].getNume(), R[i].getDeno());

        ofsQues << Expression << endl;;
        ofsAnsw << Answer << endl;
    }

    ofsQues.close();
    ofsAnsw.close();

}

setProblem

  最后,是判断正误。在题库生成的同时,答案也同时生成。此时程序会等待用户在题库中填写答案。填写完毕后输入1得到结果。由于有分数的存在,所以我通过比较题库中=后面略过所有空白符后的字符串与答案:后面的字符串来对比是否正确,正确的题号会被记录,最终格式化输出置Grade文件里保存起来以供用户查看。

void setGrade(int proNum){
    ifstream ifsQus;
    ifstream ifsAns;
    ofstream ofsGra;
    ifsQus.open("Questions.txt",ifstream::in);
    ifsAns.open("Answer.txt",ifstream::in);
    ofsGra.open("Grade.txt",ofstream::app);
    char ques[100];
    char answ[10];
    char grade[500];
    int gra;
    vector<int>right(proNum);
    int i,j;
    int a, b;
    for (i = 0; i < proNum; ++i)
        right[i] = 0;
    for (i = 0,j=0; i < proNum;++i){
        ifsQus.getline(ques, 100);
        ifsAns.getline(answ, 10);
        for (a = 0; ques[a] != ‘=‘; ++a)
            ;
        for (b = a; ques[b] != ‘ ‘; ++b)
            ;
        for (a = 0; answ[a] != ‘:‘; ++a)
            ;

        if (isCorrect(b+1,a+1,ques,answ)){
            j++;
            right[i] = 1;
        }
    }
    vector<int>rightPos(j);
    for (i = 0,j=0; i < proNum; ++i){
        if (right[i] == 1){
            rightPos[j] = i;
            ++j;
        }
    }
    char num[10];
    sprintf_s(grade,"Correct:%d( ",j);
    for (i = 0; i < j; ++i){
        sprintf_s(num,"%d ",rightPos[i]+1);
        strcat_s(grade,num);
    }
    strcat_s(grade, ")");

    ofsGra << grade << endl;
    ifsQus.close();
    ifsAns.close();
    ofsGra.close();
}

setGrade

  在主函数中提供了选项让用户选择生成什么样规模和数量的问题,由于我觉得不会有人一下子做几百道这种题,所以我并没有写出那些离谱的选项,当然程序本身其实是支持生成上千上万道题的(笑)。

int main(void)
{
    int option;
    int proNum;
    int proLevel;

    cout << "Please choose the number of the problem:" << endl;
    cout << "1.10                               2.100" << endl;
    cout << "3.200                              4.500" << endl;
    cin >> option;
    switch (option){
    case 1:
        proNum = 10;
        break;
    case 2:
        proNum = 100;
        break;
    case 3:
        proNum = 200;
        break;
    case 4:
        proNum = 500;
        break;
    default:
        proNum = 50;
        break;
    }
    cout << "Please choose the level of the problem:" << endl;
    cout << "1.10                               2.50" << endl;
    cout << "3.100                                  " << endl;
    cin >> option;
    switch (option){
    case 1:
        proLevel = 10;
        break;
    case 2:
        proLevel = 50;
        break;
    case 3:
        proLevel = 100;
        break;
    default:
        proLevel = 30;
        break;
    }

    setProbAndAns(proNum, proLevel);
    cout << "Please write the  answers in the Questions.txt and save." << endl;
    cout << "Enter 1 to get the Grade" << endl;
    cin >> option;
    while (option != 1){
        cout << "Please enter again:" << endl;
        cin >> option;
    }
    setGrade(proNum);
    cout << "Open the Grade.txt to check your grade!" << endl;
    Sleep(10000);

    return 0;
}

main

  这个程序还有很多很多不完善的地方,尤其是生成表达式和计算表达式那一块,完全可以更好更完善,这就有待以后有时间在github上慢慢改进了(笑)。

  完整程序地址:https://github.com/MorriganMesser/ArithmeticBank

  博客编辑:尉智辉

时间: 2024-11-09 07:34:51

题目1:完成一个命令行的四则运算程序的相关文章

python:执行一个命令行N次

经常希望可以执行一个命令行N次...windows下没有现成的工具(有?推荐给我!) 用python写一个... #!/usr/bin/evn python #coding: utf-8 """ times.py run a command line for n times """ import os import sys import string if __name__ == "__main__": n = 1 cmd =

BCP是SQL Server中负责导入导出数据的一个命令行工具

BCP是SQL Server中负责导入导出数据的一个命令行工具,它是基于DB-Library的,并且能以并行的方式高效地导入导出大批量的数据.BCP可以将数据库的表或视图直接导出,也能通过SELECT FROM语句对表或视图进行过滤后导出.在导入导出数据时,可以使用默认值或是使用一个格式文件将文件中的数据导入到数据库或将数据库中的数据导出到文件中. 下面将详细讨论如何利用BCP导入导出数据. 1. BCP的主要参数介绍 BCP共有四个动作可以选择. (1) 导入. 这个动作使用in命令完成,后面

十分钟通过 NPM 创建一个命令行工具

大过年的,要不要写点代码压压惊?来花十分钟学一下怎么通过 NPM 构建一个命令行工具. 写了一个小 demo,用于代替 touch 的创建文件命令 touchme ,可以创建自带“佛祖保佑”注释的文件.效果如下: 命令可以带有一个参数,选择注释的符号 现在,开始撸代码 ~ 首先创建一个文件夹,我起名字 create-file-cli 然后通过 npm init 命令创建 package.json 文件. $ mkdir create-file-cli $ cd create-file-cli $

显示器 Linux 性能 18 (一个命令行工具传递)

对于系统和网络管理员来说每天监控和调试Linux系统的性能问题是一项繁重的工作.在IT领域作为一名Linux系统的管理员工作5年后,我逐渐认识到监控和保持系统启动并执行是多么的不easy.基于此原因.我们已编写了最常使用的18个命令行工具列表,这些工具将有助于每一个Linux/Unix 系统管理员的工作.这些命令行工具能够在各种Linux系统下使用.能够用于监控和查找产生性能问题的解决办法.这个命令行工具列表提供了足够的工具.您能够挑选适用于您的监控场景的工具. 1.Top-Linux进程监控

分享一个命令行计算器-bc

假如你在一个图形桌面环境中需要一个计算器时,你可能只需要一路进行点击便可以找到一个计算器.例如,Fedora 工作站中就已经包含了一个名为 Calculator 的工具.它有着几种不同的操作模式,例如,你可以进行复杂的数学运算或者金融运算.但是,你知道吗,命令行也提供了一个与之相似的名为 bc 的工具?下面兄弟连为大家做个介绍: bc 工具可以为你提供的功能可以满足你对科学计算器.金融计算器或者是简单计算器的期望.另外,假如需要的话,它还可以从命令行中被脚本化.这使得当你需要做复杂的数学运算时,

Linux中的一个命令行计算器bc简介

假如你在一个图形桌面环境中需要一个计算器时,你可能只需要一路进行点击便可以找到一个计算器.例如,Fedora 工作站中就已经包含了一个名为 Calculator 的工具.它有着几种不同的操作模式,例如,你可以进行复杂的数学运算或者金融运算.但是,你知道吗,命令行也提供了一个与之相似的名为 bc 的工具? bc 工具可以为你提供的功能可以满足你对科学计算器.金融计算器或者是简单计算器的期望.另外,假如需要的话,它还可以从命令行中被脚本化.这使得当你需要做复杂的数学运算时,你可以在 shell 脚本

如何写一个命令行软件?

很久以来我就一直很想用C语言做一个命令行里面的播放器,比如可以播放豆瓣音乐,实现加心.下一曲.切换频道功能.但是一直不知道软件架构如何设计,最近读到了参考文章,感觉收获很多.在此记录下.以后再总结学到的知识. 参考: http://gansteed.github.io/2014/12/12/abstractions-with-c-01/ http://gansteed.github.io/2014/12/18/abstractions-with-c-02/

linux怎么用一个命令行统计出给定目录中有多少个子目录

查看某目录下文件的个数 ls -l |grep "^-"|wc -l 或 find ./company -type f | wc -l 查看某目录下文件的个数,包括子目录里的. ls -lR|grep "^-"|wc -l 查看某文件夹下目录的个数,包括子目录里的. ls -lR|grep "^d"|wc -l 说明: ls -l 长列表输出该目录下文件信息(注意这里的文件,不同于一般的文件,可能是目录.链接.设备文件等) grep "

GitBook是一个命令行工具(Node.js库),我们可以借用该工具使用Github/Git和Markdown来制作精美的图书,但它并不是一本关于Git的教程哟。

支持输出多种格式 GitBook支持输出多种文档格式,如: 静态站点:GitBook默认输出该种格式,生成的静态站点可直接托管搭载Github Pages服务上: PDF:需要安装gitbook-pdf依赖: eBook:需要安装ebook-convert: 单HTML网页:支持将内容输出为单页的HTML,不过一般用在将电子书格式转换为PDF或eBook的中间过程: JSON:一般用于电子书的调试或元数据提取. 结构简单 使用GitBook制作电子书,必备两个文件:README.md和SUMMA