1

Bon, voilà je souhaiterai évaluer une expression mathématique en C sous ti68k.
Je ne souhaiterai pas passer par les arbres parce que je pense que ce n'est pas trop adapté sur ti68k. Je souhaiterai un algo itératif, parce que la recursivité n'est pas adaptée au 68k.

j'ai commencé à develloper un petit peu sous vc++ pour voir si l'algo que j'ai choisi est adapté, je ne sais meme pas si il marche dans tous les cas... mais bon le peu de cas que j'ai essayés marchent.
condition: l'expression doit etre valide (chiffre à virgule, + - / * (operateur binaire exclusivement pour le moment..)
A noter que seul l'algo est important.; c mal codé, et en plus les opérations devraient se faire sur des nombres de taille infini.. donc pas de double. n>>Exp;      cout<<endl<<"Analyse de l'expression: "<<Exp<<endl;      eval(Exp);      return 0; } qu'en pensez vous? Pensez vous qu'il puisse etre adapté à une expression avec parenthèses et fonctions?// az.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> using namespace std; /**********************************************************/ char Op[500]; double Nbr[500]; int iOp = 0; int iNbr = 0; #define EmpilerOp(pExp) Op[iOp++]=(pExp) #define EmpilerNbr(dNbr) Nbr[iNbr++]=dNbr #define DepilerNbr() (Nbr[--iNbr]) #define DepilerOp() (Op[--iOp]) /**********************************************************/ int PrioriteOp(char Op) {      switch(Op)      {           case '+': // binaire ...           case '-':                return 12;           case '*':           case '/':           default:                return 13;      } } double calcul(double dNbr1, char Op, double dNbr2) {      switch(Op)      {      case '+':           return dNbr1+dNbr2;      case '-':           return dNbr1-dNbr2;      case '/':           return dNbr1/dNbr2;      case '*':      default:           return dNbr1*dNbr2;      } } void eval(char *pExp) {      double dNbr,dDec;      char Op1,Op2;      while (*pExp)           if ( *pExp == '+' || *pExp == '-' || *pExp == '/' || *pExp == '*' )                EmpilerOp(*pExp++);           else           {                          dNbr = 0;                while ((*pExp>='0' && *pExp <='9'))                     dNbr = dNbr*10 + *pExp++ - '0';                if (*pExp=='.' || *pExp ==',')                {                     pExp++;                     dDec = 10;                     while ((*pExp>='0' && *pExp <='9'))                     {                          dNbr = dNbr + (*pExp++ - '0')/dDec;                          dDec*=10;                     }                }                if (iOp>=2)                {                     Op1 = DepilerOp();                     Op2 = DepilerOp();                     EmpilerOp(Op2);                     if ( PrioriteOp(Op1) > PrioriteOp(Op2) )          // on effectue le calcul du haut de la pile                     {                          dNbr = calcul(DepilerNbr(),Op1,dNbr);                     }                     else                     {                          EmpilerOp(Op1);                     }                }                     EmpilerNbr(dNbr);           }      for (int i=1;i<iNbr;i++)           Nbr[i] = calcul(Nbr[i-1], Op[i-1],Nbr[i]);      cout << "Resultat : " << Nbr[iNbr-1]<<endl; } int main(int argc, char* argv[]) {      char Exp[500];      ci

2

bon dejà il y a un probleme pour 2-2-2.. ca commence biensad

3

ca doit venir du calcul final que j'effectue de droit a gauche... 2-2-2 > 2-0 > 2 sad

4

-

5

c corrigé.

6

* Pour tes opérateurs, passe tout de suite aux pointeurs de fonctions... tu pourras faire plus de choses
* Tu devrais penser a gérer les erreurs ...

7

je pensais gérer les erreurs au début, par l'appelle d'une fonction bool ExpValide(char *pExp)

8

