找回密码
 欢迎注册
楼主: 落叶

[原创] 落叶高精度表达式计算器v1.0版

[复制链接]
 楼主| 发表于 2017-1-3 14:55:05 | 显示全部楼层
谢谢你的分析,源码,帮我从另一个角度理解表达式解析,等我回来用vc调试理解理解。
我的乘方和阶乘的判断错了,是因为我为每个运算符都定义了一个运算等级,把乘方理解为单操数运算符了,所以把它和阶乘的等级定为同级,现重新定义了等级,问题已经解决。
对于连续乘方应该是从左向右,还是从右向左,国内几个表达式计算器也是从左向右算的,具体数学上是怎么定义的,我不清楚,所以我暂时没有调整,但如何从右向左算乘方,目前我也想到了解决办法。假如老外是对的,我再改过来。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2017-1-3 16:47:54 | 显示全部楼层
本帖最后由 happysxyf 于 2017-1-3 17:18 编辑
落叶 发表于 2017-1-3 14:55
谢谢你的分析,源码,帮我从另一个角度理解表达式解析,等我回来用vc调试理解理解。
我的乘方和阶乘的判断 ...


好的,我一直都是按照老外的优先级来的,因为那样在解决一些数学问题时很有优势。
对了,那个代码只适合gcc编译器,VC需要小改一下。逆波兰是速度最快的算法,也是内存占用最小的。
为了省事,我全部用了双目运算,即使是sin之类的也是用伪双目模拟的,这样做节省了一半代码。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2017-1-5 14:48:40 | 显示全部楼层
本帖最后由 落叶 于 2017-1-5 17:23 编辑
happysxyf 发表于 2017-1-3 16:47
好的,我一直都是按照老外的优先级来的,因为那样在解决一些数学问题时很有优势。
对了,那个代码只适 ...


数字帝国的表达式计算,乘方也是从右向左算,老外的是对的,我的计算器已改过来,1.1版加上批处理和赋值语句后一起更新。
你用过我的ABC公式,算式存取功能吗?我想把它取消,全部用赋值语句存储,不知道那种方法更易用?例:用A=3+5;    代替现在的算式存入功能。

另外你的代码质量很高,看的很舒服易懂,写码速度远超过我,你写码有二年了吧?或天赋太强?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2017-1-7 11:18:05 | 显示全部楼层
本帖最后由 happysxyf 于 2017-1-7 11:22 编辑
落叶 发表于 2017-1-5 14:48
数字帝国的表达式计算,乘方也是从右向左算,老外的是对的,我的计算器已改过来,1.1版加上批处理和赋 ...


