• 四则运算2及单元测试


    老师又向二柱子提出一些要求,二柱子很崩溃

    具体要求如下:

    1. 题目避免重复
    2. 可定制(数量/打印方式)

    可控制参数
        1是否有乘除法
        2是否有括号
        3数值范围
        4加减法有无负数
        5除法有无余数

    可怜的二柱子经过8h的奋战,终于在01版本的基础上改出了满足要求的02版本

      1 #include <iostream>
      2 #include <iomanip>
      3 #include <fstream>
      4 #include <ctime>
      5 #include <cstdlib>
      6 #include <sstream>
      7 #include <string>
      8 #include <vector>
      9 #include <algorithm>
     10 using namespace std;
     11 
     12 bool isTrueFraction(int numerator, int denominator)    //判断产生的分数是否是真分数
     13 {
     14     if(numerator >= denominator)
     15         return false;
     16 
     17     for(int i = 2 ; i <= numerator ; i++)      //判断分数是否能够约分
     18     {
     19         if(numerator % i ==0 && denominator % i ==0)
     20             return false;
     21     }
     22 
     23     return true;
     24 }
     25 
     26 string getNum(int start = 0, int end = 100, bool isParentheses = false, int depth = 0)
     27 {
     28     int n = rand();
     29     if(isParentheses)      // 若带括号 则为 a op ( b op c) 的形式 op为运算符
     30     {
     31         int num1 = rand() % (end - start + 1) + start;
     32         stringstream ss;
     33         ss << num1;
     34 
     35         if(depth  < 9)     //控制递归层数,带括号的式子少于10个
     36         {
     37             string num2 = "(" + getNum(start,end, n % 2 == 0,depth + 1) + ")";
     38             return ss.str() +","+ num2;
     39         }
     40         else
     41         {
     42             string num2 = "(" + getNum(start,end, false) + ")";
     43             return ss.str() +","+ num2;
     44         }
     45     }else
     46     {
     47         if(n % 7 == 0)       //若随机数n是7的倍数,产生一个真分数和一个整数,否则为两个整数
     48         {
     49             int num1 = rand() % (end - start + 1) + start;
     50             int num2 = rand() % (end - start + 1) + start;
     51             int num3 = rand() % (end - start + 1) + start;
     52 
     53             if(isTrueFraction(num1,num2))
     54             {
     55                 stringstream s1,s2,s3;   //将int转为string
     56                 s1<<num1;
     57                 s2<<num2;
     58                 s3<<num3;
     59                 return s1.str()+"/"+s2.str()+","+s3.str();
     60             }else
     61             {
     62                 return getNum(start,end);
     63             }
     64         }else
     65         {
     66             int num1 = rand() % (end - start + 1) + start;
     67             int num2 = rand() % (end - start + 1) + start;
     68             stringstream s1,s2;
     69             //string ss1,ss2;
     70             s1<<num1;
     71             s2<<num2;
     72             return s1.str()+","+s2.str();
     73         }
     74     }
     75 
     76 
     77 }
     78 
     79 char getOperator(string num2 = "1", bool isMulandDiv = true)   // 默认第二个参数不为0,默认包括乘除法
     80 {
     81     char op[] = {'+','-','*','/'};
     82 
     83     if(isMulandDiv)
     84     {
     85         if(num2 == "0") //避免除数为0
     86             return op[rand() % 3];
     87         else
     88             return op[rand() % 4];
     89     }else
     90     {
     91         return op[rand() % 2];     //只包含加减
     92     }
     93 }
     94 
     95 bool isDup(vector<string> &items, string item)    //若重复返回true,否则返回false
     96 {
     97     if(find(items.begin(),items.end(),item) == items.end())
     98         return false;
     99     else
    100         return true;
    101 }
    102 
    103 bool isNegative(string num1, string num2, char op)      //判断两数加减的正负
    104 {
    105     stringstream ss1,ss2;
    106     int n1,n2;
    107     ss1 << num1;
    108     ss1 >> n1;
    109     ss2 << num2;
    110     ss2 >> n2;
    111     if(op == '-')
    112     {
    113         if(n1 < n2)
    114         {
    115             return true;
    116         }else
    117         {
    118             return false;
    119         }
    120     }else
    121     {
    122         if(n1 + n2 < 0)
    123             return true;
    124         else
    125             return false;
    126     }
    127 
    128 }
    129 
    130 bool isRemainder(string num1, string num2)   //判断两数相除有无余数
    131 {
    132     stringstream ss1,ss2;
    133     int n1,n2;
    134     ss1 << num1;
    135     ss1 >> n1;
    136     ss2 << num2;
    137     ss2 >> n2;
    138 
    139     if(n1 % n2 == 0)
    140         return false;
    141     else
    142         return true;
    143 }
    144 
    145 void print(vector<string> &items, bool isCmd)
    146 {
    147     vector<string>::iterator it = items.begin();
    148     if(isCmd)
    149     {
    150         for(;it != items.end(); it++)
    151         {
    152             cout << (*it) <<endl;
    153         }
    154     }else
    155     {
    156         ofstream of("problems.txt");
    157         if(!of)
    158             exit(1);
    159 
    160         for(;it != items.end() ; it++)
    161             of<<*it <<endl;
    162 
    163         of.close();
    164     }
    165 }
    166 
    167 //void itemsGenerate(int itemNum, bool isCmd)
    168 //{
    169 
    170 //}
    171 
    172 int main(int argc, char *argv[])
    173 {
    174     srand((int)time(0));    //设定时间种子
    175     vector<string> items;   //将题目存在items中,用于判断是否重复和输出
    176     int itemNum,tmp;  //题目数量
    177     char ttmp;
    178     bool isCmd;    //打印方式
    179     bool isMulandDiv;     //是否有乘除法
    180     bool isParentheses;  //是否带括号
    181     int start,end;  //数值范围
    182     bool isNeg;    //有无负数
    183     bool isRem;    //有无余数
    184     bool addFlag = false;  //添加标识
    185 
    186     cout << "请输入题目数量:" << endl;       //定制题目数量、打印方式等
    187     cin >> itemNum;
    188     if(itemNum < 0 )
    189     {
    190         cout << "非法的题目数量!" <<endl;
    191         exit(1);
    192     }
    193 
    194     cout << "请输入打印方式(0. 输出到屏幕 1.输出到文件)" <<endl;
    195     cin >> tmp;
    196     if(tmp == 0)
    197     {
    198         isCmd = true;
    199     }else if(tmp == 1)
    200     {
    201         isCmd = false;
    202     }else
    203     {
    204         cout << "非法的打印方式!" <<endl;
    205         exit(1);
    206     }
    207 
    208     cout << "请输入是否有乘除法(Y/N)" <<endl;
    209     cin >>ttmp;
    210     if(ttmp == 'y' || ttmp == 'Y')
    211     {
    212         isMulandDiv = true;
    213     }else if (ttmp == 'N' || ttmp == 'n')
    214     {
    215         isMulandDiv = false;
    216     }else
    217     {
    218         cout << "非法输入!"<<endl;
    219         exit(1);
    220     }
    221 
    222     cout << "请输入是否有括号?(Y/N)" <<endl;
    223     cin >>ttmp;
    224     if(ttmp == 'y' || ttmp == 'Y')
    225     {
    226         isParentheses = true;
    227     }else if (ttmp == 'N' || ttmp == 'n')
    228     {
    229         isParentheses = false;
    230     }else
    231     {
    232         cout << "非法输入!"<<endl;
    233         exit(1);
    234     }
    235 
    236     cout << "请输入数值范围:(中间由一空格分隔)" << endl;
    237     cin >> start >> end ;
    238     if(start > end)
    239     {
    240         swap(start, end);
    241     }
    242 
    243     cout << "加减法有无负数?(Y/N)" <<endl;
    244     cin >> ttmp;
    245     if(ttmp == 'y' || ttmp == 'Y')
    246     {
    247         isNeg = true;
    248     }else if (ttmp == 'N' || ttmp == 'n')
    249     {
    250         isNeg = false;
    251     }else
    252     {
    253         cout << "非法输入!"<<endl;
    254         exit(1);
    255     }
    256 
    257     cout << "乘除法有无余数?(Y/N)" <<endl;
    258     cin >> ttmp;
    259     if(ttmp == 'y' || ttmp == 'Y')
    260     {
    261         isRem = true;
    262     }else if (ttmp == 'N' || ttmp == 'n')
    263     {
    264         isRem = false;
    265     }else
    266     {
    267         cout << "非法输入!"<<endl;
    268         exit(1);
    269     }
    270 
    271 
    272     for(;items.size() != itemNum ;)    //根据条件生成问题
    273     {
    274         string num = getNum(start,end,isParentheses);
    275         while (num.find(",") != string::npos)
    276         {
    277             addFlag = true;
    278             if( num[num.find(",") + 1] == '(')     //运算符后紧跟括号,运算符选取只和isMulandDiv有关
    279             {
    280                 char op = getOperator("1",isMulandDiv);
    281                 stringstream ss;
    282                 ss << op;
    283                 num = num.replace(num.find(","),1,ss.str());
    284             }else                             //运算符后是数字,运算符选取和num2和isMulandDiv有关,此时是不带括号或最右边的算式
    285             {
    286                 //string::iterator it= num.find(",");
    287                 string num2 = num.substr( num.find(",") + 1, num.find(")",num.find(",") + 1));
    288                 char op = getOperator(num2,isMulandDiv);
    289                 stringstream ss;
    290                 ss << op;
    291                 num = num.replace(num.find(","),1,ss.str());
    292                 int begin = 0;    //找到形如 a op b 的式子
    293                 if(num.find("(") != string::npos)
    294                     begin = num.find_last_of("(") + 1;
    295                 string num1 = num.substr(begin,num.find(ss.str()));
    296                 num2 = num.substr(num.find_last_of(ss.str()) + 1,num.find_first_of(")"));
    297                 if(op == '-' || op == '+')
    298                 {
    299 
    300                     if(!isNeg && isNegative(num1,num2,op))
    301                     {
    302                         addFlag = false;
    303                         break;
    304                     }
    305 
    306                 }else if(op == '/')
    307                 {
    308                     if(!isRem && isRemainder(num1,num2))
    309                     {
    310                         addFlag = false;
    311                         break;
    312                     }
    313                 }
    314             }
    315 
    316         }
    317         if(!addFlag)    //满足要求,可以添加
    318         {
    319             continue;
    320         }
    321 
    322         if(!isDup(items,num))    //判断是否重复,不重复则添加
    323         {
    324             items.push_back(num);
    325         }
    326 
    327 
    328     }
    329 
    330     print(items,isCmd);
    331     return 0;
    332 }

    首先,用vector 存式子 ,1、方便检查重复 2、方便集中输出(屏幕或文件)

    然后,生成式子带括号使用递归实现,通过depth控制深度,防止式子过长,getNum()获得参与运算的数,由“,”作为占位符,

    等数值生成完毕后,在通过getOperator()获得运算符,此时运算符的获得由紧跟运算符后的数值和有无乘除的控制标识 共同决定,

    P.S. 本程序考虑运算符,加减法有无负数,除法有无余数 仅考虑后面紧跟一个数值的情况,

    如果后面是一个由“(”和“)”包围的式子,则不考虑了, 原谅我介一生不羁放纵爱自由 ~~~

     Right-BICEP测试要求:

        1.Right-结果是否正确?

        2.B-是否所有的边界条件都是正确的?

        3.I-能查一下反向关联吗?

        4.C-能用其他手段交叉检查一下结果吗?

        5.E-你是否可以强制错误条件发生?

        6.P-是否满足性能要求?

    从带括号的式子中取 子字符串 然后比较的部分在 271~314行,这部分比较绕,调试了很久。

    附上一组测试数据: (把代码176~269行注释掉换成数据即可)

      /* 最常规的方式 */
        int itemNum = 10;  //题目数量
        bool isCmd = 0;    //打印方式 0.屏幕输出 1.文件输出
        bool isMulandDiv= true;     //是否有乘除法
        bool isParentheses = true;  //是否带括号
        int start = 0;    //数值范围起始
        int end = 100;  //数值范围结束
        bool isNeg = true;    //有无负数
        bool isRem = true;    //有无余数
      bool addFlag = false; //添加标识
    /*不带乘除法 数值范围为负 */ int itemNum = 10; //题目数量 bool isCmd = true; //打印方式 0.屏幕输出 1.文件输出 bool isMulandDiv = false; //是否有乘除法 bool isParentheses = true; //是否带括号 int start = -100; //数值范围起始 int end = 0; //数值范围结束 bool isNeg = true; //有无负数 bool isRem = true; //有无余数
      bool addFlag = false; //添加标识
    /*文件输出 除法没余数 加减不为负*/ int itemNum = 10; //题目数量 bool isCmd = false; //打印方式 0.屏幕输出 1.文件输出 bool isMulandDiv = true; //是否有乘除法 bool isParentheses = true; //是否带括号 int start = 0; //数值范围起始 int end = 100; //数值范围结束 bool isNeg = false; //有无负数 bool isRem= false; //有无余数
      bool addFlag = false; //添加标识
    /* 不带括号 */ int itemNum = 10; //题目数量 bool isCmd = true; //打印方式 0.屏幕输出 1.文件输出 bool isMulandDiv = true; //是否有乘除法 bool isParentheses = false; //是否带括号 int start = 0; //数值范围起始 int end = 100; //数值范围结束 bool isNeg = true; //有无负数 bool isRem = true; //有无余数
      bool addFlag = false; //添加标识
    /*数值范围有正有负 */ int itemNum = 10; //题目数量 bool isCmd = true; //打印方式 0.屏幕输出 1.文件输出 bool isMulandDiv = true; //是否有乘除法 bool isParentheses = true; //是否带括号 int start = -100; //数值范围起始 int end = 100; //数值范围结束 bool isNeg = true; //有无负数 bool isRem = true; //有无余数
      bool addFlag = false; //添加标识
    /*不生成式子 */ int itemNum = 0; //题目数量 bool isCmd = true; //打印方式 0.屏幕输出 1.文件输出 bool isMulandDiv = true; //是否有乘除法 bool isParentheses = true; //是否带括号 int start = 0; //数值范围起始 int end = 100; //数值范围结束 bool isNeg = true; //有无负数 bool isRem = true; //有无余数
      bool addFlag = false; //添加标识

     附上运行截图3张:

    这是输出到文本里的

    总之 ~~~

    本部分任务算是完成了,如有问题 ,欢迎老师同学提出批评建议。

  • 相关阅读:
    css页面自适应 媒体查询
    微信小程序rich-text中的nodes属性
    解析base64数据流---加载pdf
    用伪元素完成箭头
    搭建vue --2.x
    搭建Vue项目 vue-cli vue1.x
    Chrome----TCP
    单进程VS多进程
    线程VS进程
    Chrome---network模块---Timing
  • 原文地址:https://www.cnblogs.com/xiaoxt/p/5251813.html
Copyright © 2020-2023  润新知