Распознавание формулы со сложными математическими функциями в строке - 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;
}