第一次结对编程——四则运算
一个类core
一个结构体对象config,用来实现对设置项的存储,代码如下:
typedef struct { int ProblemNum; int precision; int OperandNum; int lrange; int hrange; int calculate_kind; string KindofOperator; }Config;
Setting方法:
重载的Setting方法
1.core.Setting(string option, int key);
利用option来区分是设置题目数量还是操作数数量还是操作数上下限,代码如下:
bool core::Setting(string option, int key) {//TODO ::to call the wrong parameter if (option == "calculate_kind") { config.calculate_kind = key; } if (option == "precision") { config.precision = key; return true; } if (option == "ProblemNum") { config.ProblemNum = key; return true; } if (option == "OperandNum") { config.OperandNum = key; return true; } if (option == "lrange") { config.lrange = key; return true; } if (option == "hrange") { config.hrange = key; return true; } return false; }
2.core.Setting(char option, bool key);
利用option来区分是什么运算符,key来确定是否加入,代码如下:
bool core::Setting(char c, bool key) {//TODO ::to call the wrong parameter if (c == '+') { if(key) config.KindofOperator.append("+"); return true; } if (c == '-') { if(key) config.KindofOperator.append("-"); return true; } if (c == '*') { if(key) config.KindofOperator.append("*"); return true; } if (c == '/') { if(key) config.KindofOperator.append("/"); return true; } if (c == '^') { if(key) config.KindofOperator.append("^"); return true; } return false; }
Generate方法
core.Generate()
在这个方法中,根据config的设置来随机的生成没有括号的表达式,然后递归调用私有方法AddBracket(), 随机的生成合法的并列或者是嵌套的括弧
没进入一次递归,就生成表达式的一部分,并且将这部分的表达式的后缀表达式和原表达式相同部分的后缀表达式进行比较,
如果相同,则说明这次增加的括弧多余,作废后,继续递归
AddBracket()
产生括弧的式子和原表达式同时生成后缀表达式,如果后缀表达式相同,则括号
并且将表达式尝试传入Calc方法,如果抛出不整除,除零,越界,幂指数不为整数等异常,就进行处理,放弃这个表达式,重新生成。每生成一个表达式,需要和之前生成的所有表达式进行运算过程比较,即传入ProblemCompare方法,两个表达式同时进行计算,如果每次计算的两个操作室相同(不计入顺序), 操作符相同,则两个表达式为同一表达式。
代码如下:
Generate()
void core::Generate(string* &Problem, string* &result) { int test; vector<int> DivoperatorIndex; vector<int> PowoperatorIndex; int m;// for loop int overflow = 0; int calculate_kind = config.calculate_kind; if (calculate_kind == 0) { config.precision = 0; } int precision = config.precision; const int ProblemNum = config.ProblemNum;//the number of the problems const int OperandNum = config.OperandNum;//the number of the operands string KindofOperator = config.KindofOperator;//all of the kind of the operators if (KindofOperator.find("+") != string::npos) KindofOperator.append(30, '+'); if (KindofOperator.find("-") != string::npos) KindofOperator.append(30, '-'); if (KindofOperator.find("*") != string::npos) KindofOperator.append(10, '*'); if (KindofOperator.find("/") != string::npos) KindofOperator.append(20, '/'); if (KindofOperator.find("^") != string::npos) KindofOperator.append(8, '^'); const int lrange = config.lrange; const int hrange = config.hrange;// the range of the operator and the result int* IntOperand; double *FloatOperand;//to store the operands, and to get their index IntOperand = new int[OperandNum]; FloatOperand = new double[OperandNum]; fraction *FractionOperand; FractionOperand = new fraction[OperandNum]; char *Operator;// to store the operators, and to get their index Operator = new char[OperandNum]; Problem = new string[ProblemNum]; result = new string[ProblemNum]; string OriginalProblem = ""; int j; for (j = 0; j < ProblemNum && overflow < 10000*ProblemNum ; j++, overflow++) { PowoperatorIndex.clear(); DivoperatorIndex.clear(); OriginalProblem = ""; for (int i = 0; i < OperandNum - 1; i++) { Operator[i] = KindofOperator[random(0, KindofOperator.size() - 1)]; if (Operator[i] == '^') PowoperatorIndex.push_back(i); if (Operator[i] == '/') DivoperatorIndex.push_back(i); } if (calculate_kind == 0) { for (int i = 0; i < OperandNum; i++) { IntOperand[i] = random(lrange, hrange); } for (int i = 0; i < PowoperatorIndex.size(); i++) { IntOperand[PowoperatorIndex[i] + 1] = random(0, 3); } for (int i = DivoperatorIndex.size()-1; i >= 0 ; i--) { IntOperand[DivoperatorIndex[i] + 1] = tofinddiv(IntOperand[DivoperatorIndex[i]]); } for (int i = 0; i < OperandNum - 1; i++) { OriginalProblem += to_string(IntOperand[i]); OriginalProblem += Operator[i]; } OriginalProblem += to_string(IntOperand[OperandNum - 1]); } if (calculate_kind == 1) { for (int i = 0; i < OperandNum; i++) { FloatOperand[i] = random((float)lrange, (float)hrange); } for (int i = 0; i < PowoperatorIndex.size(); i++) { FloatOperand[PowoperatorIndex[i] + 1] = random(0, 3); } for (int i = 0; i < OperandNum - 1; i++) { OriginalProblem += to_string_with_precision(FloatOperand[i], precision); OriginalProblem += Operator[i]; } OriginalProblem += to_string_with_precision(FloatOperand[OperandNum - 1], precision); } if (calculate_kind == 2) { for (int i = 0; i < OperandNum; i++) { FractionOperand[i].denominator = random(lrange, hrange); FractionOperand[i].numerator = random(lrange, hrange); FractionOperand[i] = Simplify(FractionOperand[i]); } for (int i = 0; i < PowoperatorIndex.size(); i++) { FractionOperand[PowoperatorIndex[i] + 1].numerator = random(0, 3); FractionOperand[PowoperatorIndex[i] + 1].denominator = 1; FractionOperand[PowoperatorIndex[i] + 1] = Simplify(FractionOperand[PowoperatorIndex[i] + 1]); } for (int i = 0; i < OperandNum - 1; i++) { OriginalProblem += Frac2Str(FractionOperand[i]); OriginalProblem += Operator[i]; } OriginalProblem += Frac2Str(FractionOperand[OperandNum - 1]); } Problem[j] = AddBracket(OriginalProblem); cout << Problem[j] << endl; if (Calc(Problem[j]) == "ERROR: expression!") { j--; continue; } //cout << Problem[j] << endl; for (m = 0; m < j; m++) { if (ProblemCompare(Problem[m], Problem[j]))//TODO { break; } } if (m != j)// { j--; continue; }//TODO:: } if (overflow == 10000 * ProblemNum) { for (int i = j; i < ProblemNum; i++) Problem[i] = ""; } for (int i = 0; i < ProblemNum; i++) { result[i] = Calc(Problem[i]); //Problem[i] = to_unicode(Problem[i]); //result[i] = to_unicode(result[i]); } }
ProblemCompare()
bool core::ProblemCompare(string formar, string latter) { fraction fracs[arraysize]; string::size_type idx; if (exp == "") return ""; result = "ERROR: expression!"; idx = exp.find("|"); // check out the ERROR: character in this expression try { // throw exception ExceptChar(exp); FracOrInte(exp); MatchBracket(exp); ExceptConnection(exp); // no matching error or ERROR: character if (idx == string::npos) { try { sur = exp2suffix(exp); result = to_string_with_precision(calcInte(sur, 0, 99999), config.precision); } catch (const char* msg) { return result; } } else { try { GetFrac(exp, fracs); sur = exp2suffix(exp); result = Frac2Str(CalcFrac(sur, fracs, 0, 99999)); } catch (const char* msg) { return result; } } } catch (const char* msg) { return result; } fraction fracs[arraysize]; string::size_type idx; if (exp == "") return ""; result = "ERROR: expression!"; idx = exp.find("|"); // check out the ERROR: character in this expression try { // throw exception ExceptChar(exp); FracOrInte(exp); MatchBracket(exp); ExceptConnection(exp); // no matching error or ERROR: character if (idx == string::npos) { try { sur = exp2suffix(exp); result = to_string_with_precision(calcInte(sur, 0, 99999), config.precision); } catch (const char* msg) { return result; } } else { try { GetFrac(exp, fracs); sur = exp2suffix(exp); result = Frac2Str(CalcFrac(sur, fracs, 0, 99999)); } catch (const char* msg) { return result; } } } catch (const char* msg) { return result; } return result; }
由于程序需要大量使用随机数
编写了两个随机数的方法, 代码如下
int core::random(int low, int high) { int i; srand(seed); i = (rand() % (high - low + 1)) + low; seed = (seed + 199) % RAND_MAX; return i; } double core::random(double low, double high) { int i = random((int)low*(int)low, (int)high*(int)high); return sqrt(i); }
对接遇到的问题:
1.我们之前使用的是json的字典式传参,但是在对接时,发现json的第三方库始终无法成功地链接,我们遂将Setting改成上面的重载函数的参数式的传递
2.在UI组实验只选除号的整数运算时,我们因为设计中有整除的限制,导致随机生成的式子很难符号要求,代码需要跑很长时间,才能出结构
于是我们遂在Generate里面就指定生成'/' 符号的后面的数字是前面数字的约数,这要大大提高了生成题目的速度
结果:
整数:
小数:
分数: