Board logo

标题: 逆波兰计算器 revpolish 3.0版 [打印本页]

作者: happy886rr    时间: 2017-1-2 23:15     标题: 逆波兰计算器 revpolish 3.0版

本帖最后由 happy886rr 于 2017-1-28 15:21 编辑

[version 3.0]  2017-01-28,更新只更新源码,而不做下载更新,请编译源码获取最新版。
逆波兰计算器revpolish 3.0版,支持复杂多函数混合嵌套。恐怖的计算速度,四则运算每秒可以处理1000万行,复杂数学函数嵌套,每秒可处理200万行。支持最全面的数学函数,支持超长算式,可以自定义#define  STACK_SIZE 的值,理论上不限制算式长度。拥有详细的错误反馈,无论是除数为0,还是负数开方,都会立刻终止程序并打印错误信息。跳转排序亦根据使用频率设定,使其以最小的内存、cpu占用、最快的速度完成艰巨的科学计算。

revpolish采取多版本发行策略,请下载支持您设备的版本。
摘要:
x86&x64架构windows版, 下载:revpolish.exe


x86&x64架构linux版, 下载: revpolish


安卓apk 版, 下载: revpolish.apk


arm架构版, 下载: revpolish

用法:
-----------------------------------------------------------------------------
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
通用类
        rand  随机数
        round 四舍五入
        int   取整
        ceil  向上舍入
        floor 向下舍入
        abs   绝对值
        sqrt  开方
        lg    常用对数,以10为底
        ln    自然对数
        exp   e的次幂
        gamma 伽玛函数
        deg   度转弧度
        +     加
        -     减
        *     乘
        /     除
        %     取余数
        ^     次方
        !     阶乘
三角函数类
        sin、cos、tan   
        arcsin、arccos、arctan
双曲函数类
        sinh、cosh、tanh
        arcsinh、arccosh、arctanh
-----------------------------------------------------------------------------


