结对作业——随机生成四则运算
Core组:陈修远、尹宇飞
Github地址:https://github.com/Yinyf0804/homework2
编程要求
函数要求
写一个能自动生成小学四则运算题目并给出答案的命令行 “软件”,主要有一下两个三个函数构成。
Calc()
这个Calc 函数接受字符串的输入(字符串里就是算术表达式,例如 “53.5”,“7/8 - 3/8 ”,“3 +90 0.3”等等),需要考虑各种异常因素。Setting()
在生成四则运算题目之前,需要对一系列属性进行设置,例如生成题目的数量,操作数的数量,题目中操作数的数值的范围,运算符的种类,(+-*/,是否支持真分数运算,是否支持小数运算,是否支持乘方运算……Generate()
进行一些设置之后,就可以开始生成所需要的题目了,且有以下限制:
(1)生成的题目计算过程中不能产生负数
(2)生成的题目中不能包括不必要的括号
(3)程序一次运行生成的题目不能重复
对接要求
把四则运算的计算功能包装在一个模块中(这个模块可以是一个类 Class, 一个DLL,等等)
需求分析
(1)需要生成足够数量的不相同的题目
(2)题目必须满足各种需要
(3)容错率足够高,需要考虑不同可能的错误情况
(4)实现与UI组的对接
团队分工
陈修远同学负责代码的主要架构和部分函数编写,bug修复以及程序鲁棒性的维护
尹宇飞同学负责部分代码的具体实现和dll的生成,以及与UI组交流和对接。
编程思想
考虑到每一步的运算结果均不能为负数,而直接生成一个后缀表达式再一步一步算,若有负数则丢弃实在是不好实现且代价略高。因此我们在这里选择了如下的递归的方式:
生成一个由n个操作符构成的表达式并得到结果:{
生成一个由i个运算符构成的表达式并得到结果
生成一个由n – i - 1个运算符构成的表达式并得到结果
随机生成运算符将上述表达式合并,并计算结果
}
而对于整个表达式对于加法交换律和乘法交换律不重复的规定,我们在每次生成子表达式的过程中都同时生成一个标准化的表达式:
- 即若碰到了可交换的运算,则将运算符左右两边的子表达式按ascii字符的顺序排序,并在最外面套一个括号,由此再根据一张哈希表来判断是否有重复的表达式生成。
代码架构与实现
基于上述编程的思想,我们大致写了一个框架出来。
由于要生成整数运算、分数运算和小数运算,而这三者之间很多地方都略有差异但是整体的框架并没有变。因此我们在这里考虑了写一个抽象类MyQuestion,中间提供一些虚函数的接口。
这些虚函数的具体实现则由继承这个抽象类的三个子类MyQuestionInInt, MyQuestionInFloat, MyQuestionInFraction(分别代表生成整数运算,小数运算和分数运算)来实现。
以上三个类都只能生成一个表达式及其答案,而最终生成一组表达式并判断是否重复,写文件等操作则由QuestionSetGenerator类调用以上三个类提供的接口来实现。
MyExpression结构体则用来存放表达式及其标准化形式、表达式的结果与表达式的运算符。
MyExpression结构体的成员如下:
struct MyExpression { //一个表达式
string expr; //表达
string expr_normalized; //标准化表达
string expr_answer; //答案
char expr_oper; //保存操作符
};
Myquestion类的声明如下:
class MyQuestion {
public:
void GetQuestion(int operator_number, MyExpression& expression);
//获取一个问题/表达式
protected:
vector<char> oper_set;//运算符集合
pair<int, int> range; //数字的范围
bool is_standard = true; //表达式是否符合规范
void Clear(MyExpression& expression); //清空表达式
void Combine(MyExpression& expression, MyExpression expression1, MyExpression expression2); //将两组表达式结合
virtual bool HandleException(MyExpression& expression) = 0; //处理例外情况
virtual string Calculate(string answer1, char oper, string answer2) = 0;
//计算结果
virtual string GetRandomNumber() = 0;
//获取随机数字(的字符串形式)
};
可以看见,这里一共有三个虚函数
- HandleException函数处理生成表达式过程中的一些例外情况
- Calculate函数负责计算每一步的结果
- GetRandomNumber是返回一个随机生成的数
以上三个函数对于整数运算、分数运算和小数运算均有差异,故写成了虚函数,而其他函数则都类似。
我在编程思想中描述的过程应该能在getQuestion函数中有所体现:
void MyQuestion::GetQuestion(int operator_number, MyExpression &expression) {
if (operator_number == 0) {
expression.expr_answer = GetRandomNumber();
expression.expr = expression.expr_answer;
expression.expr_normalized = expression.expr_answer;
expression.expr_oper = ' ';
return;
}
//运算符数量为0时随机生成数字
else if (operator_number == 1) {
bool is_exception = HandleException(expression);
if (is_exception) {
return;
}
}
//运算符数量为1时的一些例外情况
MyExpression expression1, expression2;
while (true)
{
int key = (rand() % operator_number);
//随机取key值分割n个运算符
Clear(expression1);
Clear(expression2);
GetQuestion(key, expression1);
//expression1 = getQuestion(key)
GetQuestion(operator_number - key - 1, expression2);
//expression2 = getQuestion(num - key - 1)
expression.expr_oper = oper_set[rand() % oper_set.size()];
//随机取运算符
expression.expr_answer = Calculate(expression1.expr_answer, expression.expr_oper, expression2.expr_answer);
//计算结果
if (is_standard) {
break;
}
}
Combine(expression, expression1, expression2);
//生成表达式, 通过operator判断是否需要加括号,并生成表达式的标准形式
}
至于更细节一些的地方,太多了,在此不一一赘述,文末附上代码。
六、本次组队的感想
尹宇飞:
由于陈修远同学在本次项目前已经对C++以及C++11的高级编程非常熟练,而我对C++的认识还只停留在起步阶段,所以一开始看到陈修远同学写的C++架构,还是有点担心自己能否完全理解并完成代码的编写,但这也给了我一个很好的深入学习C++的机会。
随着项目的进行,我逐渐熟悉了C++语言的一些用法,也在陈修远同学的帮助下,成功完成了主要功能的编程内容,并在最后实现了与UI组的对接。虽然短短一个多星期,但这个项目进行的却比想象中的艰难一些,因为不仅我几乎从来没有实际编写过C++,而且期间层出不穷的bug和报错也让我非常头疼。
然而,这个项目却让我受益匪浅,它不仅让我熟悉了C++的编写、dll的生成,还让我的自学能力有了质的飞越,同时,我也学会了许多如何与新队友沟通的技巧和方法,这对我之后的工作有着很大的帮助。虽然过程艰难,但与陈修远同学的合作还是很愉快的,同时,我很感谢这位编程高手这几天给我的帮助,他对编程的认知和对细节的一丝不苟的态度让我受益匪浅,很期待下次的合作。
陈修远:
这是我第一次尝试写虚函数和类的继承(讲道理我之前也是一无所知,都是假装用一个类封装一下装模作样写一写,里子还是函数式的编程思想),其实也算是第一次依葫芦画瓢的OO程序了,而且也不知道自己学得像不像。但第一次写抽象类,就感受到了它的强大。
之前其实想过重载运算符这种操作,但好像实现代价略高而且对于整个程序并没有什么用处。模版类这种东西好像在这里也并不是特别适合(可能是我想不到怎么用吧),而虚函数这种东西是我在查找模版类资料的时候得知的,想了想好像能用就硬着头皮写了下去23333。
当然程序肯定也有不足之处,我肯定也没有把方方面面都考虑周到,很多问题在跟UI组对接了之后才暴露出来,这说明了测试模块的必要性(然而我并不会,老师能讲一下么?)
最后想说一下结对的心得吧,交流确实比想象中的困难,对方怎么想的他解释半天我也不见得就懂了,我怎么想的对方也听得迷迷糊糊的。如何才能更高效地交流,我也不是特别明白,所以如果我在交流过程中有表现出不耐烦,希望尹宇飞同学可以包容一下。至于效率,一个简简单单的函数可能自己写只要一两下,而对方却要花很久去看。(或者说我自己隔几天去看就也没心情看下去了)这也是个问题,如何解决也要靠之后慢慢摸索了。
PSP表格
PSP2.1 | 任务内容 | 计划需要完成的时间(min) | 实际需要完成的时间(min) |
---|---|---|---|
Estimate | 估算 | 15 | 15 |
Analysis | 需求分析 | 135 | 200 |
Design Spec | 设计文档 | 15 | 15 |
Coding Standard | 代码规范 | 10 | 10 |
Design | 具体设计 | 60 | 120 |
Coding | 具体编码 | 300 | 480 |
Code Review | 2 h | 包含在具体编码过程中 | / |
Test | 测试 | 120 | 300 |
Record Time Spent | 记录用时 | 10 | 10 |
Test Report | 测试报告 | 20 | 40 |
Size Measurement | 计算工作量 | 20 | 10 |
Postmortem | 总结改进 | 180 | 180 |
Summary | 合计 | 885 | 1380 |
代码
MyExpression结构体
struct MyExpression { //一个表达式
string expr; //表达
string expr_normalized; //标准化表达
string expr_answer; //答案
char expr_oper; //保存操作符
};
MyQuestion类
class MyQuestion {
public:
void GetQuestion(int operator_number, MyExpression& expression);
//获取一个问题/表达式
protected:
vector<char> oper_set; //运算符集合
pair<int, int> range; //数字的范围
bool is_standard = true; //表达式是否符合规范
void Clear(MyExpression& expression); //清空表达式
void Combine(MyExpression& expression, MyExpression expression1, MyExpression expression2);
//将两组表达式结合
virtual bool HandleException(MyExpression& expression) = 0; //处理例外情况
virtual string Calculate(string answer1, char oper, string answer2) = 0; //计算结果
virtual string GetRandomNumber() = 0; //获取随机数字(的字符串形式)
};
void MyQuestion::GetQuestion(int operator_number, MyExpression &expression) {
if (operator_number == 0) {
expression.expr_answer = GetRandomNumber();
expression.expr = expression.expr_answer;
expression.expr_normalized = expression.expr_answer;
expression.expr_oper = ' ';
return;
}
else if (operator_number == 1) {
bool is_exception = HandleException(expression);
if (is_exception) {
return;
}
}
MyExpression expression1, expression2;
while (true)
{
int key = (rand() % operator_number); //get random number key in range(0,number-1)
Clear(expression1);
Clear(expression2);
GetQuestion(key, expression1); //expression1 = getQuestion(key)
GetQuestion(operator_number - key - 1, expression2); //expression2 = getQuestion(num - key - 1)
expression.expr_oper = oper_set[rand() % oper_set.size()]; //get random operator
expression.expr_answer = Calculate(expression1.expr_answer, expression.expr_oper, expression2.expr_answer); //calc answer
if (is_standard) {
break;
}
}
Combine(expression, expression1, expression2); //form question //通过operator判断是否需要加括号
}
void MyQuestion::Clear(MyExpression& expression) {
expression.expr_oper = '\0';
expression.expr = "";
expression.expr_answer = "";
expression.expr_normalized = "";
}
void MyQuestion::Combine(MyExpression& expression, MyExpression expression1, MyExpression expression2) {
char p = expression.expr_oper;
if (p != '^' && p != '-' && p != '/' && expression1.expr_normalized > expression2.expr_normalized) //小的排前面
expression1.expr_normalized.swap(expression2.expr_normalized);
expression.expr_normalized = '(';
expression.expr_normalized += expression1.expr_normalized;
expression.expr_normalized += expression.expr_oper;
expression.expr_normalized += expression2.expr_normalized;
expression.expr_normalized += ')';
//combine normalised question
if (expression.expr_oper == '^') {
if (expression1.expr_oper != ' ') {
expression.expr += '(';
expression.expr += expression1.expr;
expression.expr += ')';
}
else {
expression.expr += expression1.expr;
}
expression.expr += expression.expr_oper;
if (expression2.expr_oper != ' ') {
expression.expr += '(';
expression.expr += expression2.expr;
expression.expr += ')';
}
else {
expression.expr += expression2.expr;
}
}
else if ((expression.expr_oper == '*') || (expression.expr_oper == '/')) {
if (expression1.expr_oper == '+' || expression1.expr_oper == '-') {
expression.expr += '(';
expression.expr += expression1.expr;
expression.expr += ')';
}
else {
expression.expr += expression1.expr;
}
expression.expr += expression.expr_oper;
if (expression2.expr_oper != ' ') {
expression.expr += '(';
expression.expr += expression2.expr;
expression.expr += ')';
}
else {
expression.expr += expression2.expr;
}
}
else {
expression.expr += expression1.expr;
expression.expr += expression.expr_oper;
if (expression2.expr_oper == '+' || expression2.expr_oper == '-') {
expression.expr += '(';
expression.expr += expression2.expr;
expression.expr += ')';
}
else {
expression.expr += expression2.expr;
}
}
//combine question/expression
}
MyQuestionInInt类
//整数运算
class MyQuestionInInt : public MyQuestion {
public:
MyQuestionInInt() {
support_devision = true;
support_exponentiation = true;
oper_set.push_back('+');
oper_set.push_back('-');
oper_set.push_back('*');
range.first = 0;
range.second = 100;
}
MyQuestionInInt(vector<char> oper, pair<int, int> input_range) {
support_devision = false;
support_exponentiation = false;
auto iter = find(oper.begin(), oper.end(), '/');
if (iter != oper.end()) {
oper.erase(iter);
support_devision = true;
}
iter = find(oper.begin(), oper.end(), '^');
if (iter != oper.end()) {
oper.erase(iter);
support_exponentiation = true;
}
oper_set = oper;
range = input_range;
}
private:
bool support_devision; //是否支持除法
bool support_exponentiation; //是否支持乘方
bool isInRange(string a); //是否在范围内
//以下函数继承至MyQuestion
bool HandleException(MyExpression& expression);
string Calculate(string answer1, char oper, string answer2);
string GetRandomNumber();
string SqrtGetRandomNumber();
};
string MyQuestionInInt::SqrtGetRandomNumber() {
int upper = 2 * sqrt(range.second);
int lower = (sqrt(range.first) + 1) / 2 + 1;
int num = rand() % (upper - lower) + lower;
return to_string(num);
}//get random number in range (sqrt(lower)/2, sqrt(upper)*2)
string MyQuestionInInt::GetRandomNumber() {
int num = rand() % (range.second - range.first) + range.first;
return to_string(num);
}//get random number
bool MyQuestionInInt::HandleException(MyExpression& expression) {
if (!support_devision && !support_exponentiation) {
return false;
}
int key;
if (oper_set.empty()) {//if there's no operator in operset
if (!support_devision && support_exponentiation) {
key = 1;
}
else if (support_devision && !support_exponentiation) {
key = 2;
}
else {
key = (rand() % 2) + 1;
}
}
else { //there is other operators in operset
if (!support_devision && support_exponentiation) {
key = rand() % 2;
}
else if (support_devision && !support_exponentiation) {
key = (rand() % 2) * 2;
}
else {
key = rand() % 3;
}
}
string a1, a2, a3;
if (key == 0) {
return false;
}
else if (key == 1) { //exponentiation
while (true) {
a1 = GetRandomNumber();
if (stoi(a1) <= 50) {
break;
}
}
a2 = to_string(rand() % 5);
expression.expr_oper = '^';
}
else { //devision
while (true) {
a2 = SqrtGetRandomNumber();
a3 = SqrtGetRandomNumber();
a1 = Calculate(a2, '*', a3);
if (stoi(a1) <= range.second && stoi(a1) >= range.first) {
break;
}
}
expression.expr_oper = '/';
}
expression.expr_answer = Calculate(a1, expression.expr_oper, a2);
expression.expr = a1;
expression.expr += expression.expr_oper;
expression.expr += a2;
expression.expr_normalized = "(";
expression.expr_normalized += expression.expr;
expression.expr_normalized += ")";
return true;
}
//calculate result
string MyQuestionInInt::Calculate(string answer1, char oper, string answer2) {
string num;
int number, num1, num2;
num1 = stoi(answer1);
num2 = stoi(answer2);
is_standard = true;
if (oper == '+') {
number = num1 + num2;
}
else if (oper == '-') {
number = num1 - num2;
}
else if (oper == '*') {
number = num1 * num2;
}
else if (oper == '/') {
number = num1 / num2;
}
else if (oper == '^') {
number = pow(num1, num2);
}
else {
is_standard = false;
return "-1";
}
if (number < 0) {
is_standard = false;
return "-1";
}
num = to_string(number);
return num;
}
MyQuestionInFloat类
//小数运算,与上面类似
class MyQuestionInFloat : public MyQuestion {
public:
MyQuestionInFloat() {
oper_set.push_back('+');
oper_set.push_back('-');
oper_set.push_back('*');
oper_set.push_back('/');
range.first = 0;
range.second = 100;
}
MyQuestionInFloat(vector<char> oper, pair<int, int> input_range) {
oper_set = oper;
range = input_range;
}
private:
bool HandleException(MyExpression& expression);
string Calculate(string answer1, char oper, string answer2);
string GetRandomNumber();
// double Round(double dVal, short iPlaces);
};
//no exception here
bool MyQuestionInFloat::HandleException(MyExpression &expression) {
return false;
}
//calculate result
string MyQuestionInFloat::Calculate(string answer1, char oper, string answer2) {
string num;
double number, num1, num2;
num1 = stod(answer1);
num2 = stod(answer2);
is_standard = true;
if (oper == '+') {
number = num1 + num2;
}
else if (oper == '-') {
number = num1 - num2;
if (number < 0) {
is_standard = false;
}
}
else if (oper == '*') {
number = num1 * num2;
}
else if (oper == '/') {
if (num2 == 0) {
is_standard = false;
return("-1");
}
number = num1 / num2;
}
else {
number = -1;
}
/* else if (oper == '^') {
number = pow(num1, num2);
}
*/
// num = to_string(Round(number, 2));
// num = num.substr(0, num.size() - 4);
num = to_string(number);
return num;
}
// get random number
string MyQuestionInFloat::GetRandomNumber() {
int random = rand() % (range.second * 10 - range.first * 10) + range.first * 10;
double number = double(random) / 10;
string num = to_string(number);
return(num.substr(0, num.size() - 5));
}
MyQuestionInFraction类
//分数运算
class MyQuestionInFraction : public MyQuestion {
public:
MyQuestionInFraction() {
oper_set.push_back('+');
oper_set.push_back('-');
oper_set.push_back('*');
oper_set.push_back('/');
range.first = 0;
range.second = 100;
}
MyQuestionInFraction(vector<char> oper, pair<int, int> input_range) {
oper_set = oper;
range = input_range;
}
private:
bool HandleException(MyExpression& expression);
string Calculate(string answer1, char oper, string answer2);
string GetRandomNumber();
void reduction(int a[], string& ans);
void split(string src[], string str);
};
//get random number
string MyQuestionInFraction::GetRandomNumber() {
int num = rand() % (range.second - range.first) + range.first;
return to_string(num);
}
//split string (a/b) to (a,b)
void MyQuestionInFraction::split(string src[], string str) {
//int size = str.size();
int i = str.find("/");
if (i == -1) {
src[0] = str;
src[1] = "1";
}
else {
src[0] = str.substr(0, i);
src[1] = str.substr(i + 1);
}
}
//reduction of a fraction number
void MyQuestionInFraction::reduction(int a[], string& ans) {
if (a[0] == 0) {
ans = "0";
return;
}
if (a[1] == 0) {
ans = "-1";
is_standard = false;
return;
}
if (a[0] < 0 || a[1] < 0) {
ans = "-1";
is_standard = false;
return;
}
int max, min;
if (a[0] > a[1]) {
max = a[0];
min = a[1];
}
else {
max = a[1];
min = a[0];
}
while (max % min != 0) {
int temp = max % min;
max = min;
min = temp;
}
int up = a[0] / min, down = a[1] / min;
if (down == 1) {
ans = to_string(up);
}
else {
ans = to_string(up);
ans += "/";
ans += to_string(down);
}
}
// calculate result
string MyQuestionInFraction::Calculate(string answer1, char oper, string answer2) {
string num, a[2], b[2];
split(a, answer1);
split(b, answer2);
int answer[2];
int a0 = stoi(a[0]), a1 = stoi(a[1]), b0 = stoi(b[0]), b1 = stoi(b[1]);
is_standard = true;
if (oper == '+') {
answer[0] = a0 * b1 + a1 * b0;
answer[1] = a1 * b1;
}
else if (oper == '-') {
answer[0] = a0 * b1 - a1 * b0;
answer[1] = a1 * b1;
}
else if (oper == '*') {
answer[0] = a0 * b0;
answer[1] = a1 * b1;
}
else if (oper == '/') {
if (stoi(b[0]) == 0) {
is_standard = false;
return num;
}
answer[0] = a0 * b1;
answer[1] = a1 * b0;
}
reduction(answer, num);
return num;
}
//no exception here
bool MyQuestionInFraction::HandleException(MyExpression& expression) {
return false;
}
QuestionSetGenerator类
class __declspec(dllexport) QuestionSetGenerator {
public:
int ques_num; //题目的数量
int oper_num; //一个表达式中运算符的数量
vector<char> oper_set; //运算符的种类
int mode; //0为整数,1为小数,2为分数
pair<int, int> input_range; //题目数值的范围
double Round(double dVal, short iPlaces);
QuestionSetGenerator();
int Setting(int question_number, int operator_number, string oper, int question_type, int lower_bound, int upper_bound); //读文件并更改设置
void Generate(); //产生题目并写文件
bool flag;
};
QuestionSetGenerator::QuestionSetGenerator() {
ques_num = 10;
oper_num = 3;
oper_set.push_back('+');
oper_set.push_back('-');
oper_set.push_back('*');
oper_set.push_back('/');
oper_set.push_back('@');
mode = 0;
input_range.first = 0;
input_range.second = 100;
}
double QuestionSetGenerator::Round(double dVal, short iPlaces) {
double dRetval;
double dMod = 0.0000001;
if (dVal<0.0) dMod = -0.0000001;
dRetval = dVal;
dRetval += (5.0 / pow(10.0, iPlaces + 1.0));
dRetval *= pow(10.0, iPlaces);
dRetval = floor(dRetval + dMod);
dRetval /= pow(10.0, iPlaces);
return(dRetval);
}
int QuestionSetGenerator::Setting(int quesnum, int opernum, string oper, int question_type, int lower_bound, int upper_bound) {
ques_num = 10;
oper_num = 3;
oper_set.push_back('+');
oper_set.push_back('-');
oper_set.push_back('*');
oper_set.push_back('/');
mode = 1;
input_range.first = 0;
input_range.second = 100;
flag = true;
if (quesnum <= 0 || opernum <= 0) {//question number and operator number should > 0
flag = false;
return -1;
}
if (question_type < 0 || question_type>2) { //question type should be 0,1 or 2
flag = false;
return -1;
}
int key[5] = { 0,0,0,0,0 };
for (int i = 0; i < oper.size(); i++) {
if (oper[i] == '+') {
key[0] = 1;
}
else if (oper[i] == '-') {
key[1] = 1;
}
else if (oper[i] == '*') {
key[2] = 1;
}
else if (oper[i] == '/') {
key[3] = 1;
}
else if (oper[i] == '^' && question_type == 0) {//only in mode 0 would ^ be allowed to appear
key[4] = 1;
}
}
if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0 && key[4] == 0) { //no supporting operator is not allowed
flag = false;
return -1;
}
if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0 && key[4] == 1 && opernum > 1 && question_type == 0) {
flag = false;
return -1;
}
//if only ^ is supported in mode 0, then operator number should be 1
if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 1 && key[4] == 0 && opernum > 1 && question_type == 0) {
flag = false;
return -1;
}
//if only / is supported in mode 0, then operator number should be 1
if (lower_bound >= upper_bound) { //lower bound should not be larger than upper bound
flag = false;
return -1;
}
if (lower_bound < 0) { //lower bound should > 0
flag = false;
return -1;
}
ques_num = quesnum;
oper_num = opernum;
mode = question_type;
oper_set.clear();
if (key[0] == 1) {
oper_set.push_back('+');
}
if (key[1] == 1) {
oper_set.push_back('-');
}
if (key[2] == 1) {
oper_set.push_back('*');
}
if (key[3] == 1) {
oper_set.push_back('/');
}
if (key[4] == 1) {
oper_set.push_back('^');
}
input_range.first = lower_bound;
input_range.second = upper_bound;
return 0;
}
void QuestionSetGenerator::Generate() {
unordered_map<string, bool> expression_set;
if (flag == false) cout << "Sorry,you have made some stange requests" << endl;
else {
MyQuestion* ques;
if (mode == 0) {
//ques = new MyQuestionInInt();
ques = new MyQuestionInInt(oper_set, input_range);
}
else if (mode == 1) {
//ques = new MyQuestionInFloat;
ques = new MyQuestionInFloat(oper_set, input_range);
}
else {
//ques = new MyQuestionInFraction;
ques = new MyQuestionInFraction(oper_set, input_range);
}
srand((unsigned)time(0));
unsigned long key = 0;
ofstream formula("formula.txt");
ofstream result("result.txt");
if (!formula.is_open())
{
cout << "Cannot create the file" << endl;
}
if (!result.is_open())
{
cout << "Cannot create the file" << endl;
}
for (int i = 0; i < ques_num; i++) {
key++;
if (key > 1000000) {
formula << "Cannot generate so many questions with given condition." << endl;
result << "Cannot generate so many questions with given condition." << endl;
}
MyExpression temp;
ques->GetQuestion(oper_num, temp); //获取一个问题
auto iter = expression_set.find(temp.expr_normalized);
if (iter == expression_set.end()) { //若该问题没有重复
expression_set[temp.expr_normalized] = true; //存入map
if (mode == 1)
{
temp.expr_answer = to_string(Round(stod(temp.expr_answer), 2));
temp.expr_answer = temp.expr_answer.substr(0, temp.expr_answer.size() - 4);
}
if (mode == 2) {
int i = temp.expr_answer.find("/");
if (i != -1) {
string answer;
int num1 = stoi(temp.expr_answer.substr(0, i));
int num2 = stoi(temp.expr_answer.substr(i + 1));
if (num1 > num2)
{
answer = to_string(num1 / num2);
answer += '+';
answer += to_string(num1%num2);
answer += '/';
answer += to_string(num2);
temp.expr_answer = answer;
}
}
}
cout << temp.expr << " = " << temp.expr_answer << endl;
formula << temp.expr << endl;
result << temp.expr_answer << endl;
//write file
}
else { //若已存在这个问题
i--; //这次循环不算数
}
}
formula.close();
result.close();
}
}