Fonctions Saisie --- Expression mathématique

Tersaken Message lu Posté le 08 Avr 2008 à 23:00 Bulle
Avatar de Tersaken
Membre Confirmé

Messages : 302
GCPoints : 23103
Oulà, a l'origine je voulais tester une fonction du forum et me voilà dans l'impossibilité de supprimer mon propre poste ... Bon bref, je vais en profiter pour vous demandez "une astuce"
J'ai conçu une fonction de saisie qui vous permet de rentrer une expression mathématique ( ne travaille qu'avec des nombres entiers pour le moment ). A titre d'exemple, vous pourrez demander au programme de calculer "2+3*(3+5)+2*2". Celui ci est censé retourner le bon résultat.
J'aimerais convertir cette fonction en dll,
Y a t-il a priori une méthode simple pour arriver a mes fins ... merci d'avance :wink:


Code :
#include <cstdlib>
#include <iostream>
#include <string>
#include <math.h>

using namespace std;

// Prototypes de fonctions.

int value( char c ) ; 
double GetNumber( string  s );
int length( string s );
double Compute( string s );
string Calculer( string s ) ;
string FromIntToString( double ent );
string AddTo( string s, char c, int p );
string Convert( string s );
string AfficherCalculs(string s);
string ClearSpace( string s );

// ... 

int main()
{
    string v ;
    cin >> v ; 
    cout << AfficherCalculs(v) << "n" ;
  
  
  

  
  system("PAUSE");

}


// calcul d'une expression avec gestion des priorités ( parentheses seulement ) 

string AfficherCalculs(string s)
{
       s = ClearSpace(s);
       s = Convert(s);
       return Calculer(s) ; 
}

string Calculer( string s ) 
{
       
       int lg = length(s);
       int i  = 0        ; // le compteur ; 
       bool etat = false ; 
       string s2 = ""    ; // une chaine intermediaire ! :-)
       string s3 = ""    ; // la chaine a renvoyer
       int Compt = 0     ; // compte le nombre de " ( ";
  
       
       while ( i < lg )
       {
                   
        if ( s[i] == '(' && etat == false  ) 
        { 
             etat = true  ; i++ ; Compt = 1 ;
        }
        
    

     // on est dans une parenthese
        if ( etat == true )
        {
                     if ( s[i] == '(' ) { Compt ++ ;}
                     if ( s[i] == ')' ) { Compt -- ;}
                     if ( Compt != 0 )
                     {
                       s2 = s2 + s[i] ; 
                     }
                     else
                     {
                         s3 = s3+Calculer(s2);
                         s2 = "";    
                         etat = false ;
                     }
        }
        else
        {      
            s3 = s3 + s[i] ; 
        }
         i++;
       } 
       
       return FromIntToString( Compute(s3) ) ;
      
}

// Calcul la valeur d'une expression... [ fonctionne parfaitement !! ] 

double Compute( string s )
{
       int i     = 0  ; // pointeur! 
       int somme = 0  ; // contient la somme a renvoyer ; 
       string s_ = "" ; // chaine intermediaire
       int lg = length(s) ; // longueur de s ; 
       
       char OldOp = '+' ; // contient l'operation a effectuer
       
       while ( i < lg )
       {
            while ( s[i] != '+' && s[i] != '-' && s[i] != '*' && s[i] != '/' && i < lg  )
            {
                      s_ = s_+s[i] ;
                      i++;
            }
            switch ( OldOp ){
                 case '+' : somme = somme+GetNumber(s_);break;
                 case '-' : somme = somme-GetNumber(s_);break;
                 case '*' : somme = somme*GetNumber(s_);break;
                 case '/' : somme = somme/GetNumber(s_);break;
      
             }
            OldOp = s[i];
            s_    = "" ; 
            i++;
       
        }
        
        return somme ; 
}

// Extrait un nombre d'une expression.

double GetNumber( string  s )
{
     double a = 0 ;   
     int i    = 0 ;  
     int lg = length(s);  
     while ( value(s[i]) >= 0 && value(s[i]) <= 9 && i < lg )
     {
       a = a*10+value(s[i]) ; i++ ;
     }
     return a ;      
}


// renvoit la valeur du chiffre contenu dans c.
int value( char c )
{
  return int(c)-48 ;
}


// renvoit la longueur i d'une chaine ; 

int length( string s )
{
    int i = 0 ; 
    while ( s[i] != '&#65533;' )
    {
          i++;
    }
    return i ; 
}

// convertie un entier en string !  

string FromIntToString( double ent )
{
    int lg = log(ent)/log(10);
    string s  = ""                   ; // le string de retour ! 
    int e  = 0                    ; // l'entier a traiter !

    for( int x = lg ; x >= 0 ; x-- )
    {
         e =  int(ent/pow(10,x));
         s = s+char( e+48 ) ;
         ent = ent - e*pow(10,x) ; 
     }
     
     return s ;  
      
}

// rajoute a la chaine s le caractere c a la position p 

string AddTo( string s, char c, int p )
{
    int lg = length(s);
    string s2 = ""    ; // chaine de retour.
    for( int x = 0 ; x < lg ; x++ )
    {
         if (x == p){ s2=s2+c ; }
         s2 = s2+s[x] ; 
         
     }
     
     return s2 ; 
       
}

// Adresse le parenthesage d'une expression. 

string Convert( string s )
{
   int lg = length(s) ;
   int i = 0          ; 
   int old = 0        ;
   int nw   = 0       ;
   string s2 = ""     ;
   bool etat = true  ;
   bool para = false ; 
   
   while ( i < lg )
   {
                    if ( s[i] == '(' ) { para = true  ; }
                    if ( s[i] == ')' ) { para = false ; }
                      
                    if ( ( s[i] == '+' ||  s[i] == '-') && para == false   )
                    {
                             if ( etat == false ) 
                              {
                                   etat = true ; 
                              }
                              else
                              {
                              
                                  nw = i ;
                                  etat = false;
                                  s = AddTo(s,')', nw );
                                  s = AddTo(s,'(', old );
                                  old = nw+3;
                                  lg = length(s) ;
                               
                              }
                    }

                          i++;
                      
        }
      // en sortie on ferme la parenthese si besoin est !   
        if ( etat == true)
        {
            s = AddTo(s,'(', old );             
            s = s+')';

        }
        
        return s;
        

}

// on supprime tous les espaces nocifs a la comprehension du calcul.

string ClearSpace( string s )
{
     int lg = length(s);
     string s2 = ""    ; // la chaine de retour
     for( int x = 0 ; x < lg ; x++  )
     {
    
            if (  s[x] != ' '  ) 
             {
                  s2 = s2+s[x];
             } 
     } 
     
     return s2;
}
Dernière édition le 08 Avr 2008 à 23:05
Loack Message lu Posté le 09 Avr 2008 à 12:54 Bulle
Avatar de Loack
Membre Novice

Messages : 62
GCPoints : 24761
Pourquoi tu n'es pas passé par un arbre binaire pour analyser ton expression mathématique ?
Tersaken Message lu Posté le 09 Avr 2008 à 13:42 Bulle
Avatar de Tersaken
Membre Confirmé

Messages : 302
GCPoints : 23103
Parce que je ne connais pas cette méthode :confused: Je n'ai rien repompé ici j'ai fait un systeme tres simple qui gere simplement la priorité des parentheses ... ( fonction recursive )
J'ai ensuite mis au point un programme qui applique les parentheses de façon a ce que l'expression soit comprehensible par la fonction precedente ... Franchement il n'y a rien de compliquer, j'ai du refaire des fonctions qui sont peut etre deja presente dans les librairies dont je me sers ici ( length, conversion d'un entier en chaine et reciproquement ).
Si jamais tu as un tuto sur les arbres, je suis prenneur... On avait tout de même vu les arbres binaires en cours avec le langage "scheme" ( si certains connaissent ) mais en y repensant, ça revient au même qu'un systeme qui applique des "parentheses".

[ edit : @mod, ça serait sympa de mettre au point qui cache le code par defaut, et qui permet, via un simple clique de le rendre visible )
Dernière édition le 09 Avr 2008 à 13:44
Loack Message lu Posté le 09 Avr 2008 à 17:19 Bulle
Avatar de Loack
Membre Novice

Messages : 62
GCPoints : 24761
Hellow,

Voilà le site où ma prof a prit ses cours:
http://depinfo.u-cergy.fr/~bourdon/enseignement/indexL1-MPI-I200.html
Il faut fouiller dans les differentes parties, tu trouvera vers la partie 10 les arbres :)