我是新手,自学C语言才半年。我的是在批处理中就直接支持批量计算,可以每秒计算1000万行。
这改是我的进版,增加了错误反馈,速度比前面的代码提升10倍左右。

  1. /*
  2.     REVERSE POLISH EXPRESSION CALCULATOR, COPYRIGHT@2017~2019 BY HAPPYSXYF
  3.     REVPOLISH.EXE
  4.     VERSION 1.6
  5. */

  6. #include   <stdio.h>
  7. #include   <ctype.h>
  8. #include    <math.h>
  9. #include <windows.h>

  10. /***************定义宏变量***************/
  11. //堆栈尺寸
  12. #define  STACK_SIZE   1024
  13. //帮助说明
  14. #define HELPINFORMATION "\
  15. REVERSE POLISH EXPRESSION CALCULATOR,COPYRIGHT@2017~2019 BY HAPPYSXYF\n\
  16. -----------------------------------------------------------------\n\
  17. revpolish [expression]\n\
  18. -----------------------------------------------------------------\n\
  19. FUNCTIONS:\n\
  20.     pi=3.1415926535897932, e=2.7182818284590452\n\
  21.     +, -, *, /, %, ^, !\n\
  22.     round, floor, ceil, exp, deg, sqrt, abs, lg, ln\n\
  23.     sin, cos, tan, arcsin, arccos, arctan\n\
  24.     sinh, cosh, tanh, arcsinh, arccosh, arctanh\n\
  25. -----------------------------------------------------------------\n\
  26. 2017-01-05  VERSION 1.6\n"

  27. /***************全局类变量***************/
  28. //数学函数关键词
  29. static const char* KEY_WORDS[]={"e", "pi", "sqrt", "lg", "ln", "sin", "cos", "tan", "arcsin", "arccos", "arctan", "deg", "abs", "round", "floor", "ceil", "exp", "sinh", "cosh", "tanh", "arcsinh", "arccosh", "arctanh", NULL};
  30. //运算符栈
  31. char   STACK1[STACK_SIZE]={0};
  32. //逆波兰栈
  33. char   STACK2[STACK_SIZE]={0};
  34. //浮点数栈
  35. double STACK3[STACK_SIZE]={0};

  36. /***************功能函数类***************/
  37. //阶乘函数
  38. long long fact(long long n)
  39. {
  40.     return (n<2) ?1 :n*(fact(n-1));
  41. }
  42. //逆波兰核心
  43. double RevPolishCore(const char* expression)
  44. {
  45.         char   *op=(char*)expression, *S1=STACK1, *S2=STACK2, **key, *cp, *kp;
  46.         double *S3=STACK3, di, ni;
  47.        
  48.         //生成逆波兰       
  49.         while(*op!='\0'){               
  50.                 switch(*op){
  51.                 case ' ' :
  52.                 case '\t':
  53.                 case '\r':
  54.                 case '\n':
  55.                         //过滤空字符
  56.                         op++;
  57.                         continue;

  58.                 case 'a':
  59.                 case 'b':
  60.                 case 'c':
  61.                 case 'd':
  62.                 case 'e':
  63.                 case 'f':
  64.                 case 'g':
  65.                 case 'h':
  66.                 case 'i':
  67.                 case 'j':
  68.                 case 'k':
  69.                 case 'l':
  70.                 case 'm':
  71.                 case 'n':
  72.                 case 'o':
  73.                 case 'p':
  74.                 case 'q':
  75.                 case 'r':
  76.                 case 's':
  77.                 case 't':
  78.                 case 'u':
  79.                 case 'v':
  80.                 case 'w':
  81.                 case 'x':
  82.                 case 'y':
  83.                 case 'z':
  84.                         //识别数学函数关键词
  85.                         key=(char**)KEY_WORDS;
  86.                         while(*key !=NULL){       
  87.                                 cp=op, kp=*key;
  88.                                 //比对关键词字母
  89.                                 while(*cp==*kp && *kp!='\0'){
  90.                                         cp++, kp++;
  91.                                 }
  92.                                 //验证关键词结尾
  93.                                  if((*cp<'a'||*cp>'z') && (*kp=='\0')){
  94.                                          op=cp;
  95.                                         break;
  96.                                 }
  97.                                 key++;
  98.                         }
  99.                         //构建伪双目
  100.                         if(*key !=NULL){                               
  101.                                 *(S2++)='.';
  102.                                 *(S2++)=' ';
  103.                                 //伪双目入栈
  104.                                 while('A'<=(*S1) && (*S1)<='Z'){
  105.                                         *(S2++)=*(S1--);
  106.                                 }
  107.                                 *(++S1)=key-(char**)KEY_WORDS+65;
  108.                                 continue;
  109.                         }else{
  110.                                 //无法识别的数学函数
  111.                                 fputs("Unrecognized math function\n", stderr);
  112.                                 exit(1);
  113.                         }
  114.                         break;
  115.                
  116.                 case '(':
  117.                         *(++S1)=*op;
  118.                         if(*(op+1)=='-' || *(op+1)=='+'){
  119.                                 *(S2++)='0', *(S2++)=' ';
  120.                         }
  121.                         break;

  122.                 case ')':
  123.                         while(*S1!='(')
  124.                         {
  125.                                 *(S2++)=*(S1--);
  126.                         }               
  127.                         //舍弃'('
  128.                         S1--;               
  129.                         break;

  130.                 case '+':
  131.                 case '-':
  132.                         while(S1!=STACK1 && *S1!='(')
  133.                         {
  134.                                 *(S2++)=*(S1--);
  135.                         }
  136.                         *(++S1)=*op;
  137.                         break;

  138.                 case '^':
  139.                         //指数符
  140.                         while('A'<=(*S1) && (*S1)<='Z')
  141.                         {
  142.                                 *(S2++)=*(S1--);
  143.                         }
  144.                         *(++S1)=*op;
  145.                         break;

  146.                 case '!':
  147.                         //阶乘符
  148.                         *(S2++)=*op;
  149.                         break;

  150.                 case '%':
  151.                 case '*':
  152.                 case '/':
  153.                         while(('A'<=(*S1) && (*S1)<='Z') ||*S1=='%' ||*S1=='*' ||*S1=='/' ||*S1=='^'){
  154.                                 *(S2++)=*(S1--);
  155.                         }
  156.                         *(++S1)=*op;
  157.                         break;

  158.                 default :
  159.                         if((*op<'0' || *op>'9') && (*op!='.')){
  160.                                 //无法识别的运算符
  161.                                 fputs("Unrecognized operator\n", stderr);
  162.                                 exit(1);
  163.                         }
  164.                         //浮点数入栈
  165.                         while(('0'<=*op && *op<='9') ||*op=='.'){
  166.                                 *(S2++)=*(op++);
  167.                         }
  168.                         op--;
  169.                         *(S2++)=' ';
  170.                         break;
  171.                 }
  172.                 op++;
  173.         }
  174.         //收尾逆波兰
  175.         while(S1 !=STACK1){*(S2++)=*(S1--);}
  176.         *S2=' ';

  177.         //计算逆波兰
  178.         op=STACK2;
  179.         while(*op!=' '){
  180.                 switch(*op){
  181.                 case 'A':
  182.                         *S3=2.7182818284590452;
  183.                         break;
  184.                 case 'B':
  185.                         *S3=3.1415926535897932;
  186.                         break;
  187.                 case 'C':
  188.                         if(*S3 <0){
  189.                                 //负数没有平方根
  190.                                 fputs("Negative numbers have no square root\n", stderr);
  191.                                 exit(1);
  192.                         }
  193.                         *(S3-1)=sqrt(*S3);
  194.                         S3--;
  195.                         break;
  196.                 case 'D':
  197.                         if(*S3 <0){
  198.                                 //负数没有对数
  199.                                 fputs("Negative numbers are not logarithmic\n", stderr);
  200.                                 exit(1);
  201.                         }
  202.                         *(S3-1)=log10(*S3);
  203.                         S3--;
  204.                         break;
  205.                 case 'E':
  206.                         if(*S3 <0){
  207.                                 //负数没有自然对数
  208.                                 fputs("Negative numbers have no natural logarithms\n", stderr);
  209.                                 exit(1);
  210.                         }
  211.                         *(S3-1)=log(*S3);
  212.                         S3--;
  213.                         break;
  214.                 case 'F':
  215.                         *(S3-1)=sin(*S3);
  216.                         S3--;
  217.                         break;
  218.                 case 'G':
  219.                         *(S3-1)=cos(*S3);
  220.                         S3--;
  221.                         break;
  222.                 case 'H':
  223.                         if(*S3==3.1415926535897932/2){
  224.                                 //π/2没有正切值
  225.                                 fputs("The pi/2 has no tangent\n", stderr);
  226.                                 exit(1);
  227.                         }
  228.                         *(S3-1)=tan(*S3);
  229.                         S3--;
  230.                         break;
  231.                 case 'I':
  232.                         *(S3-1)=asin(*S3);
  233.                         S3--;
  234.                         break;
  235.                 case 'J':
  236.                         *(S3-1)=acos(*S3);
  237.                         S3--;
  238.                         break;
  239.                 case 'K':
  240.                         *(S3-1)=atan(*S3);
  241.                         S3--;
  242.                         break;
  243.                 case 'L':
  244.                         *(S3-1)=(*S3)*3.1415926535897932/180.0;
  245.                         S3--;
  246.                         break;
  247.                 case 'M':
  248.                         *(S3-1)=(*S3<0)?(-(*S3)):(*S3);
  249.                         S3--;
  250.                         break;
  251.                 case 'N':
  252.                         *(S3-1)=round(*S3);
  253.                         S3--;
  254.                         break;
  255.                 case 'O':
  256.                         *(S3-1)=floor(*S3);
  257.                         S3--;
  258.                         break;
  259.                 case 'P':
  260.                         *(S3-1)=ceil(*S3);
  261.                         S3--;
  262.                         break;
  263.                 case 'Q':
  264.                         *(S3-1)=exp(*S3);
  265.                         S3--;
  266.                         break;
  267.                 case 'R':
  268.                         *(S3-1)=sinh(*S3);
  269.                         S3--;
  270.                         break;
  271.                 case 'S':
  272.                         *(S3-1)=cosh(*S3);
  273.                         S3--;
  274.                         break;
  275.                 case 'T':
  276.                         *(S3-1)=tanh(*S3);
  277.                         S3--;
  278.                         break;
  279.                 case 'U':
  280.                         *(S3-1)=asinh(*S3);
  281.                         S3--;
  282.                         break;
  283.                 case 'V':
  284.                         *(S3-1)=acosh(*S3);
  285.                         S3--;
  286.                         break;
  287.                 case 'W':
  288.                         *(S3-1)=atanh(*S3);
  289.                         S3--;
  290.                         break;
  291.                 case '+':
  292.                         *(S3-1)+=*S3;
  293.                         S3--;
  294.                         break;
  295.                 case '-':
  296.                         *(S3-1)-=*S3;
  297.                         S3--;
  298.                         break;
  299.                 case '*':
  300.                         *(S3-1)*=*S3;
  301.                         S3--;
  302.                         break;
  303.                 case '%':
  304.                 case '/':
  305.                         if(*S3 !=0){
  306.                                 if(*op=='%'){
  307.                                         //取余数
  308.                                         *(S3-1)=(int)*(S3-1) % (int)*S3;
  309.                                 }else{
  310.                                         *(S3-1)/=*S3;
  311.                                 }
  312.                                
  313.                         }else{
  314.                                 //除数不能为零
  315.                                 fputs("Divisor is zero error\n", stderr);
  316.                                 exit(1);
  317.                         }
  318.                         S3--;
  319.                         break;
  320.                 case '^':
  321.                         if(*(S3-1)==0 && *S3<0){
  322.                                 //除数不能为零
  323.                                 fputs("Function pow's divisor is zero error\n", stderr);
  324.                                 exit(1);
  325.                         }
  326.                         *(S3-1)=pow(*(S3-1), *S3);
  327.                         S3--;
  328.                         break;
  329.                 case '!':
  330.                         if(*S3 <0){
  331.                                 //负数没有阶乘
  332.                                 fputs("Negative numbers have no factorial\n", stderr);
  333.                                 exit(1);
  334.                         }
  335.                         *S3=fact((long long)(*S3));
  336.                         break;
  337.                 default :
  338.                         //字符串转浮点
  339.                         di=0, ni=1;
  340.                         while('0'<=*op && *op<='9'){
  341.                                 di=10*di+(*op)-'0';
  342.                                 op++;
  343.                         }       
  344.                         if(*op=='.'){
  345.                                 op++;
  346.                                 while('0'<=*op && *op<='9'){
  347.                                         di=10*di+(*op)-'0';
  348.                                         op++, ni*=10;
  349.                                 }       
  350.                         }
  351.                         *(++S3)=di/ni;
  352.                         break;
  353.                 }
  354.                 op++;
  355.         }

  356.         /////////////////////////////////////////////////////////////////////
  357.         //返回计算结果
  358.         //return *S3;

  359.         //打印中缀式
  360.         fprintf(stdout, "ORIGINALEXP: %s\n", expression);

  361.         //打印后缀式
  362.         fprintf(stdout, "REVPOLISH:   ");
  363.         op=STACK2;
  364.         while(op!=S2){
  365.                 if(*op=='.' && *(op+1)==' '){
  366.                         op++;

  367.                 }else if('A'<=(*op) && (*op)<='Z'){
  368.                         fprintf(stdout, "%s ", KEY_WORDS[*op-65]);
  369.                        
  370.                 }else{
  371.                         fputc(*op, stdout);
  372.                         if(*op=='+' ||*op=='-' ||*op=='*' ||*op=='/' ||*op=='%' ||*op=='^' ||*op=='!'){fputc(' ', stdout);}
  373.                 }
  374.                 op++;
  375.         }
  376.         fputc('\n', stdout);

  377.         //打印计算结果
  378.         fprintf(stdout, "RESULT:      %.16lf\n", *S3);
  379. }

  380. /*************MAIN主函数入口*************/
  381. int main(int argc, char** argv)
  382. {
  383.         if((argc==1) || (argc==2 && argv[1][0]=='/' && (argv[1][1]=='?'||argv[1][1]=='h'))){
  384.                 //使用说明
  385.                 fputs(HELPINFORMATION, stderr);
  386.                 exit(1);
  387.         }
  388.         RevPolishCore(argv[1]);
  389.         return 0;
  390. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2017-1-7 11:41:44 | 显示全部楼层
本帖最后由 落叶 于 2017-1-7 13:05 编辑

学了半年就能这水平,只能让我汗颜,我虽然去年才开始学写代码,但之前可是看了十多年计算机方面的书,学的广而泛,
看你的新代码加入了输入值校验功能,看来你也意识到这方面的重要性,我为我的计算器加这个功能可是用了一个多月,
就这样windows的异常处理我还没尝试过,因为关于计算器测试方面的资料没查到。
整个计算器的最终测试用了快两月,才有了一个大致的头绪,里面还没考虑到的问题还多多。
在表达式中支持空格,回车换行,并在解析表达式前除去你也采用了,这点可以增加用户使用体验。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2017-1-7 13:39:26 | 显示全部楼层
落叶 发表于 2017-1-7 11:41
学了半年就能这水平,只能让我汗颜,我虽然去年才开始学写代码,但之前可是看了十多年计算机方面的书,学的 ...


是的,基本的计算器结构都差不多,都是逆波兰式。你的计算器关键是支持大数和高精度,这点就非常了不起,还有你支持函数定义吗?比如定义 f(x)=sin(x)/x;直接输入f(3.5)求值。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2017-1-7 13:47:35 | 显示全部楼层
本帖最后由 落叶 于 2017-1-7 14:31 编辑

不支持,高精度这块也没什么要做的,主要定位是用户体验。其实这个计算器最难的是高精度和表达式运算结合在一起。这个计算器最难的是这个框架的建立。
如果只是你所述的函数定义,我考虑了一下,可以快速实现,因为它的核心也是表达式计算,而这个是我计算器的主要功能。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2017-1-7 14:04:44 | 显示全部楼层
落叶 发表于 2017-1-7 13:47
不支持,高精度这块也没什么要做的,主要定位是用户体验。其实这个计算器最难的是高精度和表达式运算结合在 ...

要是能绘图就更好了
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2017-1-7 14:45:52 来自手机 | 显示全部楼层
本帖最后由 落叶 于 2017-1-7 14:51 编辑

我的算式存入功能也可实现函数功能,只是不直观,多看看帮助,刚乱码了,我举的例子乱码了。以后增加赋值语句后会有所改观的。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2017-1-7 17:17:57 | 显示全部楼层
happysxyf 发表于 2017-1-7 14:04
要是能绘图就更好了

那个绘图就没办法了,那需要团队合作,我既使免强做出一点,也会画虎不成反类猫,个人开发,只能专而精,知识也跟不上。

想请问一下你,你的关键字识别所用方法是你自己所想的吗?比我的方法好多了,我要借荐你的方法。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-12-27 04:52 , Processed in 0.027977 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表