Un plotter de fonctions mathematiques

  • Thread starter ELAATIFI Sidi Mohamed
  • Start date
E

ELAATIFI Sidi Mohamed

Voila un plotter de fonctions simple ecrit
/*
* PLOT.CPP - Dessiner un graph
* Design & Programmation : ELAATIFI Sidi Mohamed
* <[email protected]>
* 01/2005
*/
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>

#include "pile.h"
/*
******** Interpreteur ****************************
*/
/*
* Constantes & Macros
*/
#define MAXBUF 300
#define ZEROBUF(x) memset(x,0,MAXBUF)
/*
* la liste des symbole support‚s
*/
typedef enum
{
LeX = 1000, // variable x
Pi,
E1,
Nombre, // nombre entier
ParD, // prenthese droit
ParG, // --------- Gauche
Plus, // +
Moin, // -
Multiplier, // *
Diviser, // /
Sin, // Sinus
Cos, // Cosinus
Tan, // ...
Sqrt,
Ln,
Exp,
ACos,
ATan,
Sinh,
Cosh,
Tanh,
Pow,
Abs,
ASin,
Separateur, // Separateurs tel espace ' ' et nouvelle ligne '\n'
Erreur // Token indefini ou erreur
}Token;
/*
* Type lexical
*/
typedef struct
{
int s;
int d[100];
}Fonction;