Tu lis donc le cours sur les arbres binaire, et puis après tu verras comment l'appliquer pour les expressions arithmetiques (avec le lien suivant: http://www.chambily.com/recursivite/chap_VII_3.htm )

Si tu as des questions hésites pas à prendre mon MSN j'pourrai t'aider :)
Tu verras les arbres, une fois qu'on y goute, on s'en passe plu ^_^
Tersaken Message lu Posté le 09 Avr 2008 à 19:09 Bulle
Avatar de Tersaken
Membre Confirmé

Messages : 302
GCPoints : 23103
Merci, trés bon cours, extrement bien ficelé ! :wink: Je vais tenter de refaire ce programme via les arbres "binaires" donc .... :wink:
Darktib Message lu Posté le 09 Avr 2008 à 21:43 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Pas mal comme code...

Et le cours est bien écrit^^

Sinon pour la dll tu peux créer un projet dll (avec MSVCC ou C::B :love: ) et mettre ton code. Compile, puis va regarder le fichier def crée, normalement tu devrait voir le nom de te fonctions. Si tu veux utiliser ce code en C il faut mettre extern C.

Puis quand tu veux utiliser la dll il te faudra mettre les prototypes des fonctions au déébut de ton main, et de linker la lib créée avec la dll.

Normalement ca marche^^
Tersaken Message lu Posté le 08 Juin 2008 à 15:34 Bulle
Avatar de Tersaken
Membre Confirmé