revpolish.c   3.0版本源码
  1. /*
  2.     REVERSE POLISH EXPRESSION CALCULATOR, COPYRIGHT@2017~2019 BY HAPPYSXYF
  3.     REVPOLISH.EXE
  4.     VERSION 3.0
  5. */
  6. #include   <stdio.h>
  7. #include  <stdlib.h>
  8. #include    <math.h>
  9. /***************定义宏变量***************/
  10. //堆栈尺寸
  11. #define  STACK_SIZE   1024
  12. //帮助说明
  13. #define HELPINFORMATION "\
  14. REVERSE POLISH EXPRESSION CALCULATOR,COPYRIGHT@2017~2019 BY HAPPY\n\
  15. -----------------------------------------------------------------\n\
  16. revpolish [expression]\n\
  17. -----------------------------------------------------------------\n\
  18. FUNCTIONS:\n\
  19.     pi=3.1415926535897932, e=2.7182818284590452\n\
  20.     +, -, *, /, %, ^, !\n\
  21.     round, floor, ceil, exp, deg, sqrt, abs, lg, ln\n\
  22.     sin, cos, tan, arcsin, arccos, arctan\n\
  23.     sinh, cosh, tanh, arcsinh, arccosh, arctanh\n\
  24. -----------------------------------------------------------------\n\
  25. VERSION 3.0 2017-01-28\n"
  26. /***************全局类变量***************/
  27. //数学函数关键词
  28. 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", "int", "gamma", "rand", NULL};
  29. //运算符栈
  30. char   STACK1[STACK_SIZE]={0};
  31. //逆波兰栈
  32. char   STACK2[STACK_SIZE]={0};
  33. //浮点数栈
  34. double STACK3[STACK_SIZE]={0};
  35. /***************功能函数类***************/
  36. //阶乘函数
  37. long long fact(long long n)
  38. {
  39.     return (n<2) ?1 :n*(fact(n-1));
  40. }
  41. //逆波兰核心
  42. double RevPolishCore(const char* expression)
  43. {
  44. char   *op=(char*)expression, *S1=STACK1, *S2=STACK2, **key, *cp, *kp;
  45. double *S3=STACK3, di, ni;
  46. int    brackets=0;
  47. STACK3[0]=0;
  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. case '(':
  116. brackets++;
  117. *(++S1)=*op;
  118. if(*(op+1)=='-' || *(op+1)=='+'){
  119. *(S2++)='0', *(S2++)=' ';
  120. }
  121. break;
  122. case ')':
  123. brackets--;
  124. while(*S1!='(')
  125. {
  126. *(S2++)=*(S1--);
  127. }
  128. //舍弃'('
  129. S1--;
  130. break;
  131. case '+':
  132. case '-':
  133. while(S1!=STACK1 && *S1!='(')
  134. {
  135. *(S2++)=*(S1--);
  136. }
  137. *(++S1)=*op;
  138. break;
  139. case '^':
  140. //指数符
  141. while('A'<=(*S1) && (*S1)<='Z')
  142. {
  143. *(S2++)=*(S1--);
  144. }
  145. *(++S1)=*op;
  146. break;
  147. case '!':
  148. //阶乘符
  149. *(S2++)=*op;
  150. break;
  151. case '%':
  152. case '*':
  153. case '/':
  154. while(('A'<=(*S1) && (*S1)<='Z') ||*S1=='%' ||*S1=='*' ||*S1=='/' ||*S1=='^'){
  155. *(S2++)=*(S1--);
  156. }
  157. *(++S1)=*op;
  158. break;
  159. default :
  160. if((*op<'0' || *op>'9') && (*op!='.')){
  161. //无法识别的运算符
  162. fputs("Unrecognized operator\n", stderr);
  163. exit(1);
  164. }
  165. //浮点数入栈
  166. while(('0'<=*op && *op<='9') ||*op=='.'){
  167. *(S2++)=*(op++);
  168. }
  169. op--;
  170. *(S2++)=' ';
  171. break;
  172. }
  173. op++;
  174. }
  175. //验证括号是否闭合
  176. if(brackets){
  177. fputs("The brackets '(' or ')' are not closed", stderr);
  178. exit(1);
  179. }
  180. //收尾逆波兰
  181. while(S1 !=STACK1){*(S2++)=*(S1--);}
  182. *S2=' ';
  183. //计算逆波兰
  184. op=STACK2;
  185. while(*op!=' '){
  186. switch(*op){
  187. case 'A':
  188. *S3=2.7182818284590452;
  189. break;
  190. case 'B':
  191. *S3=3.1415926535897932;
  192. break;
  193. case 'C':
  194. if(*S3 <0){
  195. //负数没有平方根
  196. fputs("Negative numbers have no square root\n", stderr);
  197. exit(1);
  198. }
  199. *(S3-1)=sqrt(*S3);
  200. S3--;
  201. break;
  202. case 'D':
  203. if(*S3 <0){
  204. //负数没有对数
  205. fputs("Negative numbers are not logarithmic\n", stderr);
  206. exit(1);
  207. }
  208. *(S3-1)=log10(*S3);
  209. S3--;
  210. break;
  211. case 'E':
  212. if(*S3 <0){
  213. //负数没有自然对数
  214. fputs("Negative numbers have no natural logarithms\n", stderr);
  215. exit(1);
  216. }
  217. *(S3-1)=log(*S3);
  218. S3--;
  219. break;
  220. case 'F':
  221. *(S3-1)=sin(*S3);
  222. S3--;
  223. break;
  224. case 'G':
  225. *(S3-1)=cos(*S3);
  226. S3--;
  227. break;
  228. case 'H':
  229. if(*S3==3.1415926535897932/2){
  230. //π/2没有正切值
  231. fputs("The pi/2 has no tangent\n", stderr);
  232. exit(1);
  233. }
  234. *(S3-1)=tan(*S3);
  235. S3--;
  236. break;
  237. case 'I':
  238. *(S3-1)=asin(*S3);
  239. S3--;
  240. break;
  241. case 'J':
  242. *(S3-1)=acos(*S3);
  243. S3--;
  244. break;
  245. case 'K':
  246. *(S3-1)=atan(*S3);
  247. S3--;
  248. break;
  249. case 'L':
  250. *(S3-1)=(*S3)*3.1415926535897932/180.0;
  251. S3--;
  252. break;
  253. case 'M':
  254. *(S3-1)=fabs(*S3);
  255. S3--;
  256. break;
  257. case 'N':
  258. *(S3-1)=round(*S3);
  259. S3--;
  260. break;
  261. case 'O':
  262. *(S3-1)=floor(*S3);
  263. S3--;
  264. break;
  265. case 'P':
  266. *(S3-1)=ceil(*S3);
  267. S3--;
  268. break;
  269. case 'Q':
  270. *(S3-1)=exp(*S3);
  271. S3--;
  272. break;
  273. case 'R':
  274. *(S3-1)=sinh(*S3);
  275. S3--;
  276. break;
  277. case 'S':
  278. *(S3-1)=cosh(*S3);
  279. S3--;
  280. break;
  281. case 'T':
  282. *(S3-1)=tanh(*S3);
  283. S3--;
  284. break;
  285. case 'U':
  286. *(S3-1)=asinh(*S3);
  287. S3--;
  288. break;
  289. case 'V':
  290. *(S3-1)=acosh(*S3);
  291. S3--;
  292. break;
  293. case 'W':
  294. *(S3-1)=atanh(*S3);
  295. S3--;
  296. break;
  297. case 'X':
  298. *(S3-1)=(int)(*S3);
  299. S3--;
  300. break;
  301. case 'Y':
  302. if(*S3 <0){
  303. //负数没有伽玛函数
  304. fputs("Negative numbers have no factorial", stderr);
  305. exit(1);
  306. }
  307. *(S3-1)=tgamma((*S3)+1);
  308. S3--;
  309. break;
  310. case 'Z':
  311. //随机数生成器
  312. if(*S3 <0){
  313. //负数没有伽玛函数
  314. fputs("A negative number can not be used as a random upper bound", stderr);
  315. exit(1);
  316. }else if(*S3 <2){
  317. //负数没有伽玛函数
  318. *(S3-1)=rand() % 8192 /8192.0;
  319. }else{
  320. *(S3-1)=rand() % (int)(*S3);
  321. }
  322. S3--;
  323. break;
  324. case '+':
  325. *(S3-1)+=*S3;
  326. S3--;
  327. break;
  328. case '-':
  329. *(S3-1)-=*S3;
  330. S3--;
  331. break;
  332. case '*':
  333. *(S3-1)*=*S3;
  334. S3--;
  335. break;
  336. case '%':
  337. case '/':
  338. if(*S3 !=0){
  339. if(*op=='%'){
  340. //取余数
  341. *(S3-1)=(int)*(S3-1) % (int)*S3;
  342. }else{
  343. *(S3-1)/=*S3;
  344. }
  345. }else{
  346. //除数不能为零
  347. fputs("Divisor is zero error\n", stderr);
  348. exit(1);
  349. }
  350. S3--;
  351. break;
  352. case '^':
  353. if(*(S3-1)==0 && *S3<0){
  354. //除数不能为零
  355. fputs("Function pow's divisor is zero error\n", stderr);
  356. exit(1);
  357. }
  358. *(S3-1)=pow(*(S3-1), *S3);
  359. S3--;
  360. break;
  361. case '!':
  362. if(*S3 <0){
  363. //负数没有阶乘
  364. fputs("Negative numbers have no factorial\n", stderr);
  365. exit(1);
  366. }
  367. *S3=fact((long long)(*S3));
  368. break;
  369. default :
  370. //字符串转浮点
  371. di=0, ni=1;
  372. while('0'<=*op && *op<='9'){
  373. di=10*di+(*op)-'0';
  374. op++;
  375. }
  376. if(*op=='.'){
  377. op++;
  378. while('0'<=*op && *op<='9'){
  379. di=10*di+(*op)-'0';
  380. op++, ni*=10;
  381. }
  382. }
  383. *(++S3)=di/ni;
  384. break;
  385. }
  386. op++;
  387. }
  388. //判断结果是否异常或溢出
  389. if(isinf(*S3)||isnan(*S3)){
  390. fputs("Overflow or illegal operation is calculated", stderr);
  391. exit(1);
  392. }
  393. /////////////////////////////////////////////////////////////////////
  394. //返回计算结果
  395. //return *S3;
  396. //打印中缀式
  397. fprintf(stdout, "ORIGINALEXP: %s\n", expression);
  398. //打印后缀式
  399. fprintf(stdout, "REVPOLISH:   ");
  400. op=STACK2;
  401. while(op!=S2){
  402. if(*op=='.' && *(op+1)==' '){
  403. op++;
  404. }else if('A'<=(*op) && (*op)<='Z'){
  405. fprintf(stdout, "%s ", KEY_WORDS[*op-65]);
  406. }else{
  407. fputc(*op, stdout);
  408. if(*op=='+' ||*op=='-' ||*op=='*' ||*op=='/' ||*op=='%' ||*op=='^' ||*op=='!'){fputc(' ', stdout);}
  409. }
  410. op++;
  411. }
  412. fputc('\n', stdout);
  413. //打印计算结果
  414. fprintf(stdout, "RESULT:      %.16lf\n", *S3);
  415. }
  416. /*************MAIN主函数入口*************/
  417. int main(int argc, char** argv)
  418. {
  419. if((argc==1) || (argc==2 && argv[1][0]=='/' && (argv[1][1]=='?'||argv[1][1]=='h'))){
  420. //使用说明
  421. fputs(HELPINFORMATION, stderr);
  422. exit(1);
  423. }
  424. //初始化随机种子
  425. srand((int)getpid());
  426. RevPolishCore(argv[1]);
  427. return 0;
  428. }
复制代码
gcc编译参数
  1. gcc revpolish.c -std=gnu99 -O3 -s -o revpolish.exe
复制代码
cmd调用示例
  1. @echo off
  2. ::****************************************************
  3. :HEAD
  4. revpolish
  5. ping -n 2 127.1>NUL
  6. echo;
  7. echo;
  8. ::****************************************************
  9. :TEST
  10. for /f "delims=" %%a in ('more +16 "%~f0"') do (
  11. revpolish "%%a"&echo;
  12. )
  13. set/p=Well Done!&exit
  14. ::****************************************************
  15. abs(1/(2*50)*lg(2*pi*(e^2)/(2*50+1))-lg2)
  16. ((((((((2^2)*2)^2)*2)^2)*2)^2)^2)*2
  17. -((((((((2^2)*2)^2)*2)^2)*2)^2)^2)*2
  18. 23+56/(102-100)*((36-24)/(8-6))
  19. sin(6)+3
  20. cos(sin(6)^4)^6
  21. cos(sin(-6)^4)^6
  22. cos(-sin(6)^4)^6
  23. 2^cos(sin(6)^4)^6
  24. 2^sin(3)^2
  25. 4^4!
  26. 3^4^2
  27. gamma(20.3)
复制代码

作者: 莫奈良    时间: 2017-1-6 21:16

