如何优化才更具大规模计算效率

xempo 2009-08-16 11:44:43
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include <math.h>

#define fcn 11
double ctg(double d)
{return 1/tan(d);}

double actg(double d)
{return(M_PI_2-atan(d));}

int n_CalcErr;
char MathSyb[6]={ '(', ')', '[', ']', '{', '}' },
Calcfunc[36];/* store error mathfunc-name */
double (*mfun[fcn])(double d)={sin,cos,tan,ctg,log10,asin,acos,atan,actg,exp,fabs};

double db_syb(char *pch,double *bk,int *i)
{
char jao=0;
double db;
if(*pch=='@'){ (*i)++; pch++; jao=1; }
switch(*pch){
case -1 : db=M_E; break;
case -2 : db=M_PI; break;
case 127 : (*i)++; db=bk[pch[1]]; break;
default : db=atof(pch);
}
return jao ? db * M_PI/180: db;
}

double calc(char *ExprChs)
{
static char CalcChs[8]="_^*/%+-",
fun[fcn][5]={"sin","cos","tag","ctg","lg","asin","acos","atag","actg","exp","abs"};
static int cchslen[3]={2,3,2}, begin[3]={0,2,5};
double *db, *bk, rc, db1;
int x, y, t, b, i=-1, *sybpos,
j=1, w=1, v=1, f=0, ErrNo=0;
char *chs, *bu, *symbuf, syb, syb2, C;
long l1, l2;
if(!ExprChs || !*ExprChs)return 0;
/* because rc=0 is x87, so use return, smaller size */
t=strlen(ExprChs)+1;
chs=(char *)malloc(3*t+5);
bu=chs; symbuf=chs+t+1;
sybpos=(int *)(symbuf+t+1);

while(++i<t) /* 0 must send to chs, so t...+1 */
if((C=ExprChs[i])!=32){/* 压缩 */
syb2=ExprChs[i+1]|32;
if((syb=C|32)=='e'&&(syb2<97||syb2>122))*bu=-1;
else if(syb=='p'&&syb2=='i'){ *bu=-2; i++; }
else { *bu=C;
if(C==')'||C==']'||C=='}')j++;
else if(strchr(CalcChs,C))w++;
}
bu++;
}
db=(double *)malloc(8*(w+j));
bk=db+w;
for(x=0;x<5;x+=2){
for(y=0;chs[y]/* no change this,it would change len in follow */;y++){
if(chs[y]==MathSyb[x])sybpos[f++]=y;
if(chs[y]==MathSyb[x+1]){
if(f--<1){ ErrNo=5011+x; goto calcEnd; }
w=sybpos[f];
bu=chs+w+1; chs[y]=0;
CalcRun: for(syb=1,i=0;bu[i]=='-'||bu[i]=='+';i++)
if(bu[i]=='-')syb=-syb;
*db=db_syb(bu+i,bk,&i)*syb;
for(t=0;bu[i];i++){
switch(bu[i]){ /* process bu string */
case -1:
case -2:
case 127: syb2=syb; goto skp1;
default : { syb2=1;
if(strchr(CalcChs,bu[i])){
for(symbuf[t++]=bu[i++];bu[i]=='+'||bu[i]=='-';i++)
if(bu[i]=='-')syb2=-syb2;
skp1: db[t]=db_syb(bu+i,bk,&i)*syb2;
}
for(j=0; j<34 && ((C=bu[i])|32)>96&&(C|32)<123; j++,i++)Calcfunc[j]=C;
if(j>0){
Calcfunc[j]=0;
db1=db_syb(bu+i,bk,&i);
for(j=0;j<fcn&&stricmp(Calcfunc,fun[j]);j++);
if(j>=fcn){ ErrNo=5010; goto calcEnd; }
if(db1==0 && j>2 && j<5){ ErrNo=4997+j; goto calcEnd; }
db[t] = (*mfun[j])(db1)*syb2;
}
}
}
}/* finish bu */
for(i=0;i<3;i++){
for(j=0;j<t;j++)if(memchr(CalcChs+begin[i],symbuf[j],cchslen[i])){/* math */
rc=db[j]; db1=db[j+1];

switch(symbuf[j]){
case '_' : if(rc<2||db1<1){ ErrNo=5003; goto calcEnd; }
rc=log10(db1)/log10(rc); break;
case '^' : rc=pow(rc,db1); break;
case '*' : rc*=db1; break;
case '%' : l1=rc; l2=db1;
case '/' : if(db1==0){ ErrNo=5004; goto calcEnd; }
rc=symbuf[j]!='%'? rc/db1:l1%l2;
break;
case '+' : rc+=db1; break;
case '-' : rc-=db1;
}

db[j]=rc;
if((b=t-j-1)>0){memmove(db+j+1,db+j+2,8*b);memmove(symbuf+j,symbuf+j+1,b);}
/* double is x87 code, use x86 possible
if(t>j+1)for(b1=j;b1<t;b1++){db[b1+1]=db[b1+2];symbuf[b1]=symbuf[b1+1];}*/
t--; j--;
} /* end math */
}
if(x>5)goto calcEnd;
bk[v]=*db;
strcpy(chs+w+2,chs+y+1);/*for(j=y+1,i=w+2;(chs[i]=chs[j])!=0;i++,j++);*/
y=w+1;
chs[w]=127; chs[y]=v++;
}/* end ()[]{} if */
}/* end for */
if(f){ ErrNo=5011+x+1; goto calcEnd; }
}/* end 3 loop for )]} */
bu=chs;
goto CalcRun;

calcEnd: rc= ErrNo&&*chs==0? 0:*db;
free(db); free(chs);
n_CalcErr=ErrNo;
return rc;
}

