Un plotter de fonctions mathematiques

Discussion in 'C Programming' started by ELAATIFI Sidi Mohamed, Jan 25, 2005.

  1. Voila un plotter de fonctions simple ecrit
    /*
    * PLOT.CPP - Dessiner un graph
    * Design & Programmation : ELAATIFI Sidi Mohamed
    * <>
    * 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 <>";
    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();

    }
    ELAATIFI Sidi Mohamed, Jan 25, 2005
    #1
    1. Advertising

  2. ELAATIFI Sidi Mohamed

    flure Guest

    ELAATIFI Sidi Mohamed a écrit :
    > 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
    flure, Jan 25, 2005
    #2
    1. Advertising

  3. ELAATIFI Sidi Mohamed

    CBFalconer Guest

    flure wrote:
    > ELAATIFI Sidi Mohamed a écrit :
    >
    >> 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
    CBFalconer, Jan 25, 2005
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. paolo
    Replies:
    0
    Views:
    365
    paolo
    Mar 10, 2005
  2. Charles Krug
    Replies:
    2
    Views:
    5,342
    Charles Krug
    Apr 28, 2005
  3. Ala

    ODE, GUI, plotter in Python

    Ala, Jun 16, 2009, in forum: Python
    Replies:
    3
    Views:
    698
    Rob Clewley
    Jun 17, 2009
  4. david croll
    Replies:
    0
    Views:
    76
    david croll
    Jul 30, 2003
  5. David Tran
    Replies:
    2
    Views:
    118
    David Tran
    Jul 13, 2006
Loading...

Share This Page