IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Optimisation / parser mathématique


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite
    Inscrit en
    Janvier 2005
    Messages
    711
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 711
    Par défaut Optimisation / parser mathématique
    Bien le bonjour,

    je developpe un logiciel auquel j'aurais besoin d'ajouter un parser mathematique. j'ai commencé a bidouiller un peu flex/bison (c'est assez impressionant d'ailleurs !! ) et je devrais arriver a m'en sortir. je me pose une question neanmoins :

    je vais donc parser mn expression, et construire a partir d'elle un arbre qui me permettra ensuite d'evaluer la formule e donnant des valeurs aux variables. pour cela je vais donc creer une classe mere qui sera le type de base de l'arbre, et des classes filles pour chaque "genre" : variable, fonction, operateur binaire, operateur unaire, etc... et c'est la que je m'interroge : vaut il mieux creer UNE classe pour chacun de ses genres, et gerer a l'interieur avec des switch ou des ifs, genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class nodeOperator : derive de node
    .....
     
    fonction eval()
    switch operateur
    case "+" renvoie filsGauche->eval() + filsDroit->eval()
    case "*" renvoie filsGauche->eval() * filsDroit->eval()
    etc..
    ou creer une classe fille pour CHAQUE operateur ou fonction ce qui est un peu plus long mais evite d'avoir des series de tests conditionnels ?

    merci..

    accessoirement, y a t il des choses auquelles il faut faire gaffe et auquelle je risque de ne pas penser ?? si ca peut m'eviter des erreurs au depart :-)

  2. #2
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 532
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 532
    Par défaut
    et c'est la que je m'interroge : vaut il mieux creer UNE classe pour chacun de ses genres, et gerer a l'interieur avec des switch ou des ifs, genre :
    Ben je crois que le mieux c'est de créer une classe paramêtrable c.a.d avec template...
    ( sur codeproject.com je crois qu'il y a un exemple comme cela )
    sinon tu peux prendre les conteneurs de la STL et empiler les genres...
    Non ? Meilleure idée ?

  3. #3
    Membre émérite
    Inscrit en
    Janvier 2005
    Messages
    711
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 711
    Par défaut
    je ne suis pas sur de te suivre. quand je parlais de genre, je ne voulais pas parler de type au sens entier, double.. mais bien d'element dont le role est different (operateur, variable, valeur numerique..), et dont le traitement vont etre different ! je ne vois pas trop comment je pourrais me depatouiller avec des templates... si tu povais m'en dire un peu plus ! merci :-)

  4. #4
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    Tu as regardé du côté de boost::spirit ?

    Et si tu voulais tout coder toi-même, comme en général une expression est un type récursif, et en même temps une somme disjointe de plusieurs types, soit tu peux essayer boost::variant, qui permet d'en faire.

    La méthode polymorphisme avec héritage, j'aime pas trop, il faut que tu utilises des visiteurs pour pouvoir ajouter simplement des fonctions, sinon tu serais obligé de modifier le code de chaque classe, ce qui est assez lourd.

    Ca revient au même que boost::variant, mais plus long.

  5. #5
    Membre émérite
    Inscrit en
    Janvier 2005
    Messages
    711
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 711
    Par défaut
    si je ne m'abuse, boost::spirit est un analyseur lexical/syntaxique, et comme je le disais je n'ai (pour l'instant ) pas trop de probleme de ce coté la, en utilisant bison et flex..

    pour ce qui est du polymorphisme, je suis bien obligé dans la mesure ou chaque "genre" de noeud va necessiter un traitement different, donc un boost::variant ne suffira pas.. enfin je crois

    il faut bien comprendre que l'expression mathématique n'est pas evaluée au moment du parsing (c'est comme ca qu'on dit ?) mais doit etre stockée (a priori sous forme d'arbre)...

  6. #6
    Inactif  
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    743
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Par défaut
    Citation Envoyé par jobherzt
    je ne suis pas sur de te suivre. quand je parlais de genre, je ne voulais pas parler de type au sens entier, double.. mais bien d'element dont le role est different (operateur, variable, valeur numerique..), et dont le traitement vont etre different ! je ne vois pas trop comment je pourrais me depatouiller avec des templates... si tu povais m'en dire un peu plus ! merci :-)
    Je crois qu'à ta place j'utiliserais des fonctions virtuelles. Ca t'éviterais de faire des switchs, qu'il te faudrait remettre à jour à chaque nouvelle classe.
    Ex:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    class expr
    {
      ...
      virtual expr *eval() =0;
      virtual expr *plus() =0;
    };
     
    typedef auto_pointer<expr> Expr;
     
    template<class T>
    class value : public expr
    {
      T val;
      ...
      virtual expr *operator() { return new value(val); }
      virtual expr *plus(expr *b) { return new value(val+b->val); }
    };
     
    class binop: public expr
    {
      Expr a,b;
      ...
    };
     
    class plusop : public binop
    {
      virtual expr *eval() { return a->eval()->plus(b->eval()); }
    };

  7. #7
    Membre émérite
    Inscrit en
    Janvier 2005
    Messages
    711
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 711
    Par défaut
    Citation Envoyé par Charlemagne
    Ca t'éviterais de faire des switchs, qu'il te faudrait remettre à jour à chaque nouvelle classe.
    pourquoi est ce que je devrais remettre a jour mes switch a chaque nouvelle classe ? l'ajout d'une classe n'a pas de raison d'avoir d'effet sur les autres.... je te montre le debut de ce que j'ai fait (c'est encore une sorte de "brouillon" avant d'attaquer vraiment). je n'ai pas besoin de template a priori, mes constantes numeriques seront toujours du meme type "REEL". ma question serait plutot de savoir si dans le cas ou j'aurais vraiment beaucoup (mais genre vraiment :-) ) a evaluer mon expression avec different parametetre, le fait d'avoir a effectuer un switch a chaque fois que j'ai une operation "coute" plus en temps de calcul que d'avoir une classe "dédié" pour chaque operateur ou fonction ! (je ne suis pas clair, hein )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
     
    #include "pave.h"
     
    class node
    {
    	protected:
    		interval value;
     
    	public:
     
    		node()
    		{
    		}
    		virtual interval eval(const pave& parameters,const REEL& variable) {}
    		//virtual void contract(pave& parameters, const REEL& variable ) const =0;
    };
     
    class nodeBinaryOp : public node
    {
    	protected:
    		char op;
    		node * nR;
    		node * nL;
    	public:
    		nodeBinaryOp(char _op, node * _nL, node * _nR)
    		{
    			op=_op;
    			nL=_nL;
    			nR=_nR;
    		}
     
    		interval eval(const pave& parameters,const REEL& variable)
    		{
    			switch(op)
    			{
    				case '+' : value = nL->eval(parameters, variable) + nR->eval(parameters, variable); break;
    				case '*' : value = nL->eval(parameters, variable) * nR->eval(parameters, variable);break;
    				case '-' : value = nL->eval(parameters, variable) - nR->eval(parameters, variable);break;
    				case '/' : value = nL->eval(parameters, variable) / nR->eval(parameters, variable);break;
    			}
     
    			return value;
    		}
    };
     
    class nodeConstant : public node
    {
    	public:
    	nodeConstant(interval _val)
    	{
    		value=_val;
    	}
    	interval eval(const pave& parameters,const REEL& variable)
    	{
    		return value;
    	}
    };

  8. #8
    Inactif  
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    743
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Par défaut
    A priori tu veux faire une "calculatrice".
    Si c'est le cas, ça simplifie la programmation par rapport à concevoir un "Mathématica".
    Et tu n'auras probablement qu'un seul switch pour ta fonction d'évaluation. Mais si tu comptes rajouter plus de fonctionnalités, t'auras toujours plus de switchs, qu'il te faudra remettre à jour à chaque nouvelle classe (nombres complexes, variables, fonctions scientifiques, ...).

    Je conseillerais plutôt de faire des classes dédiées, plutôt que de regrouper les 4 opérations binaires.
    Mais regroupe les dans une classe de base commune, pour factoriser le code.

    Et puis, je m'arrangerais pour que la fonction d'évaluation ne reçoive aucun paramètre (je vois pas bien à quoi correspond ton "pave").
    Mais une classe "variable" pourrait très bien retrouver la valeur associée à partir d'un nom.
    par exemple du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class variable : public expr
    {
      static map<string,expr*> vars;
     
      map<string,expr*>::iterator it;
      variable (const string &s) : expr() { it=vars.insert(s).first; }
      virtual expr *eval() { return *it; }
    };

  9. #9
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    boost::variant peut aussi très bien convenir.

    Regarde comment c'est fait ici :

    http://www.boost.org/doc/html/varian...ursive-wrapper

    Tu n'es pas obligé d'utiliser la même conception présentée. Moi personnellement à la place de mettre binary_op sous forme de classe template, je rajouterais un autre paramètre à son constructeur de type boost::function<float (float, float)> par exemple qui me permettrait de construire des nouvelles fonctions dynamiquement, de manière simple, au lieu de rajouter à chaque fois des nouveaux types dans la définition.

Discussions similaires

  1. Parser une formule mathématique
    Par rambc dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 23/11/2010, 19h53
  2. Composant Parser mathématique
    Par rvzip64 dans le forum Composants VCL
    Réponses: 5
    Dernier message: 07/07/2010, 23h23
  3. Bibliothèque d'optimisation mathématique
    Par shams dans le forum Bibliothèques
    Réponses: 2
    Dernier message: 27/11/2009, 10h50
  4. Parser Mathématique C# ?
    Par tamiii dans le forum Général Dotnet
    Réponses: 1
    Dernier message: 23/09/2008, 16h39
  5. Parser Java pour fonction mathématiques.
    Par abdelhamidem dans le forum API standards et tierces
    Réponses: 2
    Dernier message: 20/05/2008, 00h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo