您的位置:首页 > 其它

关于未成品的问题:字符类型和其他种种

2016-03-14 17:35 288 查看
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版本的随机计算器就是这样了。

第一周第二周第三周第四周第五周第六周
时间未计未计
代码量100500
博客量11
了解的知识点git字符类型
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: