Распознавание формулы со сложными математическими функциями в строке - C (СИ)
Формулировка задачи:
Задание курсовика - распознать формулу функции введенную с клавиатуры и построить ее график (прикручу графику позже, сам код уже написан мной для лабы, да и мелочи буду вылизывать в конце), нашел превосходный способ распознавания, допилил и модифицировал его под себя, так что остался только один не решенный вопрос о том, как можно реализовать распознавание матем. функций, на подобии sin, cos, log и других, на мой взгляд основная сложность заключается в том что бы распознать то что находиться у этих функций в скобках, не представляю как это можно реализовать, да и к тому же надо будет учитывать одз, хотя возможно есть и другие подводные камни о которых я и не ведаю (пока), хотелось бы услышать практических советов или примерчика какого нибудь, заранее благодарю)
До этого начинал с работать с польской записью, но этот метод, в плане вычисления показался мне несколько проще - проще реализация вычисления "сложных" выражений содержащих в перемешку разные по приоритету операции.
Пишу на чистом Си, в BorlandC 3.1 Сам код, избавленный от моих попыток научить программу понимать мат. функции:
Листинг программы
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <ctype.h>
- #include <conio.h>
- int next();
- void skip(int t);
- double expr();
- double numpar();
- double factor();
- double term();
- double x=5;
- int i=0; char s[50]; int Op; double tokval;
- int main()
- {
- clrscr();
- gets(s);
- //for(;x<10;x+=1)
- //{
- next();
- printf("\n%.9g\n", expr());
- // i=0;
- // Op=0;
- // tokval=0;
- //}
- if(!getch()) getch();
- clrscr();
- return 0;
- }
- int next()
- {
- int c,count=0;
- char cbuf[50];
- for (;;)
- {
- c=s[i++];
- if(strchr("+-*/^()\n",c)!=NULL&&i!=1)
- if(c=='*'&&s[i]=='*')
- {
- i=i+1;
- return Op='^';
- }
- else
- return Op=c;
- if(c=='s'&&s[i]=='i'&&s[i+1]=='n')
- {
- i=i+2;
- return Op='s';
- }
- if(isspace(c)) continue;
- if(isdigit(c)||c=='.'||c=='x'||c=='-')
- {
- if(c=='x')
- {
- tokval=x;
- return Op='n';
- }
- for(;((c>='0'&&c<='9')||c=='.'||c=='-');)
- {
- cbuf[count++]=c;
- cbuf[count]='\0';
- c=s[i++];
- }
- i-=1;
- tokval=atof(cbuf);
- return Op='n';
- }
- printf("Bad character: %c\n",c);
- if(!getch()) getch();
- }
- }
- void skip(int t)
- {
- if(Op!=t)
- {
- printf("You take a error, try agan");
- if(!getch()) getch();
- exit(1);
- }
- next();
- }
- // numpar ::= number | '(' expr ')'
- double numpar()
- {
- if (Op=='n')
- {
- double res=tokval;
- skip('n');
- return res;
- }
- skip('(');
- double res=expr();
- skip(')');
- return res;
- }
- // factor ::= numpar | numpar '^' factor
- double factor()
- {
- double res=numpar();
- if (Op=='^')
- {
- skip('^');
- res=pow(res,factor());
- }
- return res;
- }
- // term ::= factor | term '*' factor | term '/' factor
- double term()
- {
- double res=factor();
- for (;;)
- {
- if (Op=='*')
- {
- skip('*');
- res*=factor();
- }
- else
- if (Op=='/')
- {
- skip('/');
- res/=factor();
- }
- else
- return res;
- }
- }
- // expr ::= term | expr '+' term | expr '-' term
- double expr()
- {
- double res=term();
- for (;;)
- {
- if (Op=='+')
- {
- skip('+');
- res+=term();
- }
- else
- if (Op=='-')
- {
- skip('-');
- res-=term();
- }
- else
- return res;
- }
- }
Решение задачи: «Распознавание формулы со сложными математическими функциями в строке»
textual
Листинг программы
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <ctype.h>
- #include <conio.h>
- #include <alloc.h>
- #include <graphics.h>
- #include <DOS.h>
- #define pi 3.14159265
- int next(char *s,char *sid);
- int skip(int t, char *s,char *sid);
- double expr(char *s,char *sid);
- double numpar(char *s,char *sid);
- double factor(char *s,char *sid);
- double term(char *s,char *sid);
- void test();
- int mod(char *s);
- int graph(char *s,char *sid);
- struct Operation
- {
- char* sid[7];
- int Op;
- double tokval;
- double x;
- }Oper={"sin","cos","tg","ctg","sqrt","log","exp"};
- int main()
- {
- char c;
- int i=0;
- char *s,sid[6];
- int blocknum=0;
- int gd=DETECT,gm,err;
- heapinfo hi;
- hi.ptr=NULL;
- clrscr();
- printf("\nEnter the formula\n");
- fflush(stdin);
- s=(char*)realloc(s,++i*sizeof(char));
- s[i-1]='(';
- while((c=getch())!=13)
- {
- if(c==8) continue;
- fflush(stdin);
- putch(c);
- s=(char*)realloc(s,++i*sizeof(char));
- if(s==NULL)
- {
- printf("\n memory error");
- if(!getch()) getch();
- return -1;
- }
- s[i-1]=c;
- }
- s=(char*)realloc(s,++i*sizeof(char));
- s[i-1]=')';
- s[i]='\0';
- mod(s);
- while(heapwalk(&hi)==_HEAPOK)
- if(hi.in_use) ++blocknum;
- test();
- clrscr();
- detectgraph(&gd,&gm);
- err=graphresult();
- if(err)
- {
- printf("\n%s",grapherrormsg(err));
- return 1;
- }
- registerbgidriver(EGAVGA_driver);
- initgraph(&gd,&gm,"");
- err=graphresult();
- if(err)
- {
- printf("n%s",grapherrormsg(err));
- return 2;
- }
- cleardevice();
- clrscr();
- graph(s,sid);
- if(!getch()) getch();
- free(s);
- hi.ptr=NULL;
- while (heapwalk(&hi)==_HEAPOK)
- if(hi.in_use)
- --blocknum;
- if(blocknum)
- printf("\n Error: Useing block in heap \n");
- clrscr();
- closegraph();
- return 0;
- }
- int mod(char *s)
- {
- int a,j,n=0,i=0;
- a=strlen(s);
- for(i=0;s[i]!='\0';i++)
- {
- if(s[i]=='-')
- {
- if(s[i-1]=='(')
- {
- for (j=0;j!=a+1-i;j++) s[(a+1)-j]=s[a-j];
- s[i]='0';
- }
- }
- }
- a=strlen(s);
- for(i=0;i<a;i++)
- {
- if(s[i]=='(') n=n+1;
- if(s[i]==')') n=n-1;
- }
- if(n!=0)
- {
- closegraph();
- printf("\nYou take a error, try agan");
- if(!getch()) getch();
- exit(1);
- }
- return 0;
- }
- int next(char *s,char *sid)
- {
- int c,count=0;
- static int i=0;
- char cbuf[50];
- if(Oper.Op=='Ж') i=0;
- for (;;)
- {
- c=s[i++];
- if(strchr("+-*/^()\n",c)!=NULL&&i!=1)
- {
- if(c=='*'&&s[i]=='*')
- {
- i=i+1;
- return Oper.Op='^';
- }
- return Oper.Op=c;
- }
- if(isspace(c)) continue;
- if(isdigit(c)||c=='.'||c=='x')
- {
- for(;(c=='x'||(c>='0'&&c<='9')||c=='.');)
- {
- if(c=='x')
- {
- if(s[i-i]=='-') Oper.tokval=-1*Oper.x;
- else
- Oper.tokval=Oper.x;
- return Oper.Op='n';
- }
- cbuf[count++]=c;
- cbuf[count]='\0';
- c=s[i++];
- }
- i-=1;
- Oper.tokval=atof(cbuf);
- return Oper.Op='n';
- }
- if(isalpha(c))
- {
- if(c=='p'&&s[i++]=='i')
- {
- Oper.tokval=pi;
- return Oper.Op='n';
- }
- do
- {
- cbuf[count++]=c;
- cbuf[count]='\0';
- c=s[i++];
- }
- while(isalpha(c));
- strcpy(sid,cbuf);
- i--;
- return Oper.Op='a';//alpha function
- }
- }
- }
- int skip(int t,char *s,char *sid)
- {
- if(Oper.Op!=t)
- {
- closegraph();
- printf("\nYou take a error, try agan");
- if(!getch()) getch();
- exit(1);
- }
- next(s,sid);
- return 0;
- }
- // numpar ::= number | '(' expr ')' | (func1||...||func2) '(' expr ')'
- double numpar(char *s,char *sid)
- {
- int i=0,j=0;
- if (Oper.Op=='n')
- {
- double res=Oper.tokval;
- skip('n',s,sid);
- return res;
- }
- if (Oper.Op=='a')
- {
- skip('a',s,sid);
- skip('(',s,sid);
- double res=expr(s,sid);
- skip(')',s,sid);
- for(i=0;(strcmp(sid,Oper.sid[i])!=0);i++);
- switch(i)
- {
- case 0: res=sin(res); break;
- case 1: res=cos(res); break;
- case 2: res=sin(res)/cos(res); break;
- case 3: res=cos(res)/sin(res); break;
- case 4: if(res>=0) res=sqrt(res);
- else
- {
- res=res+getmaxx()/2;
- res=sqrt(res);
- }
- break;
- case 5: if(res>=0) res=log(res);
- else
- {
- res=res+getmaxx()/2;
- res=log(res);
- }
- break;
- case 6: res=exp(res); break;
- default: closegraph(); printf("\nBad function: %s\n",sid);res=0;
- }
- return res;
- }
- skip('(',s,sid);
- double res=expr(s,sid);
- skip(')',s,sid);
- return res;
- }
- // factor ::= numpar | numpar '^' factor
- double factor(char *s,char *sid)
- {
- double res=numpar(s,sid);
- if (Oper.Op=='^')
- {
- skip('^',s,sid);
- res=pow(res,factor(s,sid));
- }
- return res;
- }
- // term ::= factor | term '*' factor | term '/' factor
- double term(char *s,char *sid)
- {
- double temp;
- double res=factor(s,sid);
- for (;;)
- {
- if (Oper.Op=='*')
- {
- skip('*',s,sid);
- res*=factor(s,sid);
- }
- else
- if (Oper.Op=='/')
- {
- skip('/',s,sid);
- temp=factor(s,sid);
- if(temp!=0) res/=temp;
- else
- {
- temp=temp+0.001;
- res/=temp;
- }
- }
- else
- return res;
- }
- }
- // expr ::= term | expr '+' term | expr '-' term
- double expr(char *s,char *sid)
- {
- double res=term(s,sid);
- for (;;)
- {
- if (Oper.Op=='+')
- {
- skip('+',s,sid);
- res+=term(s,sid);
- }
- else
- if (Oper.Op=='-')
- {
- skip('-',s,sid);
- res-=term(s,sid);
- }
- else
- return res;
- }
- }
- void test()
- {
- char s[]="(sin(pi)^2+cos(pi)^2)";
- char sid[6];
- next(s,sid);
- if(sin(pi)*sin(pi)+cos(pi)*cos(pi)!=expr(s,sid))
- {
- clrscr();
- printf("\nTest failed");
- if(!getch()) getch();
- exit(1);
- }
- Oper.Op='Ж';
- Oper.tokval=0;
- }
- int graph(char *s,char *sid)
- {
- float a,b,i;
- int xmax,ymax,px,py,x0,y0;
- a=-4;
- b=4;
- xmax=getmaxx()+1;
- ymax=getmaxy()+1;
- px=100;
- py=100;
- x0=xmax/2;
- y0=ymax/2;
- for(;;)
- {
- if(((xmax/2+b*px)>xmax)||((xmax/2+a*px)<0))
- {
- next(s,sid);
- putpixel(xmax/2+Oper.x*px,ymax/2-expr(s,sid)*py,WHITE);
- px=px-1;
- py=py-1;
- Oper.Op='Ж';
- Oper.tokval=0;
- continue;
- }
- bar(0,0,xmax,ymax);
- setfillstyle(SOLID_FILL,WHITE);
- setcolor(GREEN);
- setlinestyle(SOLID_LINE,0,3);
- line(0,y0,xmax,y0);
- line(x0,0,x0,ymax);
- line(xmax,y0,xmax-20,y0+10);
- line(xmax,y0,xmax-20,y0-10);
- line(x0,0,x0-10,0+20);
- line(x0,0,x0+10,0+20);
- setlinestyle(DASHED_LINE,0,2);
- for(i=x0;i<xmax;i+=px) line(i,0,i,ymax);
- for(i=x0;i>0;i-=px) line(i,0,i,ymax);
- for(i=y0;i>0;i-=py) line(0,i,xmax,i);
- for(i=y0;i<ymax;i+=py) line(0,i,xmax,i);
- setlinestyle(DOTTED_LINE,0,2);
- for(i=x0;i<xmax;i+=(px/10)) line(i,0,i,ymax);
- for(i=x0;i>0;i-=(px/10)) line(i,0,i,ymax);
- for(i=y0;i>0;i-=(py/10)) line(0,i,xmax,i);
- for(i=y0;i<ymax;i+=(py/10)) line(0,i,xmax,i);
- setcolor(BROWN);
- setlinestyle(SOLID_LINE,0,3);
- circle(x0,y0,2);
- circle(x0+px,y0,2);
- circle(x0,y0-py,2);
- settextstyle(0,0,2);
- outtextxy(x0-18,y0+7,"0");
- outtextxy(x0+px,y0+14,"1");
- outtextxy(x0-14,y0-py,"1");
- outtextxy(xmax-25,y0+14,"X");
- outtextxy(x0-18,0+25,"Y");
- for(Oper.x=a;Oper.x<b;Oper.x+=(b-a)/xmax)
- {
- next(s,sid);
- putpixel(xmax/2+Oper.x*px,ymax/2-expr(s,sid)*py,BLUE);
- delay(5);
- Oper.Op='Ж';
- Oper.tokval=0;
- }
- break;
- }
- return 0;
- }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д