============ 计算器(表达式)说明 ============
四则运算符号: + - * /
求余: %
对数: _ (例如:2_4 = 2)
以10为底的对数:lg (例如:lg100=2)
乘方: ^ (例如:4^2 =16; 4^0.5=2)
绝对值:abs (例如:abs(-2.88)=2.88)

三角函数如下:
sin, cos, tag, ctg
一般是孤度,若以@开头的即是角度。例如:sin(@30)=0.5; sin(pi/6)=0.5 // pi是圆周率

反三角函数如下:
asin, acos, atag, actg

exp:科学计算
e=2.7182818284590452354

------ 问题-----
此程序怎样优化才更具大规模计算效率?
...全文
276 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
xempo 2010-02-12
  • 打赏
  • 举报
回复
有三个错漏:
1,括号统计(j值)用左括号。
if(C==')'||C==']'||C=='}')j++;

2,sybpos及db的空间分配要改。原

chs=(char *)malloc(3*t+5);

改为:

sybpos=(int *)malloc( sizeof(int)*j + sizeof(double)*(w+j) );
db=(double *)(sybpos+j);

3,对数的限制好象是: >0且不等于1。要改。
......
xempo 2009-12-08
  • 打赏
  • 举报
回复
在Linux C99中直接动态开辟栈,要注意安全,加一个条件限制—— ExprChs的长度不长于某一个值,如:50000byte

if(!ExprChs || !*ExprChs || stlen(ExprChs)>49999)return 0;
xempo 2009-08-22
  • 打赏
  • 举报
回复

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include <math.h>

#define fcn 11
double ctg(double d)
{return 1/tan(d);}

double actg(double d)
{return(M_PI_2-atan(d));}

int n_CalcErr;
char MathSyb[6]={ '(', ')', '[', ']', '{', '}' },
Calcfunc[36];/* store error mathfunc-name */
double (*mfun[fcn])(double d)={sin,cos,tan,ctg,log10,asin,acos,atan,actg,exp,fabs};

double db_syb(char *pch,double *bk,int *i)
{
char jao=0;
double db;
if(*pch=='@'){ (*i)++; pch++; jao=1; }
switch(*pch){
case -1 : db=M_E; break;
case -2 : db=M_PI; break;
case 127 : (*i)++; db=bk[pch[1]]; break;
default : db=atof(pch);
}
return jao ? db * M_PI/180: db;
}