typedef struct
{
int size;
char data[100];
}Buffer;
/*
* Donn‚es Globales utilis‚es dans tout le programme
*/
char valeurLex[MAXBUF];
int valeurLexTaille=0;
int valeurLexEntier=0;
/*
* Analyse lexicale
* ****************
* Ici on decrit toute les fonctions que l'analyseur peut
* utiliser ...
*/
int est_Num(char c)
{
return c >='0' && c <='9';
}
int est_Alpha(char c)
{
return c>='a'&& c<='z';
}
int est_Oper(char c)
{
return c=='+'||c=='*'||c=='-'||c=='/'||c=='^';
}
int est_Sep(char c)
{
return c==' '||c=='\n';
}
int est_Pars(char c)
{
return c==')'||c=='(';
}
char Get(Buffer* b)
{
return b->data[b->size++];
}
void Put(Buffer* b,char c)
{
//b->data[b->size--] = c;
b->size--;
}
Token AnalyseLexic(Buffer* b)
{
char c;
char done = 0; // false
ZEROBUF(valeurLex);
valeurLexTaille = 0;
//char* pstr = *p;

c = Get(b)/*fgetc(f)*/ ;

if(est_Num(c)) {
Put(b,c)/*ungetc(c,f)*/;
int s = sscanf((char*)(b->data+b->size),"%d",&valeurLexEntier);
b->size += s;
return Nombre;
}
else if(est_Oper(c)) {
switch(c)
{
case '+':
return Plus;
case '-':
return Moin;
case '/':
return Diviser;
case '*':
return Multiplier;
case '^':
return Pow;
}
}
else if(est_Alpha(c)) {
if( c == 'x' )
return LeX;
else
{
char buf[6];
int index=0;
while(c!=EOF && !done)
{
buf[index++] = c;
c = Get(b)/*fgetc(f)*/;
if(!est_Alpha(c))
{
Put(b,c) /*ungetc(c,f)*/;
done = 1;
}
}
buf[index] = 0;
strcpy(valeurLex,buf);

#define SI_F(x) if(!strcmp(buf,x))
#define ESI_F(x) else if(!strcmp(buf,x))
SI_F("sin")
return Sin;
ESI_F("cos")
return Cos;
ESI_F("tan")
return Tan;
ESI_F("exp")
return Exp;
ESI_F("sqrt")
return Sqrt;
ESI_F("ln")
return Ln;
ESI_F("asin")
return ASin;
ESI_F("acos")
return ACos;
ESI_F("atan")
return ATan;
ESI_F("sinh")
return Sinh;
ESI_F("cosh")
return Cosh;
ESI_F("tanh")
return Tanh;
ESI_F("abs")
return Abs;
ESI_F("pi")
return Pi;
return Erreur;

}
}
else if(est_Pars(c))
{
if( c == ')' )
return ParD;
return ParG;
}
else if(est_Sep(c))
return Separateur;
return Erreur;
}
/*
* Analyseur syntaxique
* ********************
* L'autre part du ce p'tit evaluateur d'expression ;-)
* ici j'aurais … decrir les fonctions du analyseur syntaxique
*/
void compileExpr(Fonction* fn,Buffer* b)
{
Pile pile;
char done = 0;
Token t;
fn->s = 0;
Pile_Init(&pile);

while(!done)
{
t = AnalyseLexic(b);

if( t == ParD)
{

Token t1 = (Token)Pile_Pop(&pile);//operation
Token t2 = (Token)Pile_Pop(&pile);// ParG
Token t = t1;
if( t1 == ParG )
t = t2;
fn->d[fn->s++] = t;
}
else if( t == Nombre )
{
fn->d[fn->s++] = valeurLexEntier;
}
else if( t == LeX )
{
fn->d[fn->s++] = LeX;
}
else if( t == Erreur)
{
while(pile.index > 0)
fn->d[fn->s++] = Pile_Pop(&pile);
done = 1;
}
else if( t == Separateur)
{
while(pile.index > 0)
fn->d[fn->s++] = Pile_Pop(&pile);
done = 1;
}
else
{
Pile_Push(&pile,t);
}
}


}
/*
* Evaluation de l'experssion compil‚
*/
#define INDEF 3000
double evalueExpr(Fonction f,double x)
{
rPile p;
double a = 0.0;

rPile_Init(&p);

double ans = 0.0;
for(int i=0;i<f.s;i++)
{
if( f.d < LeX )
rPile_Push(&p,f.d);
else
{
switch(f.d )
{
case LeX:
rPile_Push(&p,x);
break;
case Plus:
ans = rPile_Pop(&p) + rPile_Pop(&p);
rPile_Push(&p,ans);
break;
case Moin:
ans = -rPile_Pop(&p);
if( p.index>0)
ans+=rPile_Pop(&p);
rPile_Push(&p,ans);
break;
case Multiplier:
ans = rPile_Pop(&p) * rPile_Pop(&p);
rPile_Push(&p,ans);
break;
case Diviser:
a = rPile_Pop(&p);
ans = rPile_Pop(&p);
if( a!= 0)
ans /= a;
else
return INDEF;
rPile_Push(&p,ans);
break;
case Sin:
ans = sin( rPile_Pop(&p) );
rPile_Push(&p,ans);
break;
/*case Sin:
ans = rPile_Pop(&p)
rPile_Push(&p,ans);
break;
*/
case Cos:
ans = cos( (double)rPile_Pop(&p) );
rPile_Push(&p,ans);
break;
case Tan:
ans = rPile_Pop(&p);
if( abs(ans) != M_PI_2)
ans = tan(ans);
else
return INDEF;
rPile_Push(&p,ans);
break;
case Ln:
ans = rPile_Pop(&p);
if( ans > 0)
ans = log( ans );
else
return INDEF;
rPile_Push(&p,ans);
break;
case Sqrt:
ans = rPile_Pop(&p);
if( ans >= 0)
ans = sqrt(ans);
else
return INDEF;
rPile_Push(&p,ans);
break;
case ASin:
a = rPile_Pop(&p);
if( a >= -1 && a <= 1)
ans = asin(a);
rPile_Push(&p,ans);
break;
case ACos:
a = rPile_Pop(&p);
if( a >= -1 && a <= 1)
ans = acos(a);
rPile_Push(&p,ans);
break;
case ATan:
a = rPile_Pop(&p);
ans = atan(a);
rPile_Push(&p,ans);
case Sinh:
a = rPile_Pop(&p);
ans = sinh(a);
rPile_Push(&p,ans);
break;
case Cosh:
ans = cosh(a);
a = rPile_Pop(&p);
rPile_Push(&p,ans);
break;
case Tanh:
a = rPile_Pop(&p);
tanh(a);
rPile_Push(&p,ans);
break;
case Exp:
ans = exp(rPile_Pop(&p));
rPile_Push(&p,ans);
break;
case Pow:
double b = rPile_Pop(&p);
a = rPile_Pop(&p);
if(b>0)
ans = pow(b,a);
else if( b!= 0)
if(a>0)
ans = mypow(b,(unsigned)a);
rPile_Push(&p,ans);
break;
case Abs:
a = rPile_Pop(&p);
ans = fabs(a);
rPile_Push(&p,ans);
break;
}
}

}
return rPile_Pop(&p);
}

