Aide pour calcul de formule

Signaler
Messages postés
15
Date d'inscription
vendredi 14 novembre 2008
Statut
Membre
Dernière intervention
24 octobre 2009
-
Messages postés
3833
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 juin 2021
-
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...
A voir également:

3 réponses

Messages postés
3833
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 juin 2021
122
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;
}
Messages postés
15
Date d'inscription
vendredi 14 novembre 2008
Statut
Membre
Dernière intervention
24 octobre 2009

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
Messages postés
3833
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 juin 2021
122
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.