static char CalcChs[8]="_^*/%+-",
fun[fcn][5]={"sin","cos","tag","ctg","lg","asin","acos","atag","actg","exp","abs"};
static int cchslen[3]={2,3,2}, begin[3]={0,2,5};
double calc(char *ExprChs)
{
double *bk, rc, db1
#ifndef _STDIO_H
, *db
#endif
;
int x, y, t, b, i=-1, *sybpos,
j=1, w=1, v=1, f=0, ErrNo=0;
char *bu, *symbuf, syb, syb2, C
#ifndef _STDIO_H
, *chs
#endif
;
long l1, l2;
if(!ExprChs || !*ExprChs)return 0;
/* because rc=0 is x87, so use return, smaller size */
t=strlen(ExprChs)+1;
#ifdef _STDIO_H
char chs[3*t+5]; // gcc
#else
chs=(char *)malloc(3*t+5); // TC
#endif
bu=chs; symbuf=chs+t+1;
sybpos=(int *)(symbuf+t+1);

while(++i<t) /* 0 must send to chs, so t...+1 */
if((C=ExprChs[i])!=32){/* 压缩 */
syb2=ExprChs[i+1]|32;
if((syb=C|32)=='e'&&(syb2<97||syb2>122))*bu=-1;
else if(syb=='p'&&syb2=='i'){ *bu=-2; i++; }
else { *bu=C;
if(C==')'||C==']'||C=='}')j++;
else if(strchr(CalcChs,C))w++;
}
bu++;
}
#ifdef _STDIO_H
double db[w+j]; // gcc
#else
db=(double *)malloc(8*(w+j)); // TC
#endif
bk=db+w;
for(x=0;x<5;x+=2){
for(y=0;chs[y]/* no change this,it would change len in follow */;y++){
if(chs[y]==MathSyb[x])sybpos[f++]=y;
if(chs[y]==MathSyb[x+1]){
if(f--<1){ ErrNo=5011+x; goto calcEnd; }
w=sybpos[f];
bu=chs+w+1; chs[y]=0;
CalcRun: for(syb=1,i=0;bu[i]=='-'||bu[i]=='+';i++)
if(bu[i]=='-')syb=-syb;
*db=db_syb(bu+i,bk,&i)*syb;
for(t=0;bu[i];i++){
switch(bu[i]){ /* process bu string */
case -1:
case -2:
case 127: syb2=syb; goto skp1;
default : { syb2=1;
if(strchr(CalcChs,bu[i])){
for(symbuf[t++]=bu[i++];bu[i]=='+'||bu[i]=='-';i++)
if(bu[i]=='-')syb2=-syb2;
skp1: db[t]=db_syb(bu+i,bk,&i)*syb2;
}
for(j=0; j<34 && ((C=bu[i])|32)>96&&(C|32)<123; j++,i++)Calcfunc[j]=C;
if(j>0){
Calcfunc[j]=0;
db1=db_syb(bu+i,bk,&i);
for(j=0;j<fcn&&stricmp(Calcfunc,fun[j]);j++);
if(j>=fcn){ ErrNo=5010; goto calcEnd; }
if(db1==0 && j>2 && j<5){ ErrNo=4997+j; goto calcEnd; }
db[t] = (*mfun[j])(db1)*syb2;
}
}
}
}/* finish bu */
for(i=0;i<3;i++){
for(j=0;j<t;j++)if(memchr(CalcChs+begin[i],symbuf[j],cchslen[i])){/* math */
rc=db[j]; db1=db[j+1];

switch(symbuf[j]){
case '_' : if(rc<2||db1<1){ ErrNo=5003; goto calcEnd; }
rc=log10(db1)/log10(rc); break;
case '^' : rc=pow(rc,db1); break;
case '*' : rc*=db1; break;
case '%' : l1=rc; l2=db1;
case '/' : if(db1==0){ ErrNo=5004; goto calcEnd; }
rc=symbuf[j]!='%'? rc/db1:l1%l2;
break;
case '+' : rc+=db1; break;
case '-' : rc-=db1;
}

db[j]=rc;
if((b=t-j-1)>0){memmove(db+j+1,db+j+2,8*b);memmove(symbuf+j,symbuf+j+1,b);}
/* double is x87 code, use x86 possible
if(t>j+1)for(b1=j;b1<t;b1++){db[b1+1]=db[b1+2];symbuf[b1]=symbuf[b1+1];}*/
t--; j--;
} /* end math */
}
if(x>5)goto calcEnd;
bk[v]=*db;
strcpy(chs+w+2,chs+y+1);/*for(j=y+1,i=w+2;(chs[i]=chs[j])!=0;i++,j++);*/
y=w+1;
chs[w]=127; chs[y]=v++;
}/* end ()[]{} if */
}/* end for */
if(f){ ErrNo=5011+x+1; goto calcEnd; }
}/* end 3 loop for )]} */
bu=chs;
goto CalcRun;

calcEnd: rc= ErrNo&&*chs==0? 0:*db;
#ifndef _STDIO_H
free(db); free(chs); // TC
#endif
n_CalcErr=ErrNo;
return rc;
}

