关于未成品的问题:字符类型和其他种种
2016-03-14 17:35
288 查看
0.2版本的随机出题器,问题还有,等着下次解决。先把作业交了再说。
完全重做了,基于VC(偷懒所以使用了MFC的CString类),但是也导致了字符类型的问题。
首先是大概:出题和答案分成了两个类,主函数用来控制参数和计算分数等。
1.答案部分(一个算数计算器)
该计算器支持+-*/^五种运算符,也支持括号(包括多重)
主要代码如上,思路如注释所示,逐字符确定是数字还是运算符,遇到运算符后入栈的数字用atof转为数字并入数值栈,然后运算符进栈,并和栈内运算符对比优先度,若优先级高,则符号入栈,若低则与数值栈的栈顶前两个出栈作运算值,运算符为符号栈栈顶;
入栈出栈部分省略,算符有限度的确定通过查表方式确定表如下:
经测试没什么大问题。能正常运作。
于是开始写随机出题器。先随机出数字,然后随机符号,利用CString的一些特性可以很方便的增补字符串,最后得出算式的表达式:
其中余数状态下还未实现,经测试,得出的算式正常,但是问题来了
上面得到的算式是uni编码,即得到的字符串为wchar_t类型,我的计算器却是识别char类型的字符串识别的。
然后去查找资料,暂时解决方法是用wcstombs_s函数来吧wchar_t字符串转为char类型。
姑且算是解决了,其实想修改计算器部分的,但是要到交作业的时候了,先用这种转换的方式实现一下。
整合两者后,发现问题了,小数运算的答案和用户输入的答案并不一致(浮点数的精度问题),用==的方式不可能确定答对与否。
想了想,其实解决也很简单,只要二者之差的绝对值不超过规定的小数位数精度即可。
测试,OK,但是分数计算、带余数的除法计算等问题还有待解决。
0.2版本的随机计算器就是这样了。
完全重做了,基于VC(偷懒所以使用了MFC的CString类),但是也导致了字符类型的问题。
首先是大概:出题和答案分成了两个类,主函数用来控制参数和计算分数等。
1.答案部分(一个算数计算器)
该计算器支持+-*/^五种运算符,也支持括号(包括多重)
double EvaluateExpression(char* MyExpression) { //表达式求值的算符优先算法。 //设OPTR和OPND分别为运算符栈和运算数栈,OP为运算符集合。 SS *OPTR = NULL; // 运算符栈,字符元素 SN *OPND = NULL; // 运算数栈,实数元素 char TempData[20]; double Data, a, b; char theta, *c, Dr[] = { '#', '\0' }; OPTR = Push(OPTR, '#'); c = strcat(MyExpression, Dr); //字符串连接函数,结尾处加个#,返回连接后的指针 strcpy(TempData, "\0");//字符串拷贝函数,TempData置空 while (*c != '#' || OPTR->c != '#') { if (!In(*c, OPSET)) //判断是否为运算符 { //若不是 if (*c != '.')//小数允许 if (*c>'9' || *c<'0')//不是数字则出错了 { printf("input error\n"); return 0; } Dr[0] = *c; strcat(TempData, Dr);//字符串连接函数,把算式的当前字符接在 TempData上 c++; //指针指向算式的下一个字符 if (In(*c, OPSET)) //若字符为运算符 { Data = atof(TempData);//字符串转换函数,转为浮点数 OPND = Push(OPND, Data); //数值入栈 strcpy(TempData, "\0"); //TempData置空 } } else { // 是运算符则进栈 switch (precede(OPTR->c, *c))//对比栈顶字符和当前字符的优先度 { case '<': // 栈顶元素优先权低,则符号入栈 OPTR = Push(OPTR, *c); c++; break; case '=': // 脱括号并接收下一字符 OPTR = Pop(OPTR); c++; break; case '>': // 退栈并将运算结果入栈 theta = OPTR->c;//记录当前符号栈栈顶,即要用的运算符 OPTR = Pop(OPTR); //符号栈顶出栈 b = OPND->f;//记录数值栈栈顶,作为第一个运算值 OPND = Pop(OPND); //数值栈顶出栈 a = OPND->f;//记录数值栈栈顶,作为第二个运算值 OPND = Pop(OPND); //数值栈顶出栈 OPND = Push(OPND, Operate(a, theta, b)); //把计算结果入栈到数值栈 break; } // switch } } // while return OPND->f; }//EvaluateExpression
主要代码如上,思路如注释所示,逐字符确定是数字还是运算符,遇到运算符后入栈的数字用atof转为数字并入数值栈,然后运算符进栈,并和栈内运算符对比优先度,若优先级高,则符号入栈,若低则与数值栈的栈顶前两个出栈作运算值,运算符为符号栈栈顶;
入栈出栈部分省略,算符有限度的确定通过查表方式确定表如下:
char list[8][8] = { // 算符间的优先关系表 // '+' '-' '*' '/' '(' ')' '#' '^' /*'+'*/'>', '>', '<', '<', '<', '>', '>', '<', /*'-'*/'>', '>', '<', '<', '<', '>', '>', '<', /*'*'*/'>', '>', '>', '>', '<', '>', '>', '<', /*'/'*/'>', '>', '>', '>', '<', '>', '>', '<', /*'('*/'<', '<', '<', '<', '<', '=', ' ', '<', /*')'*/'>', '>', '>', '>', ' ', '>', '>', '>', /*'#'*/'<', '<', '<', '<', '<', ' ', '=', '<', /*'^'*/'>', '>', '>', '>', '<', '>', '>', '>' }; char oplist[8] = { '+', '-', '*', '/', '(', ')', '#', '^' };//合法运算符表
int ReturnOpOrd(char op, char* TestOp)//查表 { for (int i = 0; i < 8; i++) if (op == TestOp[i]) return i; } char precede(char Aop, char Bop)//字符优先度对比 { int m, n; m = ReturnOpOrd(Aop, OPSET); n = ReturnOpOrd(Bop, OPSET); return Prior[m] ; }
经测试没什么大问题。能正常运作。
于是开始写随机出题器。先随机出数字,然后随机符号,利用CString的一些特性可以很方便的增补字符串,最后得出算式的表达式:
void EqaSet(int Yuan, int numlv, bool symlv, bool neg = false, bool dec = false, int declv = 3, bool po = false, bool rem = false)//从左至右:元数,范围,运算,余数,负数,小数,小数等级,次方运算 { int num[10]; wchar_t *sub; srand(time(NULL)); double fnum[10]; char SYM; CString temp; if (dec == false)//无小数 { for (int i = 0; i < Yuan; i++) num[i] = randnum(numlv, neg); } else//有小数 { for (int i = 0; i < Yuan; i++) fnum[i] = frandnum(numlv, neg, declv); } //显示的和实际计算的有区别(负数问题) if (dec == false) temp.Format(_T("%d"), num[0]); else temp.Format(_T("%g"), fnum[0]); eqa = temp; if (dec == false) { if (num[0] < 0) temp.Format(_T("(0%g)"), num[0]); } else { if (fnum[0] < 0) temp.Format(_T("(0%g)"), fnum[0]); } EQA = temp; //end for (int i = 0; i < Yuan - 1; i++) { SYM = randsym(symlv, po); if (SYM == '/') if (num[i + 1] == 0) num[i + 1] = 2; temp = SYM; eqa += temp; EQA += temp; if (dec == false) temp.Format(_T("%d"), num[i + 1]); else temp.Format(_T("%g"), fnum[i + 1]); eqa += temp; if (dec == false) { if (num[i + 1] < 0) temp.Format(_T("(0%g)"), num[i + 1]); } else { if (fnum[i + 1] < 0) temp.Format(_T("(0%g)"), fnum[i + 1]); } EQA += temp; }//for sub = eqa.GetBuffer(eqa.GetLength()); wcout << sub << "="; }
其中余数状态下还未实现,经测试,得出的算式正常,但是问题来了
上面得到的算式是uni编码,即得到的字符串为wchar_t类型,我的计算器却是识别char类型的字符串识别的。
然后去查找资料,暂时解决方法是用wcstombs_s函数来吧wchar_t字符串转为char类型。
void EQAtoSUB() { wchar_t *sub; sub = EQA.GetBuffer(EQA.GetLength()); size_t len = wcslen(sub) + 1; size_t converted = 0; SUB = (char*)malloc(len*sizeof(char)); wcstombs_s(&converted, SUB, len, sub, _TRUNCATE); }
姑且算是解决了,其实想修改计算器部分的,但是要到交作业的时候了,先用这种转换的方式实现一下。
整合两者后,发现问题了,小数运算的答案和用户输入的答案并不一致(浮点数的精度问题),用==的方式不可能确定答对与否。
想了想,其实解决也很简单,只要二者之差的绝对值不超过规定的小数位数精度即可。
测试,OK,但是分数计算、带余数的除法计算等问题还有待解决。
0.2版本的随机计算器就是这样了。
第一周 | 第二周 | 第三周 | 第四周 | 第五周 | 第六周 | |
时间 | 未计 | 未计 | ||||
代码量 | 100 | 500 | ||||
博客量 | 1 | 1 | ||||
了解的知识点 | git | 字符类型 |
相关文章推荐
- 重构第0天--重构的理解
- 对Volley网络框架的一些理解
- The Ins and Outs of Token Based Authentication
- eclipse代码行如何让它显示
- iOS 打包出现 Your session has expired. Please log in.
- 简单java连接oracle,Statement,PreparedStatement,CallableStatement操作
- iOS 自定义启动app URL Scheme 帮你实现
- HTML基础篇--html标签
- 根据Android 传感器控制3D模型方向
- 自定义进度条的颜色大小
- adb概览及协议參考
- SharePoint "System.Data.SqlClient.SqlException (0x80131904): Parameter '@someColumn' was supplied multiple times.“
- 使用MinHash算法计算两个集合的相似度
- jQuery设置checkbox全选(区别jQuery版本)
- 关于Android APP在线热修复bug方案的调研(三)(集成Nuwa遇到的坑与解决)
- 友盟多渠道打包
- 栈的链表实现
- 自定义注解和aop结合使用---自定义日志记录的实现
- CentOS 7.1使用yum安装MySql5.6.24
- 转:eclipse与myeclipse恢复已删除的文件和代码