标题: 逆波兰计算器 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版本源码- /*
- REVERSE POLISH EXPRESSION CALCULATOR, COPYRIGHT@2017~2019 BY HAPPYSXYF
- REVPOLISH.EXE
- VERSION 3.0
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
-
- /***************定义宏变量***************/
- //堆栈尺寸
- #define STACK_SIZE 1024
- //帮助说明
- #define HELPINFORMATION "\
- REVERSE POLISH EXPRESSION CALCULATOR,COPYRIGHT@2017~2019 BY HAPPY\n\
- -----------------------------------------------------------------\n\
- revpolish [expression]\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\
- VERSION 3.0 2017-01-28\n"
-
- /***************全局类变量***************/
- //数学函数关键词
- 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};
- //运算符栈
- char STACK1[STACK_SIZE]={0};
- //逆波兰栈
- char STACK2[STACK_SIZE]={0};
- //浮点数栈
- double STACK3[STACK_SIZE]={0};
-
- /***************功能函数类***************/
- //阶乘函数
- long long fact(long long n)
- {
- return (n<2) ?1 :n*(fact(n-1));
- }
- //逆波兰核心
- double RevPolishCore(const char* expression)
- {
- char *op=(char*)expression, *S1=STACK1, *S2=STACK2, **key, *cp, *kp;
- double *S3=STACK3, di, ni;
- int brackets=0;
- STACK3[0]=0;
-
- //生成逆波兰
- while(*op!='\0'){
- switch(*op){
- case ' ' :
- case '\t':
- case '\r':
- case '\n':
- //过滤空字符
- op++;
- continue;
-
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- case 'g':
- case 'h':
- case 'i':
- case 'j':
- case 'k':
- case 'l':
- case 'm':
- case 'n':
- case 'o':
- case 'p':
- case 'q':
- case 'r':
- case 's':
- case 't':
- case 'u':
- case 'v':
- case 'w':
- case 'x':
- case 'y':
- case 'z':
- //识别数学函数关键词
- key=(char**)KEY_WORDS;
- while(*key !=NULL){
- cp=op, kp=*key;
- //比对关键词字母
- while(*cp==*kp && *kp!='\0'){
- cp++, kp++;
- }
- //验证关键词结尾
- if((*cp<'a'||*cp>'z') && (*kp=='\0')){
- op=cp;
- break;
- }
- key++;
- }
- //构建伪双目
- if(*key !=NULL){
- *(S2++)='.';
- *(S2++)=' ';
- //伪双目入栈
- while('A'<=(*S1) && (*S1)<='Z'){
- *(S2++)=*(S1--);
- }
- *(++S1)=key-(char**)KEY_WORDS+65;
- continue;
- }else{
- //无法识别的数学函数
- fputs("Unrecognized math function\n", stderr);
- exit(1);
- }
- break;
-
- case '(':
- brackets++;
- *(++S1)=*op;
- if(*(op+1)=='-' || *(op+1)=='+'){
- *(S2++)='0', *(S2++)=' ';
- }
- break;
-
- case ')':
- brackets--;
- while(*S1!='(')
- {
- *(S2++)=*(S1--);
- }
- //舍弃'('
- S1--;
- break;
-
- case '+':
- case '-':
- while(S1!=STACK1 && *S1!='(')
- {
- *(S2++)=*(S1--);
- }
- *(++S1)=*op;
- break;
-
- case '^':
- //指数符
- while('A'<=(*S1) && (*S1)<='Z')
- {
- *(S2++)=*(S1--);
- }
- *(++S1)=*op;
- break;
-
- case '!':
- //阶乘符
- *(S2++)=*op;
- break;
-
- case '%':
- case '*':
- case '/':
- while(('A'<=(*S1) && (*S1)<='Z') ||*S1=='%' ||*S1=='*' ||*S1=='/' ||*S1=='^'){
- *(S2++)=*(S1--);
- }
- *(++S1)=*op;
- break;
-
- default :
- if((*op<'0' || *op>'9') && (*op!='.')){
- //无法识别的运算符
- fputs("Unrecognized operator\n", stderr);
- exit(1);
- }
- //浮点数入栈
- while(('0'<=*op && *op<='9') ||*op=='.'){
- *(S2++)=*(op++);
- }
- op--;
- *(S2++)=' ';
- break;
- }
- op++;
- }
-
- //验证括号是否闭合
- if(brackets){
- fputs("The brackets '(' or ')' are not closed", stderr);
- exit(1);
- }
-
- //收尾逆波兰
- while(S1 !=STACK1){*(S2++)=*(S1--);}
- *S2=' ';
-
- //计算逆波兰
- op=STACK2;
- while(*op!=' '){
- switch(*op){
- case 'A':
- *S3=2.7182818284590452;
- break;
- case 'B':
- *S3=3.1415926535897932;
- break;
- case 'C':
- if(*S3 <0){
- //负数没有平方根
- fputs("Negative numbers have no square root\n", stderr);
- exit(1);
- }
- *(S3-1)=sqrt(*S3);
- S3--;
- break;
- case 'D':
- if(*S3 <0){
- //负数没有对数
- fputs("Negative numbers are not logarithmic\n", stderr);
- exit(1);
- }
- *(S3-1)=log10(*S3);
- S3--;
- break;
- case 'E':
- if(*S3 <0){
- //负数没有自然对数
- fputs("Negative numbers have no natural logarithms\n", stderr);
- exit(1);
- }
- *(S3-1)=log(*S3);
- S3--;
- break;
- case 'F':
- *(S3-1)=sin(*S3);
- S3--;
- break;
- case 'G':
- *(S3-1)=cos(*S3);
- S3--;
- break;
- case 'H':
- if(*S3==3.1415926535897932/2){
- //π/2没有正切值
- fputs("The pi/2 has no tangent\n", stderr);
- exit(1);
- }
- *(S3-1)=tan(*S3);
- S3--;
- break;
- case 'I':
- *(S3-1)=asin(*S3);
- S3--;
- break;
- case 'J':
- *(S3-1)=acos(*S3);
- S3--;
- break;
- case 'K':
- *(S3-1)=atan(*S3);
- S3--;
- break;
- case 'L':
- *(S3-1)=(*S3)*3.1415926535897932/180.0;
- S3--;
- break;
- case 'M':
- *(S3-1)=fabs(*S3);
- S3--;
- break;
- case 'N':
- *(S3-1)=round(*S3);
- S3--;
- break;
- case 'O':
- *(S3-1)=floor(*S3);
- S3--;
- break;
- case 'P':
- *(S3-1)=ceil(*S3);
- S3--;
- break;
- case 'Q':
- *(S3-1)=exp(*S3);
- S3--;
- break;
- case 'R':
- *(S3-1)=sinh(*S3);
- S3--;
- break;
- case 'S':
- *(S3-1)=cosh(*S3);
- S3--;
- break;
- case 'T':
- *(S3-1)=tanh(*S3);
- S3--;
- break;
- case 'U':
- *(S3-1)=asinh(*S3);
- S3--;
- break;
- case 'V':
- *(S3-1)=acosh(*S3);
- S3--;
- break;
- case 'W':
- *(S3-1)=atanh(*S3);
- S3--;
- break;
- case 'X':
- *(S3-1)=(int)(*S3);
- S3--;
- break;
- case 'Y':
- if(*S3 <0){
- //负数没有伽玛函数
- fputs("Negative numbers have no factorial", stderr);
- exit(1);
- }
- *(S3-1)=tgamma((*S3)+1);
- S3--;
- break;
- case 'Z':
- //随机数生成器
- if(*S3 <0){
- //负数没有伽玛函数
- fputs("A negative number can not be used as a random upper bound", stderr);
- exit(1);
- }else if(*S3 <2){
- //负数没有伽玛函数
- *(S3-1)=rand() % 8192 /8192.0;
- }else{
- *(S3-1)=rand() % (int)(*S3);
- }
- S3--;
- break;
- case '+':
- *(S3-1)+=*S3;
- S3--;
- break;
- case '-':
- *(S3-1)-=*S3;
- S3--;
- break;
- case '*':
- *(S3-1)*=*S3;
- S3--;
- break;
- case '%':
- case '/':
- if(*S3 !=0){
- if(*op=='%'){
- //取余数
- *(S3-1)=(int)*(S3-1) % (int)*S3;
- }else{
- *(S3-1)/=*S3;
- }
-
- }else{
- //除数不能为零
- fputs("Divisor is zero error\n", stderr);
- exit(1);
- }
- S3--;
- break;
- case '^':
- if(*(S3-1)==0 && *S3<0){
- //除数不能为零
- fputs("Function pow's divisor is zero error\n", stderr);
- exit(1);
- }
- *(S3-1)=pow(*(S3-1), *S3);
- S3--;
- break;
- case '!':
- if(*S3 <0){
- //负数没有阶乘
- fputs("Negative numbers have no factorial\n", stderr);
- exit(1);
- }
- *S3=fact((long long)(*S3));
- break;
- default :
- //字符串转浮点
- di=0, ni=1;
- while('0'<=*op && *op<='9'){
- di=10*di+(*op)-'0';
- op++;
- }
- if(*op=='.'){
- op++;
- while('0'<=*op && *op<='9'){
- di=10*di+(*op)-'0';
- op++, ni*=10;
- }
- }
- *(++S3)=di/ni;
- break;
- }
- op++;
- }
-
- //判断结果是否异常或溢出
- if(isinf(*S3)||isnan(*S3)){
- fputs("Overflow or illegal operation is calculated", stderr);
- exit(1);
- }
-
- /////////////////////////////////////////////////////////////////////
- //返回计算结果
- //return *S3;
-
- //打印中缀式
- fprintf(stdout, "ORIGINALEXP: %s\n", expression);
-
- //打印后缀式
- fprintf(stdout, "REVPOLISH: ");
- op=STACK2;
- while(op!=S2){
- if(*op=='.' && *(op+1)==' '){
- op++;
-
- }else if('A'<=(*op) && (*op)<='Z'){
- 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) || (argc==2 && argv[1][0]=='/' && (argv[1][1]=='?'||argv[1][1]=='h'))){
- //使用说明
- fputs(HELPINFORMATION, stderr);
- exit(1);
- }
- //初始化随机种子
- srand((int)getpid());
- RevPolishCore(argv[1]);
- return 0;
- }
复制代码
gcc编译参数- gcc revpolish.c -std=gnu99 -O3 -s -o revpolish.exe
复制代码
cmd调用示例- @echo off
- ::****************************************************
- :HEAD
- revpolish
- ping -n 2 127.1>NUL
- echo;
- echo;
-
- ::****************************************************
- :TEST
- for /f "delims=" %%a in ('more +16 "%~f0"') do (
- revpolish "%%a"&echo;
- )
- set/p=Well Done!&exit
-
- ::****************************************************
- abs(1/(2*50)*lg(2*pi*(e^2)/(2*50+1))-lg2)
- ((((((((2^2)*2)^2)*2)^2)*2)^2)^2)*2
- -((((((((2^2)*2)^2)*2)^2)*2)^2)^2)*2
- 23+56/(102-100)*((36-24)/(8-6))
- sin(6)+3
- cos(sin(6)^4)^6
- cos(sin(-6)^4)^6
- cos(-sin(6)^4)^6
- 2^cos(sin(6)^4)^6
- 2^sin(3)^2
- 4^4!
- 3^4^2
- 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 |