Aide pour calcul de formule

snakers07 Messages postés 15 Date d'inscription vendredi 14 novembre 2008 Statut Membre Dernière intervention 24 octobre 2009 - 15 mai 2009 à 09:57
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 - 26 mai 2009 à 19:40
bonjour, j'ai crée un programme permettant de calculer une formule utilisant les opérateurs +,-,*,/
avec un controle sur les parenthése:
par exemple :
((5-4)-(3*4))=-11

le probleme est que je suis obligé à chaque fois de parenthéser complétement mon expression.

je voudrais avoir ceci:

avant: ((5-4)-(3*4))=-11
après: (5-4)-(3*4)=-11  j'aimerai que en écrivant cette formule sous cette forme, qu'il me donne le même résulat

voici mon code:

#include
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma warning(disable : 4996)
/*-----
 Pile Num
   -----*/
struct StructNumLifo{
 double pile[50];
 int sommet;
};


typedef struct StructNumLifo NumLifo;


void initialiserNum(NumLifo* lifo){
 //initialisation des valeurs de la pile
 int i=0;
 for(i=0;i<50;i++){
  lifo->pile[i]=0; //lifo->pile[i] est equivalent à *lifo.pile[i]
 }
 //initialisation du sommet
 lifo->sommet=-1;
}
int empilerNum(NumLifo* lifo, double value){
 //test de position du sommet
 if(lifo->sommet < 49){
  lifo->sommet++; //incrémentation du sommet
  lifo->pile[lifo->sommet] = value; //enregistrement de la valeur
  return 1;
 }else{
  return 0;
 }
}
double depilerNum(NumLifo* lifo){
 double value=0; //test de position du sommet
 if(lifo->sommet > -1){
  value = lifo->pile[lifo->sommet]; //récupération temporaire de la valeur
  lifo->pile[lifo->sommet] = 0; //mise à zéro de la valeur courante
  lifo->sommet--; //décrémentation du sommet
  return value;
 }else{
  return 0;
 }
}
void afficherNum(NumLifo* lifo){
 int i=0;
 printf("\n");
 for(i=0;i<=lifo->sommet;i++){
  printf("%d\t%f\n",i,lifo->pile[i]);
 }
 printf("Sommet %d\n",lifo->sommet);
}




/*-----
 Pile Char
   -----*/
struct StructChar{
 char pile[50];
 int sommet;
};


typedef struct StructChar CharLifo;


void initialiserChar(CharLifo* lifo){
 //initialisation des valeurs de la pile
 int i=0;
 for(i=0;i<50;i++){
  lifo->pile[i]='\0';
 }
 //initialisation du sommet
 lifo->sommet=-1;
}
int empilerChar(CharLifo* lifo, char value){
 //test de position du sommet
 if(lifo->sommet < 49){
  lifo->sommet++; //incrémentation du sommet
  lifo->pile[lifo->sommet] = value; //enregistrement de la valeur
  return 1;
 }else{
  return 0;
 }
}
char depilerChar(CharLifo* lifo){
 char value = '\0';
 //Test de position du sommet
 if(lifo->sommet > -1){
  value = lifo->pile[lifo->sommet]; //récupération temporaire de la valeur
  lifo->pile[lifo->sommet] = 0; //mise à zéro de la valeur courante
  lifo->sommet--; //décrémentation du sommet
  return value;
 }else{
  return 0;
 }
}
void afficherChar(CharLifo* lifo){
 int i=0;
 printf("\n");
 for(i=0;i<=lifo->sommet;i++){
  printf("%d\t%c\n",i,lifo->pile[i]);
 }
 printf("Flag %d\n",lifo->sommet);
}
/*-----
 Calcul
   -----*/
double calcul(char* expression){
 //Déclarations
 char* c=NULL; //pointeur qui parcourt le tableau (plus facile que naviguer dans celui-ci)
 int OpenParenthese = 0; //définit si la derniére occurance été une parenthése ouvrante : seul cas possbile pour un nombre négatif
 NumLifo numbers; //pile des nombres
 CharLifo operations; //pile des opérations
 initialiserNum(&numbers);
 initialiserChar(&operations);


 //Parcours de l'expression
 for(c=expression; c<expression+strlen(expression); c++){


  
  
  //Détection d'un nombre
  if( (*c>='0' && *c<='9') || (*c=='-' && OpenParenthese==1) ){
   char* end; //poiteur de fin de chaine du nombre
   double number;
   
   //récupération du nombre
   number=strtod(c,&end);  /*fonction qui convertie une portion de chaine en double (ex: 2 chiffres a la suite en nombre)
         chercher sur internet pour faciliter les calculs parce que sinon trop incomprehensible*/
   empilerNum(&numbers,number);


   //mise à jours des variables
   c=end-1;
   OpenParenthese=0;
   continue;
  }


  //Détection d'une opération  if(*c '+' || *c '-' || *c == '*' || *c == '/'){
   empilerChar(&operations,*c);
   OpenParenthese=0;
   continue;
  }


  //Déclenchement d'un calcul
  if(*c == ')'){
   double nb1 = depilerNum(&numbers);
   double nb2 = depilerNum(&numbers);
   char operation = depilerChar(&operations);


   switch (operation){
    case '*' :
     empilerNum(&numbers,nb2*nb1);
     printf("%f * %f = %f\n",nb2,nb1,nb2*nb1);
     break;
    case '+' :
     empilerNum(&numbers,nb2+nb1);
     printf("%f + %f = %f\n",nb2,nb1,nb2+nb1);
     break;
    case '-' :
     empilerNum(&numbers,nb2-nb1);
     printf("%f - %f = %f\n",nb2,nb1,nb2-nb1);
     break;
    case '/' :
     empilerNum(&numbers,nb2/nb1);
     printf("%f / %f = %f\n",nb2,nb1,nb2/nb1);
     break;
   } 
   OpenParenthese=0;
  }
 }
 return depilerNum(&numbers);
}
/*-----
 Interface
   -----*/




void startCalcul(char* expression){
 printf("%s = %f\n\n",expression,calcul(expression));
}


 
 


/*-----
  Main
   -----*/
void main(){
 
    char expression[50];


 system("cls");
 printf("Saisir une expression completement parenthesee :\n");
 scanf("%s", &expression);
 startCalcul(expression);
}

merci d'avance de votre aide...

3 réponses

cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
15 mai 2009 à 11:23
Il y a plein d'autre petites erreurs:

Saisir une expression completement parenthesee :
(((1+1)))
1.000000 + 1.000000 = 2.000000
(((1+1))) = 0.000000

Saisir une expression completement parenthesee :
(1--1)   
1.000000 - 1.000000 = 0.000000
(1--1) = 0.000000

Saisir une expression completement parenthesee :
(1 + 1)
(1 = 1.000000

Saisir une expression completement parenthesee :
toto          
toto = 0.000000

Saisir une expression completement parenthesee :
x1+1)
1.000000 + 1.000000 = 2.000000
x1+1) = 2.000000

Quelques remarques sur le code:
 for(c=expression; c<expression+strlen(expression); c++)
Et pourquoi pas tout simplement ceci, qui est plus rapide d'ailleurs:
 for (char* c = expression; c && *c; c++)
Ou si tu préfères, en plus explicite:
 for (char* c = expression; c != NULL && *c != '\0'; c++)

Voici toutefois une version qui fonctionne, que j'ai un peu "proprisé" en passant (et corriger 2-3 petits trucs). Ton problème venait du fait que tu ne te servait jamais de "OpenParenthese". A noter que c'est plus de la bidouille sale fait à la va-vite, qu'autre chose. Renseigne toi sur une vraie méthode pour répondre à ce besoin: les AST.

Les modifs:

//#include
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* #pragma warning(disable : 4996) */

struct StructNumLifo
{
  double pile[50];
  int sommet;
};

typedef struct StructNumLifo NumLifo;

void initialiserNum(NumLifo* lifo)
{
  for (int i = 0; i < 50; i++)
    lifo->pile[i] = 0;

  lifo->sommet=-1;
}

int empilerNum(NumLifo* lifo, double value)
{
  if (lifo->sommet < 49)
  {
    lifo->sommet++;
    lifo->pile[lifo->sommet] = value;
    return 1;
  }
  return 0;
}

double depilerNum(NumLifo* lifo)
{
  if (lifo->sommet > -1)
  {
    double value = lifo->pile[lifo->sommet];
    lifo->pile[lifo->sommet] = 0;
    lifo->sommet--;
    return value;
  }
  return 0;
}

void afficherNum(NumLifo* lifo)
{
  printf("\n");
  for (int i = 0; i <= lifo->sommet; i++)
    printf("%d\t%f\n",i,lifo->pile[i]);
  printf("Sommet %d\n",lifo->sommet);
}

/*-----
  Pile Char
  -----*/
struct StructChar
{
  char pile[50];
  int sommet;
};

typedef struct StructChar CharLifo;

void initialiserChar(CharLifo* lifo)
{
  int i = 0;

  for (i = 0; i < 50; i++)
    lifo->pile[i] = '\0';
  lifo->sommet = -1;
}

int empilerChar(CharLifo* lifo, char value)
{
  if (lifo->sommet < 49)
  {
    lifo->sommet++;
    lifo->pile[lifo->sommet] = value;
    return 1;
  }
  return 0;
}