Messages : 302
GCPoints : 23103
Bonjour, je me suis finalement résigné, ( mais quel plaisir ! ) à coder le programme précédent sous forme d'arbre binaire :smile:
Je pense que je suis arrivé à maturité du programme, mais avant toute diffusion ( notamment sous forme de dll ) je souhaiterais ( du moins ça me serait trés utile :grin: ) que certains d'entre vous testent des expressions arithmétiques ( sans inconnu donc :smile: ) tordues via le programme à telecharger ici ( cliquez ici en gros)
[ C'est logiquement un .zip, mais vu que j'heberge le fichier sur ifrance, je l'ai renommé en .zop pour que vous puissiez le télécharger , il suffit donc de renommer l'extension :want: )
Attention, les expressions doivent être correctement écrites ( pensez aux parenthèses ) ... Le programme ne "comprend" pas les espaces de vos expressions ( bien que j'avais mis au point une fonction pour les supprimer mais par je ne sais quel mystère, elle ne veut pas fonctionner ) ...
Si vous rencontrez le moindre bug, exprimez vous ! ( tout en soulignant ce que vous avez tapez pour réussir a obtenir un resultat incorrect ou voir, a ce que le programme plante )
Merci d'avance !

[edit : ah j'oubliais, pour séparer la partie entiere et décimale, il suffit d'utiliser un point ( genre 3.2 ) et non une virgule ( bon ça peut vous paraitre logique mais j'en connais qui se tromperaient ^^' )
Le resultat est un type float, donc ne vous attendez pas une à une grande précision au niveau du nombre de décimales ... voilà :wink:

[edit 2 ; arg j'ai crié victoire trop tot il y a au moins un bug qui persiste 8-/ )
edit 3 ; bon normalement ça devrait fonctionner comme sur des roulettes ( le même lien ! )
Dernière édition le 08 Juin 2008 à 18:00
Darktib Message lu Posté le 08 Juin 2008 à 15:49 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Pour moi ca marche pas mal^^ Par contre j'ai remarqué que les lettres ont aussi une valeur, genre A=17 ou 'exit' = 60000 et des poussieres :absurd:
Je n'ai eu aucun bug et apparement les décimals sont plutot précis.
Tersaken Message lu Posté le 09 Juin 2008 à 13:59 Bulle
Avatar de Tersaken
Membre Confirmé

Messages : 302
GCPoints : 23103
Merci d'avoir tester :wink: Effectivement, chaque lettre à une valeur numérique en ascii, d'où les problèmes rencontrés ^_^
Je ferais un automate qui vérifira si l'expression entrée est correcte !
ça serait sympa que d'autres testent, j'ai tendance a rentrer des chaînes qui se ressemblent un peu, donc c'est un peu dur d'avoir du recul :smile:
Mod Message lu Posté le 09 Juin 2008 à 14:25 Bulle
Avatar de Mod
Webmaster

Messages : 4954
GCPoints : 2100823
Après test, ça fonctionne sans problème si on reste dans les chiffres.

Je serai curieux de savoir comment tu as codé ton analyseur syntaxique, car il donne des résultats assez étranges par moment. Je pense à l'utilisation de lettres. Par exemple, si je met p2, sachant que p <=> 64 , il me répond 642, comme s'il s'agissait d'une concaténation. Assez inattendu ^^.

Ah, et sinon, pas de puissance ? J'aurais bien testé un petit 4^(1/2) :p
Darktib Message lu Posté le 09 Juin 2008 à 18:47 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Pour les lettres et les chiffres, normalement 0~9 <=> ASCII 48~57.
Donc apres il te suffit de vérifier la plage du nombre rentré.

@Mod : ca me parait logique, vu qu'il s'agit du meme comportement avec les chiffres (si tu rentre 32 tu aura bien 32 et non 6)
Tersaken Message lu Posté le 09 Juin 2008 à 19:03 Bulle
Avatar de Tersaken
Membre Confirmé

Messages : 302
GCPoints : 23103
Darktib a raison ( concernant la comportement " étrange " )

Citation :

0~9 <=> ASCII 48~57.


Oui je m'en suis servis pour convertir mes strings en entier, toutes les fonctions ou presque sont codés main ^^'
Pour l'automate, c'est un peu plus compliqué que cela, il faut voir s'il n'y a pas d'opération " illégale " [ du genre (*3) ] ; rien d'infaisable cependant [ en gros je divise a chaque fois l'expression en deux, genre (a*b) devient (a)*(b)
, il suffit de voir quand a ou b n'est pas un nombre et renvoyer une erreur )
Sinon je vais rajouter certaines constantes ( e pour l'exponentiel, Pi etc ) les fonctions usuelles et effectivement, les puissances^^'
Je vais tenter d'y rajouter le calcul de dérivée ( a une variable pour le moment ) voir le calcul d'intégral ( ça va être beaucoup plus dur :absurd: )
J'ai réussi a en faire une dll, mais j'avoue que le comportement est assez étrange ... fin je me pencherai dessus plus tard ... Merci en tout cas
Loack Message lu Posté le 10 Juin 2008 à 01:15 Bulle
Avatar de Loack
Membre Novice

Messages : 62
GCPoints : 24761
Hm, sinon tu pouvais faire ça:

Code :
int number, number2;
std::string s = "123 124";
std::istringstream iss(s);
iss >> number >> number2;


Par exemple si |s| = "123 124" tu auras
|number| = 123
|number2| = 124

(pense à inclure l'entête sstream: #include <sstream>) -- (j'espère pas t'avoir dit de bêtise, j'ai pas testé ce que je viens de te dire.)
J'espère que ça pourra t'aider en tout cas. :)
Répondre
GameCorp - Site d'apprentissage et d'entraide à la création de jeux vidéo.
XHTML Valid 1.1 - Page générée en 0.0425 secondes