已完成了一个优化。
ies_sweet 2009-08-18
  • 打赏
  • 举报
回复
没有详细看楼主的代码。

不过优化可以从以下几个原则来考虑

1,空间。尽量原地工作,减少不必要的内存拷贝。
2,流水线作业。用循环来进行流水线作业,提高CPU利用率。
3,浮点运算。在精度可以保证下,不用浮点运算。
4,表驱动。利用查表法来代替现场运算。
5,公共表达式。对于热度很高的地方,使用公共表达式,不要每次都计算。

以上都是细节,
最最关键的,还是算法。
这算法,我是外行,就不发表意见了。
fallening 2009-08-18
  • 打赏
  • 举报
回复
profile一下看看瓶颈在哪里才可以优化的,不要凭空随便找地方优化
superbtl 2009-08-18
  • 打赏
  • 举报
回复
LZ是要用数据结构跟算法来提升效率吧
xempo 2009-08-18
  • 打赏
  • 举报
回复

#include <stdio.h>
#ifdef _STDIO_H
#define stricmp strcasecmp
#else
// DOS or Windows
// #define stkalloc malloc
#endif

#include "calc.c" // 以上原问题的代码

int main()
{
char buf[200];
double db;
puts("Enter \'q\' to exit");
do {
gets(buf);
db=calc(buf);
if(n_CalcErr==0)printf("%g\n", db);
}while(buf[0]!='q');
}


以上是一个小应用。

----------- 再问 -----------
在Linux中,如果将calc中的malloc改成栈动态分配,将会是一个巨大的效率提升。
不知哪位知道此类函数的原型在哪一个头文件作出说明的。
easyEagel 2009-08-18
  • 打赏
  • 举报
回复

#include<string.h>

int main()
{
char* str="lgbkdk";

int a[strlen(str)];

return 0;
}

上面的代码正常编译,并正常运行,应该就是你说的栈上的动态分配吧。C99好像支持这种使用方式。
xempo 2009-08-18
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 ies_sweet 的回复:]

优化可以从以下几个原则来考虑

1,空间。尽量原地工作,减少不必要的内存拷贝。
2,流水线作业。用循环来进行流水线作业,提高CPU利用率。
3,浮点运算。在精度可以保证下,不用浮点运算。
4,表驱动。利用查表法来代替现场运算。
5,公共表达式。对于热度很高的地方,使用公共表达式,不要每次都计算。
[/Quote]
说的都有些道理,但具体我要在此程序中。呃,Linux是有个栈动态分配的,你能告诉我在哪一个头文件吗?或叫啥名字?几年前,我在一本Linux初学者之类书看见过。
xempo 2009-08-17
  • 打赏
  • 举报
回复
或增强一些加功能,可乎?

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