char depilerChar(CharLifo* lifo)
{
  if (lifo->sommet > -1)
  {
    char value = lifo->pile[lifo->sommet];
    lifo->pile[lifo->sommet] = 0;
    lifo->sommet--;
    return value;
  }
  return 0;
}

void afficherChar(CharLifo* lifo)
{
  printf("\n");
  for (int i = 0; i <= lifo->sommet; i++)
    printf("%d\t%c\n", i, lifo->pile[i]);
  printf("Flag %d\n", lifo->sommet);
}

/*-----
  Calcul
  -----*/
double calcul(char* expression)
{
  int OpenParenthese = 1;
  NumLifo numbers;
  CharLifo operations;

  initialiserNum(&numbers);
  initialiserChar(&operations);

  for (char* c = expression; c && *c != '\0'; c++)
  {
    if (*c == '(')
    {
      OpenParenthese = 1;
      continue;
    }

    //Detection d'un nombre
    if ((*c >= '0' && *c <= '9') || (*c == '-' && OpenParenthese))
    {
      char* end = NULL;
      double number = strtod(c, &end);
      empilerNum(&numbers, number);
      c = end - 1;
      continue;
    }
    if (*c '+' || *c '-' || *c == '*' || *c == '/')
    {
      empilerChar(&operations, *c);
      continue;
    }

    if (OpenParenthese && *c == ')')
    {
      double nb1 = depilerNum(&numbers);
      double nb2 = depilerNum(&numbers);
      char operation = depilerChar(&operations);

      switch (operation)
      {
    case '*':
      empilerNum(&numbers, nb2 * nb1);
      printf("%f * %f = %f\n", nb2, nb1, nb2 * nb1);
      break;
    case '+':
      empilerNum(&numbers, nb2 + nb1);
      printf("%f + %f = %f\n", nb2, nb1, nb2 + nb1);
      break;
    case '-':
      empilerNum(&numbers, nb2 - nb1);
      printf("%f - %f = %f\n", nb2, nb1, nb2 - nb1);
      break;
    case '/':
      empilerNum(&numbers, nb2 / nb1);
      // Testez la division par 0 !!!
      printf("%f / %f = %f\n", nb2, nb1, nb2 / nb1);
      break;
      }
      OpenParenthese = 0;
    }
  }

  // Solution sale...
  if (OpenParenthese)
  {
    double nb1 = depilerNum(&numbers);
    double nb2 = depilerNum(&numbers);
    char operation = depilerChar(&operations);

    switch (operation)
    {
      case '*':
    empilerNum(&numbers, nb2 * nb1);
    printf("%f * %f = %f\n", nb2, nb1, nb2 * nb1);
    break;
      case '+':
    empilerNum(&numbers, nb2 + nb1);
    printf("%f + %f = %f\n", nb2, nb1, nb2 + nb1);
    break;
      case '-':
    empilerNum(&numbers, nb2 - nb1);
    printf("%f - %f = %f\n", nb2, nb1, nb2 - nb1);
    break;
      case '/':
    empilerNum(&numbers, nb2 / nb1);
    // Testez la division par 0 !!!
    printf("%f / %f = %f\n", nb2, nb1, nb2 / nb1);
    break;
    }
  }
  return depilerNum(&numbers);
}

/*-----
  Interface
  -----*/
void startCalcul(char* expression)
{
  printf("%s = %f\n\n", expression, calcul(expression));
}

/*-----
  Main
  -----*/
int main(void)
{
  char expression[50];

  /* system("cls"); */
  printf("Saisir une expression completement parenthesee :\n");
  scanf("%s", expression);
  startCalcul(expression);

  return 0;
}
0
snakers07 Messages postés 15 Date d'inscription vendredi 14 novembre 2008 Statut Membre Dernière intervention 24 octobre 2009
26 mai 2009 à 17:46
merci beaucoup de ton aide, j'ai modifié ton code et il marche bien, j'ai du rajouter quelques conditions, mais rien de bien méchant.
maintenant j'aimerai te poser une dernière question, à savoir les priorité
c'est à dire si j'effectue le calcul suivant:

(4-1*9)+(9*5)= 44
en bref de gérer la priorité sur la multiplication vis a vis de la soustraction

merci d'avance de ton aide
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
26 mai 2009 à 19:40
Gérer ce type de priorité est bien plus hardu. Il faudrait revoir beaucoup de chose dans ton code pour gérer cela correctement (comme je te l'ai dit, la version que je te propose est sale).
Plutôt que de bidouiller ton code, je te conseil de jeter un coup d'oeil à ce qu'on appelle les AST, ainsi qu'à la grammaire en notation BNF.
Mieux vaut utiliser une méthode propre, maintenable et élégante, plutôt que de t'empêtrer sur une successions de bidouille.
0
Rejoignez-nous