Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Un plotter de fonctions mathematiques

4 réponses
Avatar
ELAATIFI Sidi Mohamed
Voila un plotter de fonctions simple ecrit
/*
* PLOT.CPP - Dessiner un graph
* Design & Programmation : ELAATIFI Sidi Mohamed
* <elaatifi@menara.ma>
* 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[i] < LeX )
rPile_Push(&p,f.d[i]);
else
{
switch(f.d[i] )
{
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 <elaatifi@menara.ma>";
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();

}

4 réponses

Avatar
flure
Voila un plotter de fonctions simple ecrit
/*
* PLOT.CPP - Dessiner un graph
* Design & Programmation : ELAATIFI Sidi Mohamed
*


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 ...


--
Florent "flure" C.
http://flure.free.fr

Avatar
Targeur fou
ELAATIFI Sidi Mohamed wrote:


Bonjour,

Voila un plotter de fonctions simple ecrit
/*
* PLOT.CPP - Dessiner un graph


Plutôt extension C si c'est du C.

#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>


Prends l'habitude de séparer en-têtes standard, en-têtes propres à
ton système et les tiens,
c'est plus lisible, à mon avis.

/* en-têtes standard */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>

/* en-têtes propres au système machin-bidule (DOS ?) */
#include <conio.h>
#include <dos.h>
#include <graphics.h>

/* mes en-têtes */
#include "pile.h"

[coupé]

typedef enum
{
LeX = 1000, // variable x


Attention à ne pas trop mélanger les commentaires C90 /**/ avec ceux
simple-ligne // de C++ et C99 pour la bonne et simple raison que
beaucoup de compilateurs C ne supportent que le premier style (C90),...
m'enfin ce n'est pas si grave.

[coupé]

Une meilleure modularisation aurait été la bienvenue, les structures
Fonction et Buffer
mériteraient de monter dans un .h
Les variables globales (valeurLex and co.) en mises en classe extern (1
et 1 seule définition par la suite) si elles sont montées dans un .h
ou mises en static si elles restent dans le .c (visibilité locale à
ce qui suit dans le .c).

int est_Num(char c)
{
return c >='0' && c <='9';
}


Un fonction de la bibliothèque standard C le fait déjà : int
isdigit(int car); /* ctype.h */

int est_Alpha(char c)
{
return c>='a'&& c<='z';
}


Idem qu'au-dessus : int islower(int car); /* ctype.h */
A moins que ce soit int isalpha(int car); que tu souhaites, équivalent
à return ((car>='a' && car<='z') || (car>='A' && car<='Z')); /* en
ASCII, du moins... */

[coupé]

int est_Sep(char c)
{
return c==' '|| c=='n';
}


Pourquoi pas, mais là il y a int isspace(int car); toujours dans
ctype.h qui fait presque ce boulot. A toi de voir si tu considères que
les tabulations, saut de page sont aussi des séparateurs pour tes
besoins.

[coupé]

char Get(Buffer* b)
{
return b->data[b->size++];


Aïe...Es-tu sûr que :
1) b n'est pas NULL
2) 0 <= b->size <= 99, contrôle des limites de tableaux

Une question à se poser, que va t'on retourner comme caractère en cas
d'erreur ? Je propose d'utiliser int plutôt que char pour le controle
d'erreur, histoire d'utiliser EOF (End of File, "constante non
représentable" en char).
Pour le contrôle des limites de tableaux, tu peux utiliser
l'opérateur sizeof(type ou var.) qui détermine la taille du type ou
de la variable en bytes.
Par exemple sizeof(tableau)/sizeof(tableau[0]) te donne le nombre
d'éléments du tableau.

int Get(Buffer * b)
{
int rc;
/* ctrl ptr NULL */
if (b == NULL) {
fprintf(stderr,"Get(): pointeur b (type Buffer*) NULLn");
rc = EOF;
}
else {
/* ctrl des bornes */
if (b->size >=0 && b->size <=
(sizeof(b->data)/sizeof(b->data[0])-1 ) {
rc = b->data[b->size++];
}
else {
fprintf(stderr,"Get(): indice de tableau hors bornesn");
rc = EOF;
}
}
return rc;
}

C'est un peu plus de code, mais c'est bien plus robuste et ca permet de
tracer les problèmes quand ils arrivent (gain de temps en
maintenance).

J'ai regardé un peu la suite, ce sont un souvent les mêmes problèmes
qui reviennent : contrôle de la validité des pointeurs ainsi que des
bornes des tableaux (pareil avec la structure Fonction). Je n'ai pas
regardé le fonctionnel.

Regis

Avatar
CBFalconer
flure wrote:

Voila un plotter de fonctions simple ecrit
/*
* PLOT.CPP - Dessiner un graph
* Design & Programmation : ELAATIFI Sidi Mohamed
*


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 ...


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.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson


Avatar
elaatifi
D'abord Merci pour vos remarques,
en fait je suis un newbie des Newsgroup (veilliez m'éxcuser).
beacoup de gens m'ont demandé d'ecrire un petit plotter de fonctions(
pour MS-DOS sous Turbo C++ 3.0 dans un cadre pédagogique) danc, j'ai
ecris ce petit programme pour tracer un peu le graphe de fonction.

J'avais pas beacoup de temps (quelques heurs) danc je me suis préssé
pour achever l'evaluateur d'expressions et l'affichage graphique.

Si ca vous interresse et pour essayer ce bout de code vous pouver le
telecharger sur : http://smelaatifi.free.fr/pub/realisations/plot.zip

Merci.