- 注册时间
- 2016-4-18
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 415
- 在线时间
- 小时
|
发表于 2017-1-3 13:20:54
|
显示全部楼层
本帖最后由 happysxyf 于 2017-1-3 17:25 编辑
如果你使用逆波兰,你就没有这些问题了,我又花了几小时写了个逆波兰,这个的计算结果跟SpeedCrunch软件的完全吻合,运算优先级完全一致。只要你用逆波兰那些优先级都是一致的。只是我没加入高精度,其实大体框架已经成了。就差做个计算器的界面和按钮 以及 调用GMP的大数库提高点精度。
我的代码,本来只有100行,为了弄精致点变成了- /*
- REVERSE POLISH EXPRESSION CALCULATOR, COPYRIGHT@2017~2019 BY HAPPYSXYF
- REVPOLISH.EXE
- VERSION 1.0
- */
- #include <stdio.h>
- #include <ctype.h>
- #include <math.h>
- #include <windows.h>
- /***************定义宏变量***************/
- //堆栈尺寸
- #define STACK_SIZE 1024
- //数学函数关键词数
- #define KEY_SIZE 23
- //帮助说明
- #define HELPINFORMATION "\
- REVERSE POLISH EXPRESSION CALCULATOR, VERSION 1.0\n\
- -----------------------------------------------------------------\n\
- revpolish [expression]\n\
- -----------------------------------------------------------------\n\
- EXAMPLES:\n\
- revpolish ((3*3+2)%6+7.187)*5-7/189+3^2\n\
- revpolish (ceil(sin(pi/3)+2)%6+0.187)*e-lg(6.5)\n\
- revpolish 5*(arctan(cos(sin(ln(lg(2.71828))))))\n\
- -----------------------------------------------------------------\n\
- FUNCTIONS:\n\
- pi=3.1415926535897932, e=2.7182818284590452\n\
- +, -, *, /, %, ^, !\n\
- round, floor, ceil, exp, deg, sqrt, abs, lg, ln\n\
- sin, cos, tan, arcsin, arccos, arctan\n\
- sinh, cosh, tanh, arcsinh, arccosh, arctanh\n\
- -----------------------------------------------------------------\n\
- COPYRIGHT@2017~2019 BY HAPPYSXYF 2017-01-03\n"
- /***************全局类变量***************/
- //数学函数关键词
- static const char* KEY_WORDS[]={"arcsinh", "arccosh", "arctanh", "arcsin", "arccos", "arctan", "round", "floor", "ceil", "sqrt", "deg", "sinh", "cosh", "tanh", "lg", "ln", "sin", "cos", "tan", "abs", "exp", "e", "pi"};
- static const char KEY_LLENS[]={ 7, 7, 7, 6, 6, 6, 5, 5, 4, 4, 3, 4, 4, 4, 2, 2, 3, 3, 3, 3, 3, 1, 2 };
- //运算符栈
- char STACK1[STACK_SIZE]={0};
- //逆波兰栈
- char STACK2[STACK_SIZE]={0};
- //浮点数栈
- double STACK3[STACK_SIZE]={0};
- /***************功能函数类***************/
- //判断逆波兰函数符,即大写字母
- inline BOOL isLETTER(const char c)
- {
- if('A'<=c && c<='Z'){return TRUE;}
- return FALSE;
- }
- //判断浮点数,包括小数点
- inline BOOL isDDIGIT(const char c)
- {
- if( ('0'<=c&&c<='9') || c=='.'){return TRUE;}
- return FALSE;
- }
- //阶乘函数
- int fact(int n)
- {
- return (n<2) ?1 :n*(fact(n-1));
- }
- //识别关键词
- char IdentifyKeyWords(char* pstr)
- {
- char SN;
-
- for(SN=0; SN<KEY_SIZE; SN++){
-
- char *op=pstr, *kp=(char*)KEY_WORDS[SN];
- //比对字母
- while(*op==*kp && *kp!='\0'){
- op++, kp++;
- }
- //尾部验证
- if((*op<'a'||*op>'z') && (*kp=='\0')){
- return SN;
- }
- }
- return -1;
- }
- //逆波兰核心
- void RevPolishCore(const char* expression)
- {
- char *op=(char*)expression, *S1=STACK1, *S2=STACK2, SN;
- double *S3=STACK3;
-
- //逆波兰化
- while(*op!='\0')
- {
- if(isspace(*op)){
- op++;
- continue;
- }
- //判断伪双目
- if( (SN=IdentifyKeyWords(op)) !=-1)
- {
- *(S2++)='.';
- *(S2++)=' ';
- //伪双目入栈
- while(isLETTER(*S1))
- {
- *(S2++)=*(S1--);
- }
- *(++S1)=SN+65;
- op+=KEY_LLENS[SN];
- continue;
- }
- switch(*op)
- {
- case '(':
- *(++S1)=*op;
- if(*(op+1)=='-' || *(op+1)=='+'){
- *(S2++)='0', *(S2++)=' ';
- }
- break;
- case ')':
- while(*S1!='(')
- {
- *(S2++)=*(S1--);
- }
- //舍弃'('
- S1--;
- break;
- case '+':
- case '-':
- while(S1!=STACK1 && *S1!='(')
- {
- *(S2++)=*(S1--);
- }
- *(++S1)=*op;
- break;
- case '^':
- while(isLETTER(*S1))
- {
- *(S2++)=*(S1--);
- }
- *(++S1)=*op;
- break;
- case '!':
- *(S2++)=*op;
- break;
- case '%':
- case '*':
- case '/':
- while(isLETTER(*S1) ||*S1=='%' ||*S1=='*' ||*S1=='/' ||*S1=='^')
- {
- *(S2++)=*(S1--);
- }
- *(++S1)=*op;
- break;
- default :
- //浮点数入栈
- while(isDDIGIT(*op)){
- *(S2++)=*(op++);
- }
- op--;
- *(S2++)=' ';
- break;
- }
- op++;
- }
- while(S1 !=STACK1)
- {
- *(S2++)=*(S1--);
- }
- *S2=' ';
- //计算逆波兰
- op=STACK2;
- while(*op!=' ')
- {
- //计算伪双目
- if(isLETTER(*op))
- {
- switch(*op)
- {
- case 'A':
- *(S3-1)=asinh(*S3);
- break;
- case 'B':
- *(S3-1)=acosh(*S3);
- break;
- case 'C':
- *(S3-1)=atanh(*S3);
- break;
- case 'D':
- *(S3-1)=asin(*S3);
- break;
- case 'E':
- *(S3-1)=acos(*S3);
- break;
- case 'F':
- *(S3-1)=atan(*S3);
- break;
- case 'G':
- *(S3-1)=round(*S3);
- break;
- case 'H':
- *(S3-1)=floor(*S3);
- break;
- case 'I':
- *(S3-1)=ceil(*S3);
- break;
- case 'J':
- *(S3-1)=sqrt(*S3);
- break;
- case 'K':
- *(S3-1)=(*S3)*3.1415926535897932/180.0;
- break;
- case 'L':
- *(S3-1)=sinh(*S3);
- break;
- case 'M':
- *(S3-1)=cosh(*S3);
- break;
- case 'N':
- *(S3-1)=tanh(*S3);
- break;
- case 'O':
- *(S3-1)=log10(*S3);
- break;
- case 'P':
- *(S3-1)=log(*S3);
- break;
- case 'Q':
- *(S3-1)=sin(*S3);
- break;
- case 'R':
- *(S3-1)=cos(*S3);
- break;
- case 'S':
- *(S3-1)=tan(*S3);
- break;
- case 'T':
- *(S3-1)=(*S3<0)?(-(*S3)):(*S3);
- break;
- case 'U':
- *(S3-1)=exp(*S3);
- break;
- case 'V':
- *S3=2.7182818284590452;
- break;
- case 'W':
- *S3=3.1415926535897932;
- break;
- default :
- break;
- }
- if(*op!='V' && *op!='W'){S3--;}
- op++;
- continue;
- }
- //计算双目
- switch(*op)
- {
- case '+':
- *(S3-1)+=*S3;
- S3--;
- break;
- case '-':
- *(S3-1)-=*S3;
- S3--;
- break;
- case '*':
- *(S3-1)*=*S3;
- S3--;
- break;
- case '%':
- case '/':
- if(S3 !=STACK3){
- if(*op=='%'){
- *(S3-1)=(int)*(S3-1) % (int)*S3;
- }else{
- *(S3-1)/=*S3;
- }
-
- }else{
- //除数为0,抛出错误并退出
- fputs("Divisor is zero error\n", stderr);
- exit(0);
- }
- S3--;
- break;
- case '^':
- *(S3-1)=pow(*(S3-1), *S3);
- S3--;
- break;
- case '!':
- *S3=fact((int)(*S3));
- break;
- default :
- //集数器
- if (isDDIGIT(*op)){
- *(++S3)=atof(op);
- }
- while(isDDIGIT(*op)){
- op++;
- }
- break;
- }
- op++;
- }
-
- //打印中缀式
- fprintf(stdout, "ORIGINALEXP: %s\n", expression);
- //打印后缀式
- fprintf(stdout, "REVPOLISH: ");
- op=STACK2;
- while(op!=S2){
- if(*op=='.' && *(op+1)==' '){
- op++;
- }else if(isLETTER(*op)){
- fprintf(stdout, "%s ", KEY_WORDS[*op-65]);
-
- }else{
- fputc(*op, stdout);
- if(*op=='+' ||*op=='-' ||*op=='*' ||*op=='/' ||*op=='%' ||*op=='^' ||*op=='!'){fputc(' ', stdout);}
- }
- op++;
- }
- fputc('\n', stdout);
- //打印计算结果
- fprintf(stdout, "RESULT: %.16lf\n", *S3);
- }
- /*************MAIN主函数入口*************/
- int main(int argc, char** argv)
- {
- if(argc==1){
- //异常则抛出使用说明
- fputs(HELPINFORMATION, stderr);
- exit(1);
- }
- RevPolishCore(argv[1]);
- return 0;
- }
复制代码 300行:
以下是说明
- 用法:
- -----------------------------------------------------------------------------
- revpolish [expression]
- -----------------------------------------------------------------------------
- 示例:
- revpolish ((3*3+2)%6+7.187)*5-7/189+3^2
- revpolish (ceil(sin(pi/3)+2)%6+0.187)*e-lg(6.5)
- revpolish 5*(arctan(cos(sin(ln(lg(2.71828))))))
- -----------------------------------------------------------------------------
- 备注:
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 常数类
- pi 3.1415926535897932
- e 2.7182818284590452
- 通用类
- round 四舍五入
- floor 整取
- abs 绝对值
- ceil 向上舍入
- deg 角度转弧度
- exp e的次幂
- sqrt 开方
- fac 阶乘
- lg 常用对数,以10为底
- ln 自然对数
- + 加
- - 减
- * 乘
- / 除
- % 取余数
- ^ 次方
- ! 阶乘
- 三角函数类
- sin、cos、tan
- arcsin、arccos、arctan
- 双曲函数类
- sinh、cosh、tanh
- arcsinh、arccosh、arctanh
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
复制代码
源码都是完整的,直接就能编译,如果你的机器无法编译C语言请下载我的附件。我就差个高精度和计算器按钮界面了。 |
-
-
revpolish.zip
8.95 KB, 下载次数: 12, 下载积分: 金币 -1 枚, 经验 1 点, 下载 1 次
逆波兰计算器
|