bon maintenant ca gere les parenthèse mais c en recursifsad
objectif, derecursifier l'algo et faire une bonne gestion de la ramtongue // az.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> using namespace std; /**********************************************************/ #define EmpilerOp(pExp) Op[iOp++]=(pExp) #define EmpilerNbr(dNbr) Nbr[iNbr++]=dNbr #define DepilerNbr() (Nbr[--iNbr]) #define DepilerOp() (Op[--iOp]) /**********************************************************/ int PrioriteOp(char Op) {      switch(Op)      {           case '+': // binaire ...           case '-':                return 12;           case '*':           case '/':           default:                return 13;      } } double calcul(double dNbr1, char Op, double dNbr2) {      switch(Op)      {      case '+':           return dNbr1+dNbr2;      case '-':           return dNbr1-dNbr2;      case '/':           return dNbr1/dNbr2;      case '*':      default:           return dNbr1*dNbr2;      } } double eval(char *pExp) {      double dNbr,dDec;      char Op1,Op2;      char Op[500];      double Nbr[500];      int iOp = 0;      int iNbr = 0;      while (*pExp)           if ( *pExp == '+' || *pExp == '-' || *pExp == '/' || *pExp == '*' )                EmpilerOp(*pExp++);           else                if ( *pExp == '(' )                {                     int i=1;                     EmpilerNbr(eval(++pExp));                     while(i)                     {                          if (*pExp == ')') i--;                          else if (*pExp == '(') i++;                          pExp++;                     }                }                else if ( *pExp == ')' )                {                     for (int i=1;i<iNbr;i++)                          Nbr[i] = calcul(Nbr[i-1], Op[i-1],Nbr[i]);                     return Nbr[iNbr-1];                }                else                {                          dNbr = 0;                while ((*pExp>='0' && *pExp <='9'))                     dNbr = dNbr*10 + *pExp++ - '0';                if (*pExp=='.' || *pExp ==',')                {                     pExp++;                     dDec = 10;                     while ((*pExp>='0' && *pExp <='9'))                     {                          dNbr = dNbr + (*pExp++ - '0')/dDec;                          dDec*=10;                     }                }                if (iOp>=2)                {                     Op1 = DepilerOp();                     Op2 = DepilerOp();                     EmpilerOp(Op2);                     if ( PrioriteOp(Op1) > PrioriteOp(Op2) )          // on effectue le calcul du haut de la pile                     {                          dNbr = calcul(DepilerNbr(),Op1,dNbr);                     }                     else                     {                          EmpilerOp(Op1);                     }                }                     EmpilerNbr(dNbr);           }      for (int i=1;i<iNbr;i++)           Nbr[i] = calcul(Nbr[i-1], Op[i-1],Nbr[i]);      return Nbr[iNbr-1]; } int main(int argc, char* argv[]) {      char Exp[500];      while(true){           cin>>Exp;           if (*Exp == 'q' )                break;           cout<<endl<<"Analyse de l'expression: "<<Exp<<endl;           cout<< "Resultat : "<<eval(Exp)<<endl;      }      return 0; }

9

Ops gestion du - unaire représenté par un '!' // az.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> using namespace std; /**********************************************************/ #define EmpilerOp(pExp) Op[iOp++]=(pExp) #define EmpilerNbr(dNbr) Nbr[iNbr++]=dNbr #define DepilerNbr() (Nbr[--iNbr]) #define DepilerOp() (Op[--iOp]) /**********************************************************/ int PrioriteOp(char Op) {      switch(Op)      {           case '+': // binaire ...           case '-':                return 12;           case '*':           case '/':           default:                return 13;      } } double calcul(double dNbr1, char Op, double dNbr2) {      switch(Op)      {      case '+':           return dNbr1+dNbr2;      case '-':           return dNbr1-dNbr2;      case '/':           return dNbr1/dNbr2;      case '*':      default:           return dNbr1*dNbr2;      } } double eval(char *pExp) {      double dNbr,dDec;      char Op1,Op2;      int minus =0;      char Op[500];      double Nbr[500];      int iOp = 0;      int iNbr = 0;      while (*pExp)           if ( *pExp == '+' || *pExp == '-' || *pExp == '/' || *pExp == '*' )                     EmpilerOp(*pExp++);           else if ( *pExp == '!')           {                minus++;                pExp++;           }           else                if ( *pExp == '(' )                {                     int i=1;                     EmpilerNbr(eval(++pExp));                     while(i)                     {                          if (*pExp == ')') i--;                          else if (*pExp == '(') i++;                          pExp++;                     }                }                else if ( *pExp == ')' )                {                     for (int i=1;i<iNbr;i++)                          Nbr[i] = calcul(Nbr[i-1], Op[i-1],Nbr[i]);                     return Nbr[iNbr-1];                }                else                {                          dNbr = 0;                while ((*pExp>='0' && *pExp <='9'))                     dNbr = dNbr*10 + *pExp++ - '0';                if (*pExp=='.' || *pExp ==',')                {                     pExp++;                     dDec = 10;                     while ((*pExp>='0' && *pExp <='9'))                     {                          dNbr = dNbr + (*pExp++ - '0')/dDec;                          dDec*=10;                     }                }                if (minus%2 == 1)                     dNbr = -dNbr;                minus = 0;                if (iOp>=2)                {                     Op1 = DepilerOp();                     Op2 = DepilerOp();                     EmpilerOp(Op2);                     if ( PrioriteOp(Op1) > PrioriteOp(Op2) )          // on effectue le calcul du haut de la pile                     {                          dNbr = calcul(DepilerNbr(),Op1,dNbr);                     }                     else                     {                          EmpilerOp(Op1);                     }                }                     EmpilerNbr(dNbr);           }      for (int i=1;i<iNbr;i++)           Nbr[i] = calcul(Nbr[i-1], Op[i-1],Nbr[i]);      return Nbr[iNbr-1]; } int main(int argc, char* argv[]) {      char Exp[500];      while(true){           cin>>Exp;           if (*Exp == 'q' )                break;           cout<<endl<<"Analyse de l'expression: "<<Exp<<endl;           cout<< "Resultat : "<<eval(Exp)<<endl;      }      return 0; }
j'attend vos critiques;p

10

Je n'ai pas tout compris à ton source (désolé, je n'aime pas les langages de haut niveau tongue, Assembleur only grin !), mais voici ce que je ferais en itératif pour la gestion des parenthèses :
1/ faire une sous-routine ne gérant que les expressions mathématiques sans parenthèses (ta première version, je suppose)
2/ compter les '(' et les ')', vérifier l'égalité, et enregistrer ce nombre dans une variables 'Parenthèses'
3/ scanner l'expression complète (avec parenthèses) de gauche à droite et s'arrêter à la première parenthèse fermante ')', puis de là, repartir vers la gauche et s'arrêter à la première parenthèse ouvrante '(', en enregistrant la position des 2 parenthèses trouvées
3 bis (variante)/ pareil, mais dans l'autre sens : scanner de droite à gauche jusqu'à la première ouvrante '(', et repartir vers la droite jusqu'à la première fermante ')' (choisis le sens qui te convient le mieux avec ce que tu as déjà fait)
Visualisation de l'étape 3 :
- expression de départ -> 2-((2+3)*(4-1)) d'où Parenthèse = 3
- chercher la première ')' de gauche à droite -> 2-((2+3)*(4-1))
- repartir vers la gauche jusqu'à '(' -> 2-((2+3)*(4-1))
4/ extraire les 3 sous-chaînes obtenus grâce aux positions enregistrées -> 2-( / 2+3 / *(4-1))
=> attention ! On peut avoir des sous-chaînes vides si on a une '(' tout au début ou une ')' tout à la fin !
5/ passer la sous-chaîne du milieu en paramètre à la sous-routine de l'étape 1 -> calcul( "2+3" ) => "5"
6/ recoller les 3 sous-chaînes en remplaçant celle du milieu par le résultat, la chaîne obtenue écrasant l'expression initiale, et décrémenter 'Parenthèses' -> 2-(5*(4-1)) avec Parenthèses = 2
7/ repartir à l'étape 3 jusqu'à ce que 'Parenthèses' soit nul

A vue de nez, ça doit bien marcher, ça doit pouvoir se coder facilement, et c'est itératif ...

@++
avatar
Je ne suis pas développeur Java : je suis artiste Java.
Ce que l’on conçoit bien s’énonce clairement, / Et le code pour l’écrire arrive aisément.
Hâtez-vous lentement ; toujours, avec méthode, / Vingt fois dans l’IDE travaillez votre code.
La perfection est atteinte, non pas lorsqu’il n’y a plus rien à ajouter, mais lorsqu’il n’y a plus rien à retirer.
You don't use science to show that you're right, you use science to become right.

11

ouui, mais la gestion des chaines me semble un peut lourde non? meme si mon code sera recoder en asm.. je cherche vraiment le plus efficace, a la limite l'algo que j'ai fait peut etre derecursifier facilement. le probleme, ce sera pour la gestion du pretty print, qui est beaucoup plus simple avec un arbre.

12

Gros inconvenient, pour un ploteur de fonction, je serai obligé de tout reparser... grrrr

13

Mouais, l'algo d'Ethaniel n'est pas génial génial.
Avec une pile tu dois pouvoir tout faire en une passe.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

14

bon je pense que je vais tokeniser les fonctions pour le plotter, comme ca ce sera beaucoup plus rapide. A moins que j'arrive a symplifier les eq.

15

je crayonne sasume...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

16

Tu veux faire ca pourquoi?
Tout ce qui passe pas par le port 80, c'est de la triche.

17

avatar

18

bon en gros avec ma methode, en une parse j'ai le resultat, mais pour le ploteur, ca me fera 240 parses.. alors que si je tokenise, ca allege les calculs repetitifs.
Pour le moment je tokenise l'expressin en faisant un simple tableau d'element:
#define INTEGER 'I'
#define REAL 'R'
#define PARAMETER 'P'
//#define FILE 'F'
#define OPERATOR 'O'
#define PAROPEN '('
#define PARCLOSE ')'
#define END '\0'

typedef struct {
char uType;
char Name[9];
void *pValue;
char Op;
} Element;

Si vous avez des url pour l'evaluation d'expression avec pile, je suis preneur

19

sources de CC...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

20

(c récursif mais ça se transpose facilement à une pile)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

21

CC?

22

23

c un truc de ouf CCsad
bon ca y est je gere les variables.
enfin faut quand meme que je fasse pour le moment dans le prog:
StoValue("pi",3.1415,pElement);
mais je gere pas encore les fonctions:'

24

bon je gere enfin les fonctionstongue enfin maintenant grosse seance de debugtongue

25

yEp;p
2*sqrt(3)*pi marche, je peut au moins calculer l'air d'un cercletongue

26

bon la gestion des fonctions et compagnie marche, mais je crois que j'ai oublié un detail important: ^ :'
je suis pas sur que je puisse l'implanter facilementsad // az.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <cstring> using namespace std; /**********************************************************/ #define EmpilerOp(pExp) Op[iOp++]=(pExp) #define EmpilerNbr(dNbr) Nbr[iNbr++]=dNbr #define DepilerNbr() (Nbr[--iNbr]) #define DepilerOp() (Op[--iOp]) /**********************************************************/ int PrioriteOp(char Op) {      switch(Op)      {           case '+': // binaire ...           case '-':                return 12;           case '*':           case '/':           default:                return 13;      } } double Operator(double dNbr1, char Op, double dNbr2) {      switch(Op)      {      case '+':           return dNbr1+dNbr2;      case '-':           return dNbr1-dNbr2;      case '/':           return dNbr1/dNbr2;      case '*':      default:           return dNbr1*dNbr2;      } } double factorial(double dNbr) {      double result = 1;      for (int i=1;i<=dNbr;i++)           result *=i;      return result; } double Function(char *pName, double dNbr) {      if (!strcmp(pName,"sqrt"))           return dNbr*dNbr;      if (!strcmp(pName,"factorial"))           return factorial(dNbr);      return -1; } ////////////////////////////////////////////////////////////////////////// // Variable declaration ////////////////////////////////////////////////// #define INTEGER          'I' #define REAL          'R' #define PARAMETER     'P' #define FUNCTION     'F' #define CUNDITIONS  'C' #define OPERATOR     'O' #define PAROPEN     '(' #define PARCLOSE    ')' #define END               '\0' typedef struct {      char uType;      char Name[9];      void *pValue;      char Op; } sElement; typedef struct {      char uNbrParam;      char **Names;      char Name[9]; } sFunction; sElement* TokenizeExp(char *pExp) {      int uSize = 500;      int uN = 0;      void *pValue;      char uType;      char Name[9];      char Op;      Name[8]=0;      sElement *pElement = (sElement*)malloc(sizeof(sElement)*uSize);            while(*pExp)      {           if (uN>uSize-1)           {                uSize+=500;                pElement = (sElement*)realloc((void*)pElement,sizeof(sElement)*uSize);           }           if (*pExp>='0' && *pExp<='9')           {                pValue = (int*)malloc(sizeof(double));                uType = INTEGER;                               double IntValue = 0;                double dDec = 10;                while ((*pExp>='0' && *pExp <='9'))                     IntValue = IntValue*10 + *pExp++ - '0';                if (*pExp=='.' || *pExp ==',')                {                     uType = REAL;                     pExp++;                     dDec = 10;                     while ((*pExp>='0' && *pExp <='9'))                     {                          IntValue = IntValue + (*pExp++ - '0')/dDec;                          dDec*=10;                     }                }                               *(double*)pValue = IntValue;           }           else if( *pExp == '+' || *pExp == '-' || *pExp == '/' || *pExp == '*' )           {                uType = OPERATOR;                pValue = malloc(sizeof(char));                Op = *pExp++;           }           else if(     (*pExp >='a' && *pExp<='z')                     ||     (*pExp>='A' && *pExp<='Z'))           {                int i=0;                while (          (*pExp >='a' && *pExp<='z')                           ||     (*pExp>='A' && *pExp<='Z')                          ||     (*pExp>='0' && *pExp <='9'))                     Name[i++] = *pExp++;                if (*pExp == '(' )                {                     uType = FUNCTION;                     pExp++;                }                else                uType = PARAMETER;                Name[i]=0;           }           else if (*pExp == '(' )           {                uType = PAROPEN;                pExp++;           }           else if (*pExp == ')' )           {                uType = PARCLOSE;                pExp++;           }                 strcpy(pElement[uN].Name,Name);           pElement[uN].pValue = pValue;           pElement[uN].uType = uType;           pElement[uN].Op = Op;           uN++;      }      pElement[uN].uType = END;      return pElement; } void DisplayTokenizedExp(sElement *pElement) {      while(pElement->uType != END)      {           cout<<"Type  : " << pElement->uType<<endl;           if (pElement->uType != PAROPEN && pElement->uType != PARCLOSE)           {                if (pElement->uType == 'I' || pElement->uType == 'R' )                     cout <<"Value : " << *(double*)(pElement->pValue)<<endl;                else if (pElement->uType == 'O' )                     cout << "Operator : " << pElement->Op<<endl;                if (pElement->uType == PARAMETER || pElement->uType == FUNCTION)                     cout << "Name  : "<<pElement->Name<<endl;           }           cout<<endl;           pElement++;      } } void StoValue(char *pNameParameter, double dNbr, sElement *pElement) {      while(pElement->uType != END)      {           if (pElement->uType == PARAMETER && strcmp(pElement->Name,pNameParameter) == 0)           {                pElement->pValue = malloc(sizeof(double));                *(double*)pElement->pValue = dNbr;           }           pElement++;      } } double EvalTokenizedExp(sElement *pElement) {      double dNbr;      char Op1,Op2;      int minus =0;      char Op[500];      double Nbr[500];      int iOp = 0;      int iNbr = 0;      while (pElement->uType != END)      {           switch(pElement->uType)           {                case OPERATOR:                     {                          EmpilerOp((pElement++)->Op);                          break;                     }                case FUNCTION:                     {                          int i=1;                          dNbr =  EvalTokenizedExp(++pElement);                          dNbr = Function(pElement->Name,dNbr);                          while(i)                          {                               if (pElement->uType == PARCLOSE) i--;                               else if (pElement->uType == PAROPEN || pElement->uType == FUNCTION) i++;                               pElement++;                          }                          if (iOp>=2)                          {                               Op1 = DepilerOp();                               Op2 = DepilerOp();                               EmpilerOp(Op2);                               if ( PrioriteOp(Op1) > PrioriteOp(Op2) )          // on effectue le calcul du haut de la pile                               {                                    dNbr = Operator(DepilerNbr(),Op1,dNbr);                               }                               else                               {                                    EmpilerOp(Op1);                               }                          }                          EmpilerNbr(dNbr);                          break;                     }                case PAROPEN:                     {                          int i=1;                          dNbr = EvalTokenizedExp(++pElement);                          while(i)                          {                               if (pElement->uType == PARCLOSE) i--;                               else if (pElement->uType == PAROPEN || pElement->uType == FUNCTION) i++;                               pElement++;                          }                          if (iOp>=2)                          {                               Op1 = DepilerOp();                               Op2 = DepilerOp();                               EmpilerOp(Op2);                               if ( PrioriteOp(Op1) > PrioriteOp(Op2) )          // on effectue le calcul du haut de la pile                               {                                    dNbr = Operator(DepilerNbr(),Op1,dNbr);                               }                               else                               {                                    EmpilerOp(Op1);                               }                          }                          EmpilerNbr(dNbr);                          break;                     }                case PARCLOSE:                     {                          int i = 1;                          for (;i<iNbr;i++)                               Nbr[i] = Operator(Nbr[i-1], Op[i-1],Nbr[i]);                          cout <<Nbr[iNbr-1]<<endl;                           return Nbr[iNbr-1];                     }                case REAL:                case INTEGER:                case PARAMETER:                     {                          dNbr = *(double*)(pElement++)->pValue;                          if (minus%2 == 1)                          dNbr = -dNbr;                          minus = 0;                          if (iOp>=2)                          {                               Op1 = DepilerOp();                               Op2 = DepilerOp();                               EmpilerOp(Op2);                               if ( PrioriteOp(Op1) >= PrioriteOp(Op2) )          // on effectue le calcul du haut de la pile                               {                                    dNbr = Operator(DepilerNbr(),Op1,dNbr);                               }                               else                               {                                    EmpilerOp(Op1);                               }                          }                          EmpilerNbr(dNbr);                          break;                     }                default:                     break;           }      }      for (int i=1;i<iNbr;i++)           Nbr[i] = Operator(Nbr[i-1], Op[i-1],Nbr[i]);      return Nbr[iNbr-1]; } int main(int argc, char* argv[]) {      char Exp[500];      while(true){           cin>>Exp;           if (*Exp == 'q' )                break; //          cout<<"Analyse de l'expression: "<<Exp<<endl; //          cout<< "Resultat : "<<eval(Exp)<<endl;           DisplayTokenizedExp(TokenizeExp(Exp));           sElement *pElement = TokenizeExp(Exp);           StoValue("pi",3.1415,pElement);           cout<<"Resultat : " << EvalTokenizedExp(pElement)<<endl;      }      return 0; }

27

faudra aussi que j'optimise un peut le code:'

28

bon avec l'^ je suis obligé de passé 2 fois la pile au lieu d'unesad et je trouve ca chiansad

29

Mais tu as des idées déjà bien en place pour ton CAS ou bien tu codes comme ça vient ?
Parce qu'à mon avis, pour réaliser un projet de cette envergure, il faut y réfléchir un minimum avant, plutôt que de programmer un bout de paseur, de lui rajouter un détail puis d'autres.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

30

Pour le moment je ne vise pas un cas, mais une apps de calcul pouvant travailler avec des entiers de taille inf etc.. (c'est pour cela que mes fonctions font des malloc(sizeof(double)) qui sera ensuite modifié) qui a aussi un ploteur (2D uniquement, c pas ce qu'il y a de plus dur a faire...) une pile (RPN normalement, d'ailleurs la validité de l'expression sera évaluée au cours du calcul)) et pretty print. Ca fait bcp c pour ca que je promet rien, pour le moment je me familliarise avec un algo d'evaluation d'expression.
En revanche il pourra accepter 2*x+1 | x=3 ou 2*x+1 -> f(x) (d'ailleur il le gere deja en interne).