真的是黑科技 虽然看不懂 还是要支持一下了
作者: CrLf    时间: 2017-1-6 23:36

名字略怪,还以为是计算逆波兰式的,结果其实是波兰式
作者: happy886rr    时间: 2017-1-7 11:14

回复 3# CrLf
回复大师,这版主要是优化速度,所以没用数据结构的pop、push,而是用全局静态数组实现的。其中atof也改用自己的实现,所以比调用atof速度要快,核心不调用任何函数,单目、双目全部用双目实现。
作者: codegay    时间: 2017-1-7 23:55

linux下编译环境的应该是比较好弄。
windows 下有条件和能力的估计不多。
所以exe还是有必要发布一下。
作者: CrLf    时间: 2017-1-8 00:04

回复 5# codegay


    gcc 可以直接编译,但是 gcc 有一个问题,会将带通配符的参数展开为路径,而这个行为是编译器主动进行的,所以我都尽量用 tcc 编译
    无奈的是 tcc 的库太少,编译起来实在不方便
作者: happy886rr    时间: 2017-1-8 18:42

本帖最后由 happy886rr 于 2017-1-8 18:50 编辑

回复 6# CrLf
大师手机上也能编译,我用c4droid的手机版tcc直接.编译成了apk和arm架构C版本,已更新到顶楼。在手机上的体验很棒,完全取代了自带的计算器,有12位有效精度。
作者: CrLf    时间: 2017-1-8 20:29

回复 7# happy886rr


    手机有 #include <windows.h> 吗?
作者: happy886rr    时间: 2017-1-8 21:44

回复 8# CrLf
那个windows头我写多余了,其实只要有stdio和math这两个头就足够。代码无需修改支持各种C平台直接编译。我已经在虚拟机里测试了linux版,完全可用。
作者: pighead123    时间: 2017-2-21 00:51

本帖最后由 pighead123 于 2017-2-21 00:56 编辑

很好,怎么不放到 github 去?放上去就方便管理和发布了




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2