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

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

[复制链接]
 楼主| 发表于 2016-12-28 19:57:14 | 显示全部楼层
本帖最后由 落叶 于 2016-12-28 19:59 编辑
happysxyf 发表于 2016-12-28 19:14
表达式解析,最好还是用逆波兰特最简单,速度最快,内存占用最小,我实现表达式计算只要3小时。但是我不 ...


天哪,你表达式实现只要了三小时,你知道我构思基本通过用了多少?用了两个月,中间完善大概四个月吧,就这样我还觉得不可思议,感觉太快了!
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2016-12-29 12:02:03 | 显示全部楼层
落叶 发表于 2016-12-28 19:33
http://bbs.emath.ac.cn/thread-8882-2-1.html这里有我向宝宝请教对数的贴子,我的主题里有对三角函数的学 ...

好的,感谢提供思路,因为逆波兰特是几乎所有现代计算机的实现方式。太经典,所以必须得用。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2016-12-29 17:20:36 | 显示全部楼层
本帖最后由 落叶 于 2016-12-29 20:15 编辑

我已过了需要表扬的年龄了,首先在这里第一个发布,就是来让网友们批评,指正的,错误啥的大量接收!
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2016-12-30 19:02:44 | 显示全部楼层
本帖最后由 happysxyf 于 2016-12-30 19:06 编辑
落叶 发表于 2016-12-29 17:20
我已过了需要表扬的年龄了,首先在这里第一个发布,就是来让网友们批评,指正的,错误啥的大量接收!


落叶,你的计算器非常好用,暂无漏洞。圆周率很快,准确无误。
但是居然没有排列组合数,这个经常需要用到。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2016-12-31 02:00:41 | 显示全部楼层
本帖最后由 落叶 于 2016-12-31 02:05 编辑

整体框架现比较完善,加功能很方便的,批量计算已想好,1.1版再加上,发现一个问题,x的负一次方忘了判断,现计算是错的。
那个圆周率我没有计算,存了一个万位常数直接读取。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2016-12-31 11:02:17 | 显示全部楼层
落叶 发表于 2016-12-31 02:00
整体框架现比较完善,加功能很方便的,批量计算已想好,1.1版再加上,发现一个问题,x的负一次方忘了判断, ...


怪不得计算派都不需要时间,直接就出来了。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2017-1-2 15:47:51 | 显示全部楼层
本帖最后由 落叶 于 2017-1-2 19:56 编辑

刚才简单的和SpeedCrunch(老外的成品计算器)在表达式解析方面作了一下测试,(国内的还没找到合适的)
sin(5)
= -0.95892427466313846889

((((((((2^2)*2)^2)*2)^2)*2)^2)^2)*2
= 2305843009213693952

-((((((((2^2)*2)^2)*2)^2)*2)^2)^2)*2
= -2305843009213693952

23+56/(102-100)*((36-24)/(8-6))
= 191

1.55- 1.55^3/3! +1.55^5/5! - 1.55^7/7!+ 1.55^9/9!
= 0.99978682495119270984

1.55- 1.55*1.55^2*(4*5*6*7*8*9 - 1.55^2*(6*7*8*9 - 1.55^2*(8*9- 1.55^2)))/9!
= 0.99978682495119270984

sin(6)+3
= 2.72058450180107412719

cos(sin(6)^4)^6
= 0.99988854394413890284

cos (sin(6)^ 4)^ 6
= 0.99988854394413890284

cos(sin(-6)^4)^6
= 0.99988854394413890284

cos(-sin(6)^4)^6
= 0.99988854394413890284

2^cos(sin(6)^4)^6
= 1.9998454950664980933


上面有红色部分和我的不一致:
我的是:2^cos(sin(6)^4)^6  =6.3995055612514362198736651007398E1
然后加上括号后:2^(cos(sin(6)^4)^6 )  =1.9998454950664980933018590689861,这时才和它的结果保持一致,
不知道从语法上到底是谁才是对的?
SpeedCrunch的:2^sin(3)^2= 1.01389964085539956385,我的:2^sin(3)^2  =1.216081581587201296984729037121值不同
2^sin(3)*2= 2.20552178097356481036但这个数 SpeedCrunch的和我一致,看来它采用的是乘方指数优先原则。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2017-1-2 16:36:01 | 显示全部楼层
本帖最后由 落叶 于 2017-1-2 21:46 编辑

在算4^4!时:
SpeedCrunch的是4^4!= 281474976710656,很明显它是先算了后面的。
我目前把两个运算符的等级定为相等,所以我的是左边先算:4^4! =8.5781777534284265411908227168123E506
不知道两个运算符的数学运算等级是怎么样的,上网查了一下也没查出结果?
单操作数的运算等级应该高于双操作数的,看来它是对的,我的运算符等级需要重新调整一下。开始我把乘方运算定义为单操作数了

又查了一个国内比较牛的人写的表达式计算,运算4^4!采用的规则和它的一样。看来我需要改一下。好了,调了一下运算符等级,现在这个问题已解决。

点评

好的,谢谢你的解答!  发表于 2017-1-5 21:03
阶乘比幂更高优先级。  发表于 2017-1-3 17:09
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2017-1-2 17:03:14 | 显示全部楼层
本帖最后由 落叶 于 2017-1-2 21:19 编辑

SpeedCrunch的3^4^2= 43046721
我的是:3^4^2  =6.561E3
难道两个乘方符号在一起先算右边的?

不过在我的计算器上有个等级最高的括号,若为了表达清晰,请把需要先算的括起来,就可以正常运算了。

又查了几个国内比较牛的人写的表达式计算,采用连续乘方的规则和我的一样。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2017-1-3 13:20:54 | 显示全部楼层
本帖最后由 happysxyf 于 2017-1-3 17:25 编辑
落叶 发表于 2017-1-2 17:03
SpeedCrunch的3^4^2= 43046721
我的是:3^4^2  =6.561E3
难道两个乘方符号在一起先算右边的?

QQ图片20170103132533.png
如果你使用逆波兰,你就没有这些问题了,我又花了几小时写了个逆波兰,这个的计算结果跟SpeedCrunch软件的完全吻合,运算优先级完全一致。只要你用逆波兰那些优先级都是一致的。只是我没加入高精度,其实大体框架已经成了。就差做个计算器的界面和按钮 以及 调用GMP的大数库提高点精度。

我的代码,本来只有100行,为了弄精致点变成了
  1. /*
  2.     REVERSE POLISH EXPRESSION CALCULATOR, COPYRIGHT@2017~2019 BY HAPPYSXYF
  3.     REVPOLISH.EXE
  4.     VERSION 1.0
  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  KEY_SIZE     23
  15. //帮助说明
  16. #define HELPINFORMATION "\
  17. REVERSE POLISH EXPRESSION CALCULATOR, VERSION 1.0\n\
  18. -----------------------------------------------------------------\n\
  19. revpolish [expression]\n\
  20. -----------------------------------------------------------------\n\
  21. EXAMPLES:\n\
  22.     revpolish ((3*3+2)%6+7.187)*5-7/189+3^2\n\
  23.     revpolish (ceil(sin(pi/3)+2)%6+0.187)*e-lg(6.5)\n\
  24.     revpolish 5*(arctan(cos(sin(ln(lg(2.71828))))))\n\
  25. -----------------------------------------------------------------\n\
  26. FUNCTIONS:\n\
  27.     pi=3.1415926535897932, e=2.7182818284590452\n\
  28.     +, -, *, /, %, ^, !\n\
  29.     round, floor, ceil, exp, deg, sqrt, abs, lg, ln\n\
  30.     sin, cos, tan, arcsin, arccos, arctan\n\
  31.     sinh, cosh, tanh, arcsinh, arccosh, arctanh\n\
  32. -----------------------------------------------------------------\n\
  33. COPYRIGHT@2017~2019 BY HAPPYSXYF 2017-01-03\n"

  34. /***************全局类变量***************/
  35. //数学函数关键词
  36. 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"};
  37. 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 };
  38. //运算符栈
  39. char   STACK1[STACK_SIZE]={0};
  40. //逆波兰栈
  41. char   STACK2[STACK_SIZE]={0};
  42. //浮点数栈
  43. double STACK3[STACK_SIZE]={0};

  44. /***************功能函数类***************/
  45. //判断逆波兰函数符,即大写字母
  46. inline BOOL isLETTER(const char c)
  47. {
  48.         if('A'<=c && c<='Z'){return TRUE;}
  49.         return FALSE;       
  50. }
  51. //判断浮点数,包括小数点
  52. inline BOOL isDDIGIT(const char c)
  53. {
  54.         if( ('0'<=c&&c<='9') || c=='.'){return TRUE;}
  55.         return FALSE;       
  56. }
  57. //阶乘函数
  58. int fact(int n)
  59. {
  60.     return (n<2) ?1 :n*(fact(n-1));
  61. }
  62. //识别关键词
  63. char IdentifyKeyWords(char* pstr)
  64. {
  65.         char SN;
  66.        
  67.         for(SN=0; SN<KEY_SIZE; SN++){
  68.                
  69.                 char *op=pstr, *kp=(char*)KEY_WORDS[SN];
  70.                 //比对字母
  71.                 while(*op==*kp && *kp!='\0'){
  72.                         op++, kp++;
  73.                 }
  74.                 //尾部验证
  75.                  if((*op<'a'||*op>'z') && (*kp=='\0')){
  76.                         return SN;
  77.                 }
  78.         }                               
  79.         return -1;
  80. }
  81. //逆波兰核心
  82. void RevPolishCore(const char* expression)
  83. {
  84.         char   *op=(char*)expression, *S1=STACK1, *S2=STACK2, SN;
  85.         double *S3=STACK3;
  86.        
  87.         //逆波兰化       
  88.         while(*op!='\0')
  89.         {
  90.                 if(isspace(*op)){
  91.                         op++;
  92.                         continue;
  93.                 }
  94.                 //判断伪双目
  95.                 if( (SN=IdentifyKeyWords(op)) !=-1)
  96.                 {
  97.                         *(S2++)='.';
  98.                         *(S2++)=' ';
  99.                         //伪双目入栈
  100.                         while(isLETTER(*S1))
  101.                         {
  102.                                 *(S2++)=*(S1--);
  103.                         }
  104.                         *(++S1)=SN+65;
  105.                         op+=KEY_LLENS[SN];
  106.                         continue;
  107.                 }

  108.                 switch(*op)
  109.                 {
  110.                 case '(':
  111.                         *(++S1)=*op;
  112.                         if(*(op+1)=='-' || *(op+1)=='+'){
  113.                                 *(S2++)='0', *(S2++)=' ';
  114.                         }
  115.                         break;
  116.                 case ')':
  117.                         while(*S1!='(')
  118.                         {
  119.                                 *(S2++)=*(S1--);
  120.                         }               
  121.                         //舍弃'('
  122.                         S1--;               
  123.                         break;
  124.                 case '+':
  125.                 case '-':
  126.                         while(S1!=STACK1 && *S1!='(')
  127.                         {
  128.                                 *(S2++)=*(S1--);
  129.                         }
  130.                         *(++S1)=*op;
  131.                         break;
  132.                 case '^':
  133.                         while(isLETTER(*S1))
  134.                         {
  135.                                 *(S2++)=*(S1--);
  136.                         }
  137.                         *(++S1)=*op;
  138.                         break;
  139.                 case '!':
  140.                         *(S2++)=*op;
  141.                         break;
  142.                 case '%':
  143.                 case '*':
  144.                 case '/':
  145.                         while(isLETTER(*S1) ||*S1=='%' ||*S1=='*' ||*S1=='/' ||*S1=='^')
  146.                         {
  147.                                 *(S2++)=*(S1--);
  148.                         }
  149.                         *(++S1)=*op;
  150.                         break;
  151.                 default :
  152.                         //浮点数入栈
  153.                         while(isDDIGIT(*op)){
  154.                                 *(S2++)=*(op++);
  155.                         }
  156.                         op--;
  157.                         *(S2++)=' ';
  158.                         break;
  159.                 }
  160.                 op++;
  161.         }
  162.         while(S1 !=STACK1)
  163.         {
  164.                 *(S2++)=*(S1--);
  165.         }
  166.         *S2=' ';

  167.         //计算逆波兰
  168.         op=STACK2;
  169.         while(*op!=' ')
  170.         {
  171.                 //计算伪双目
  172.                 if(isLETTER(*op))
  173.                 {
  174.                         switch(*op)
  175.                         {
  176.                         case 'A':
  177.                                 *(S3-1)=asinh(*S3);
  178.                                 break;
  179.                         case 'B':
  180.                                 *(S3-1)=acosh(*S3);
  181.                                 break;
  182.                         case 'C':
  183.                                 *(S3-1)=atanh(*S3);
  184.                                 break;
  185.                         case 'D':
  186.                                 *(S3-1)=asin(*S3);
  187.                                 break;
  188.                         case 'E':
  189.                                 *(S3-1)=acos(*S3);
  190.                                 break;
  191.                         case 'F':
  192.                                 *(S3-1)=atan(*S3);
  193.                                 break;
  194.                         case 'G':
  195.                                 *(S3-1)=round(*S3);
  196.                                 break;
  197.                         case 'H':
  198.                                 *(S3-1)=floor(*S3);
  199.                                 break;
  200.                         case 'I':
  201.                                 *(S3-1)=ceil(*S3);
  202.                                 break;
  203.                         case 'J':
  204.                                 *(S3-1)=sqrt(*S3);
  205.                                 break;
  206.                         case 'K':
  207.                                 *(S3-1)=(*S3)*3.1415926535897932/180.0;
  208.                                 break;
  209.                         case 'L':
  210.                                 *(S3-1)=sinh(*S3);
  211.                                 break;
  212.                         case 'M':
  213.                                 *(S3-1)=cosh(*S3);
  214.                                 break;
  215.                         case 'N':
  216.                                 *(S3-1)=tanh(*S3);
  217.                                 break;
  218.                         case 'O':
  219.                                 *(S3-1)=log10(*S3);
  220.                                 break;
  221.                         case 'P':
  222.                                 *(S3-1)=log(*S3);
  223.                                 break;
  224.                         case 'Q':
  225.                                 *(S3-1)=sin(*S3);
  226.                                 break;
  227.                         case 'R':
  228.                                 *(S3-1)=cos(*S3);
  229.                                 break;
  230.                         case 'S':
  231.                                 *(S3-1)=tan(*S3);
  232.                                 break;
  233.                         case 'T':
  234.                                 *(S3-1)=(*S3<0)?(-(*S3)):(*S3);
  235.                                 break;
  236.                         case 'U':
  237.                                 *(S3-1)=exp(*S3);
  238.                                 break;
  239.                         case 'V':
  240.                                 *S3=2.7182818284590452;
  241.                                 break;
  242.                         case 'W':
  243.                                 *S3=3.1415926535897932;
  244.                                 break;
  245.                         default :
  246.                                 break;
  247.                         }
  248.                         if(*op!='V' && *op!='W'){S3--;}
  249.                         op++;
  250.                         continue;                       
  251.                 }

  252.                 //计算双目
  253.                 switch(*op)
  254.                 {
  255.                 case '+':
  256.                         *(S3-1)+=*S3;
  257.                         S3--;
  258.                         break;
  259.                 case '-':
  260.                         *(S3-1)-=*S3;
  261.                         S3--;
  262.                         break;
  263.                 case '*':
  264.                         *(S3-1)*=*S3;
  265.                         S3--;
  266.                         break;
  267.                 case '%':
  268.                 case '/':
  269.                         if(S3 !=STACK3){
  270.                                 if(*op=='%'){
  271.                                         *(S3-1)=(int)*(S3-1) % (int)*S3;
  272.                                 }else{
  273.                                         *(S3-1)/=*S3;
  274.                                 }
  275.                                
  276.                         }else{
  277.                                 //除数为0,抛出错误并退出
  278.                                 fputs("Divisor is zero error\n", stderr);
  279.                                 exit(0);
  280.                         }
  281.                         S3--;
  282.                         break;
  283.                 case '^':
  284.                         *(S3-1)=pow(*(S3-1), *S3);
  285.                         S3--;
  286.                         break;
  287.                 case '!':
  288.                         *S3=fact((int)(*S3));
  289.                         break;
  290.                 default :
  291.                         //集数器
  292.                         if   (isDDIGIT(*op)){
  293.                                 *(++S3)=atof(op);
  294.                         }
  295.                         while(isDDIGIT(*op)){
  296.                                 op++;
  297.                         }
  298.                         break;
  299.                 }
  300.                 op++;
  301.         }
  302.        
  303.         //打印中缀式
  304.         fprintf(stdout, "ORIGINALEXP: %s\n", expression);

  305.         //打印后缀式
  306.         fprintf(stdout, "REVPOLISH:   ");
  307.         op=STACK2;
  308.         while(op!=S2){
  309.                 if(*op=='.' && *(op+1)==' '){
  310.                         op++;

  311.                 }else if(isLETTER(*op)){
  312.                         fprintf(stdout, "%s ", KEY_WORDS[*op-65]);
  313.                        
  314.                 }else{
  315.                         fputc(*op, stdout);
  316.                         if(*op=='+' ||*op=='-' ||*op=='*' ||*op=='/' ||*op=='%' ||*op=='^' ||*op=='!'){fputc(' ', stdout);}
  317.                 }
  318.                 op++;
  319.         }
  320.         fputc('\n', stdout);
  321.         //打印计算结果
  322.         fprintf(stdout, "RESULT:      %.16lf\n", *S3);
  323. }

  324. /*************MAIN主函数入口*************/
  325. int main(int argc, char** argv)
  326. {
  327.         if(argc==1){
  328.                 //异常则抛出使用说明
  329.                 fputs(HELPINFORMATION, stderr);
  330.                 exit(1);
  331.         }
  332.         RevPolishCore(argv[1]);
  333.         return 0;
  334. }