/*
* Gestion graphique
*/
#define MINY 0
#define MINX 0
#define MAXX 639
#define MAXY 400
#define MIDX (MAXX+MINX)/2
#define MIDY (MAXY+MINY)/2
#define STER 30

int timeout = 0;
void const_graph()
{
int gdriver = DETECT, gmode, errorcode;
int xmax, ymax;
initgraph(&gdriver, &gmode, "..\\BGI");
}

void dessiner_fenetre(char * titre)
{
// cadre
setlinestyle(SOLID_LINE,1,1);
setcolor(15);
outtextxy(MIDX-4*strlen(titre),MAXY+70,titre);
setfillstyle(SOLID_FILL,1);
bar(MINX,MINY,MAXX,MAXY);
rectangle(MINX,MINY,MAXX,MAXY);

setlinestyle(DOTTED_LINE,1,1);
setcolor(9);

for(int i=-MIDX/STER;i<=MIDX/STER;i++)
{
line(MIDX+i*STER,MINY,MIDX+i*STER,MAXY);
}

for(i=-MIDY/STER;i<=MIDY/STER;i++)
{
line(MINX,MIDY+i*STER,MAXX,MIDY+i*STER);
}
// echele
setcolor(15);
setlinestyle(SOLID_LINE,1,1);
line(MIDX,MINY,MIDX,MAXY);
line(MINX,MIDY,MAXX,MIDY);
}

void dessiner_erreur(char* str)
{
setcolor(4);
outtextxy(MIDX-strlen(str)*4,MAXY+10,str);
}

void dessiner_foncstr(char *str)
{
setfillstyle(SOLID_FILL,0);
bar(MINX,MAXY+50,MINX+300,MAXY+60);
setcolor(15);
outtextxy(MINX,MAXY+50,"f(x) = ");
setcolor(7);
outtextxy(MINX+64,MAXY+50,str);
}
void lire_fonction(Fonction *fn,char *chaine)
{
char done = 0;
int index = 0;
char c;
while(!done)
{
dessiner_foncstr(chaine);
c = getch();
if( c == 13 )
{
done = 1;
chaine[index] = 0;
}
else
if( c == 8)
{
chaine[--index] = 0;
}
else
chaine[index++] = c;
}
Buffer b;
b.size = 0;
strcpy(b.data,chaine);
compileExpr(fn,&b);

}
void dessiner_fonction(Fonction fn,int zoomx,int zoomy)
{

const float fact = 1;

int y = 0;
float x = 0;
double e;
int gr[MIDX*2];

setlinestyle(SOLID_LINE,1,1);

for(int i=-MIDX;i<MIDX;i++)
{
x = (float) i / zoomx;
e = evalueExpr(fn,x);
if(e != INDEF)
{
y = (float) zoomy*e;
gr[MIDX+i] = MIDY-y;
}
else
{
gr[MIDX+i] = INDEF;
}

}
setcolor(14);
for(i=-MIDX;i<MIDX-1;i++)
{
int j = MIDX+i;
if((gr[j+1] <MAXY && gr[j+1] >MINY) && (gr[j]>=MINY && gr[j] <= MAXY))
{
if(timeout == 1)
delay(20);
line(j,gr[j],j+1,gr[j+1]);
}
//putpixel(j,gr[j],14);
}
}

void detr_graph()
{
closegraph();
}

/*
* Main
*/

char* INFO = "Par ELAATIFI Sidi Mohamed 2005 <[email protected]>";
void main()
{
char choix;
char chaine[100];

clrscr();
Fonction f;
Buffer b;
b.size = 0;

f.d[0] = LeX;
f.s = 1;
strcpy(chaine,"x");
const_graph();
int zoomx = STER;
int zoomy = STER;
choix = 0;
while(choix != 27 && choix!='q')
{

if( zoomx <= 10 )
zoomx = 10;
if( zoomy <= 10)
zoomy = 10;
dessiner_fenetre(INFO);
dessiner_fonction(f,zoomx,zoomy);
dessiner_erreur("+ - * / Pour agrandir ou deminuer l'echelle |
s:entr‚e nouvelle | r:redefinir l'echelle");
dessiner_foncstr(chaine);
choix = getch();
switch(choix)
{
case '+':
zoomx+=5;
break;
case '-':
zoomx-=5;
break;
case '*':
zoomy+=5;
break;
case '/':
zoomy-=5;
break;
case 's':
memset(chaine,0,100);
memset(&f,0,sizeof(f));
lire_fonction(&f,chaine);
break;
case 'd':
dessiner_fenetre(INFO);
timeout = 1;
dessiner_fonction(f,zoomx,zoomy);
dessiner_erreur("+ - * / Pour agrandir ou deminuer l'echelle |
s:entr‚e nouvelle | r:redefinir l'echelle");
dessiner_foncstr(chaine);
timeout = 0;
break;
case 'r':
zoomx = STER;
zoomy = STER;
break;
}
}

detr_graph();

}
 
F

flure

ELAATIFI Sidi Mohamed a écrit :
Voila un plotter de fonctions simple ecrit
/*
* PLOT.CPP - Dessiner un graph
* Design & Programmation : ELAATIFI Sidi Mohamed
* <[email protected]>

Tu ne devrais pas mettre en clair ton adresse de courriel sur les
newsgroups, tu risques de te faire spammer.
* 01/2005
*/
#include <conio.h>

Pas portable
#include <graphics.h>

Pas portable
#include <dos.h>

Pas portable


Le reste a l'air intéressant, mais comme ce n'est pas portable, je ne
peux pas le compiler chez moi pour le tester, et je me vois mal analyser
toutes ces lignes de code pour essayer de déterminer ce que c'est censé
faire.
Dommage ...

De plus, tu crucipostes sans remplir le champs "Faire suivre à"
("Follow-up to" dans les lecteurs de news non francisés), et c'est ce
qu'on appelle communément quelque chose de *mal*.
Enfin, tu crucipostes en français sur un newsgroup non francophone, ce
qui est aussi, et bien, *mal*.

Je positionnes donc le fu2 sur fr.comp.lang.c ...
 
C

CBFalconer

flure said:
ELAATIFI Sidi Mohamed a écrit :


Tu ne devrais pas mettre en clair ton adresse de courriel sur les
newsgroups, tu risques de te faire spammer.


Pas portable


Pas portable


Pas portable

Le reste a l'air intéressant, mais comme ce n'est pas portable, je
ne peux pas le compiler chez moi pour le tester, et je me vois mal
analyser toutes ces lignes de code pour essayer de déterminer ce
que c'est censé faire.
Dommage ...

I believe this translates to roughly "It appears interesting, but
since it is non portable I have no way of compiling or testing it,
and I am not about to fix it. Pity".
De plus, tu crucipostes sans remplir le champs "Faire suivre à"
("Follow-up to" dans les lecteurs de news non francisés), et c'est
ce qu'on appelle communément quelque chose de *mal*.
Enfin, tu crucipostes en français sur un newsgroup non francophone,
ce qui est aussi, et bien, *mal*.

This I can't translate satisfactorily except that it is about
cross-posting. The following line announces that follow-ups have
been set.
Je positionnes donc le fu2 sur fr.comp.lang.c ...

I could not quote from the original, since it is so large that my
newsreader refuses to quote it at all. Thus this, and I am not
snipping anything because my french is too poor to do so
intelligently.

I believe you have adequately made the point that this code is
totally non-portable, and has no business on c.l.c. The OP might
have at least specified what system he ran it on, without which the
meaning of <graphics.h> <conio.h> <dos.h> can be absolutely
anything. There is a finite chance that it used the Borland 2.01
Turbo C, available in their museum.

However I also see that the original has tied itself to the ASCII
char set with the various "est_*" functions. This is again
unnecessary, and the reason that the things in <ctype.h> exist.

His avoidance of spaces causes confusion and warnings in systems
that can accept "=-" as synonymous with "-=". Most of them do the
right thing. Seems rather silly to conserve blanks when he uses
such excessive indentation in the first place.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top