复制代码
300行:

以下是说明
  1. 用法:
  2. -----------------------------------------------------------------------------
  3. revpolish [expression]
  4. -----------------------------------------------------------------------------
  5. 示例:
  6.     revpolish ((3*3+2)%6+7.187)*5-7/189+3^2
  7.     revpolish (ceil(sin(pi/3)+2)%6+0.187)*e-lg(6.5)
  8.     revpolish 5*(arctan(cos(sin(ln(lg(2.71828))))))
  9. -----------------------------------------------------------------------------


  10. 备注:

  11. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  12. 常数类
  13.         pi    3.1415926535897932
  14.         e     2.7182818284590452
  15. 通用类
  16.         round 四舍五入
  17.         floor 整取
  18.         abs   绝对值
  19.         ceil  向上舍入
  20.         deg   角度转弧度
  21.         exp   e的次幂
  22.         sqrt  开方
  23.         fac   阶乘
  24.         lg    常用对数,以10为底
  25.         ln    自然对数
  26.         +     加
  27.         -     减
  28.         *     乘
  29.         /     除
  30.         %     取余数
  31.         ^     次方
  32.         !     阶乘

  33. 三角函数类
  34.         sin、cos、tan   
  35.         arcsin、arccos、arctan

  36. 双曲函数类
  37.         sinh、cosh、tanh
  38.         arcsinh、arccosh、arctanh

  39. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
复制代码


源码都是完整的,直接就能编译,如果你的机器无法编译C语言请下载我的附件。我就差个高精度和计算器按钮界面了。

revpolish.zip

8.95 KB, 下载次数: 12, 下载积分: 金币 -1 枚, 经验 1 点, 下载 1 次

逆波兰计算器

点评

我前面的写错了,e=2.718281828459045  发表于 2017-1-3 16:07
报告 happysxyf: 常数 e=2.71828182859045  发表于 2017-1-3 16:05
报告 happysxyf 常数 e=2.71828182859045  发表于 2017-1-3 16:05
下载下来学习怎样写一个计算器,你们都能写计算器,我也想学写一个  发表于 2017-1-3 16:01
这个很好,有用,要顶啊  发表于 2017-1-3 15:53
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

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

GMT+8, 2024-4-20 18:21 , Processed in 0.048383 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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