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 :

Intérpreter un calcul arithmétique


Sujet :

C#

  1. #1
    Membre averti
    Inscrit en
    Octobre 2005
    Messages
    400
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 400
    Points : 444
    Points
    444
    Par défaut Intérpreter un calcul arithmétique
    Bonjour,

    J'ai besoin d'intérpreter une fonction arithmétique que je reçois sous forme de chaine de caractère.

    ex :

    J'ai : "((178/14)*45+(14/2)*(11/4))".
    Il faudrait que je puisse récupérer le résultat de cette chaîne de caractère.

    Y'a t'il un moyen efficace de réaliser le calcul ? De quel façon procéder ?

  2. #2
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Points : 5 195
    Points
    5 195
    Par défaut
    salut

    tu compiles l'expression à la volée par exemple

    Cherches des discussions sur la compilation dynamique ici

    The Monz, Toulouse
    The Monz, Toulouse
    Expertise dans la logistique et le développement pour
    plateforme .Net (Windows, Windows CE, Android)

  3. #3
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    Par défaut
    Par récursivité :
    voilà un exemple tout fait.

  4. #4
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Cela me rapelle une calculatrice polonaise que j'avais fait à l'école.

    Ce que tu doit faire est simple :
    Lecture un à un des caractère, et regroupement des type de caractère dans différentes piles.

    Commençont avec un exemple simple :
    4 + 2 * 3

    Tu lit caractère par caractere et tu met les chiffre dans une pile et les opérateurs dans une autre. Au passage convertis tes chiffres en int.

    Tu obtiens deux pile :

    pile1 pile2
    3 *
    2 +
    4 rien

    Bah la reste plus qu'à dépiler :
    Tu dépile 3 et 2, puis *. Tu testes le caractère et tu détermines que c'est *, alors tu peux faire 3*2.
    Tu empile le résultat dans ta pile 1 et on a :

    pile1 pile2
    6 +
    4 rien

    Tu recommence l'opération jusqu'à ce que ta pile 2 soit vide et tu affiche le résultat finale.

    Après te reste plus qu'à gérer les parenthèses, le plus dure.

    Moi je les empiler avec les chiffres. Puis le les dépiler et n'en faisait pas grand chose, mais lorsque je tomber sur un séquence de dépilement chiffre, opérateur, parenthèse ouvrante, je savais que je devais d'abord calculer la suite avant de faire l'opération.
    Tu peux utiliser la récursivité pour le faire en envoyant une partie des deux piles jusqu'à la parenthèse fermante
    En même temps utilise un compteur que tu incrémente lorsque tu rencontre les parenthèse ouvrante, et décremente lorsque c'est une fermante.
    Cela te permettra de vérifier si le gars s'est tromper sur le nombre de parenthèses
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  5. #5
    Membre averti
    Inscrit en
    Octobre 2005
    Messages
    400
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 400
    Points : 444
    Points
    444
    Par défaut
    Ok, c'est une idée que j'avait en tête, mais que je souhaitais justement éviter.
    Désolé de ne pas l'avoir préciser avant.
    Connaîtriez-vous un autre moyen de procéder ?

  6. #6
    Membre averti
    Inscrit en
    Octobre 2005
    Messages
    400
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 400
    Points : 444
    Points
    444
    Par défaut
    L'idée des piles me semble la plus convaincante pour mon problème... Je vais regarder ça de plus près... Merci

  7. #7
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    La compilation à la volée est la solution de loin la plus simples.

    voici un bout de code qui calcul ce genre d'expression :

    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
     
     public double ComputeMathFormula(string formula)
     {
         double result = double.NaN;
         CodeCompileUnit unit = prepareCompileUnit( formula );
         Assembly dynamicAssembly = compileCode( unit, "CSharp" );
         if (dynamicAssembly != null)
         {
              object formulaComputer = dynamicAssembly.CreateInstance( "DynGen.Compute.formulaComputing", true );
               MethodInfo computeFormula = formulaComputer.GetType().GetMethod( "computeFormula" );
                result = (double)computeFormula.Invoke( formulaComputer, null );
          }    
         return result;
      }
     private Assembly compileCode( CodeCompileUnit compileunit, string language )
     {
         CompilerParameters compilerParameters = new CompilerParameters();
         compilerParameters.ReferencedAssemblies.Add( "System.dll" );
         compilerParameters.GenerateExecutable = false;
         compilerParameters.GenerateInMemory = true;
         compilerParameters.IncludeDebugInformation = false;
         compilerParameters.WarningLevel = 1;
          // compile.
         CodeDomProvider provider = CodeDomProvider.CreateProvider( language );
         CompilerResults compilerResults = provider.CompileAssemblyFromDom( compilerParameters, compileunit );
     
         // Return assembly if compilation OK - otherwise return null
         return (compilerResults.Errors.Count == 0) ? compilerResults.CompiledAssembly : null;
    }
     
     
    private CodeCompileUnit prepareCompileUnit( string formulaString )
    {
         CodeNamespace compute = new CodeNamespace( "DynGen.Compute" );
         compute.Imports.Add( new CodeNamespaceImport( "System" ) );           
         CodeCompileUnit compileUnit = new CodeCompileUnit();
         compileUnit.Namespaces.Add( compute );
         CodeTypeDeclaration formulaComputing = new CodeTypeDeclaration( "formulaComputing" );
         compute.Types.Add( formulaComputing );
         CodeMemberMethod computeFormulaCode = new CodeMemberMethod();
         computeFormulaCode.Attributes = MemberAttributes.Public;
         computeFormulaCode.Name = "computeFormula";
         computeFormulaCode.ReturnType = new CodeTypeReference( typeof( double ) );
         CodeSnippetExpression formula = new CodeSnippetExpression( formulaString );
         CodeMethodReturnStatement computeFormulaReturnStatement = new CodeMethodReturnStatement( formula );
         computeFormulaCode.Statements.Add( computeFormulaReturnStatement );
     
         formulaComputing.Members.Add( computeFormulaCode );
         return compileUnit;
    }
    Ca peut manger aussi quelque chose comme
    (Math.Cos(10.2) * Math.Sin(Math.PI/2))

    Mais il faut préfixer les fonctions par "Math."
    Tu peux éviter cela en parsant la chaine, bien sur.

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  8. #8
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Heu....
    Ton code est loin d'être simple lorsque l'on ne connait pas les classes qu'il utilise (mon cas )

    Autrement ma version avec les piles et loin d'être simple. Je me suis amuser à déterminer la routine à respecter pour la gestion des parenthèses dans la pile et c pas simple.
    Limite il faut splitter avec ( et ) pour simplifier les choses. Et encore...

    Pourtant ma calculatrice polonaise en ADA marchais, j'ai du oublier un truc dans le raisonnement.
    Si je me souviens bien la polonaise marche ainsi :
    2 (3 4) 5 *+/
    Donc pour passer de 2*(3+4)/5 à 2 (3 4) 5 *+/ me parait connecte. Mais après je ne retrouve plus le bon moyen pour gérer les parenthèses !!!
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  9. #9
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    Citation Envoyé par ced600 Voir le message
    Heu....
    Ton code est loin d'être simple lorsque l'on ne connait pas les classes qu'il utilise (mon cas )
    Peut être mais il est capable de "bouffer" n'importe quelle expression de calcul, pourvu qu'elle utilise la syntaxe C# (ou VB, il suffit de changer un paramètre - accessoirement, ça supporte aussi les syntaxes javascript).

    Il lui manque un parser pour reconnaitre les fonctions mathématiques sans avoir à les invoquer dans la classe Math explicitement (tu peux utiliser les méthodes statique de la classe Math, mais il faut écrire Math.Cos par exemple : une amélioration consisterait à chercher les mots pour voir si ils correspondent à une méthode de la classe Math, afin d'avoir une syntaxe plus transparente - moins ".Net" quoi).

    Autrement ma version avec les piles et loin d'être simple.
    Je pense que c'est même nettement plus compliqué que ma solution (qui est la plus simple que j'ai trouvée), mais c'est vrai que la notation polonaise inversée c'est sympa (les premières calculettes HP implémentant cela sont sorties en 73 - de mémoire).

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  10. #10
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Peut être mais il est capable de "bouffer" n'importe quelle expression de calcul, pourvu qu'elle utilise la syntaxe C# (ou VB, il suffit de changer un paramètre - accessoirement, ça supporte aussi les syntaxes javascript).
    Il est vrai qu'avec ma méthode cela serait un peu galère
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 14
    Points : 13
    Points
    13
    Par défaut code
    Bonjour,

    j'ai besoin de mettre en place cela pour mon boulot mais ce n'était pas prévu dans la charge.

    J'ai juste besoin en C# de pouvoir connaitre le résultat d'un string avec des +, -, /, *, (, ) et - unaire style : "-4*(5+6+9)/18"

    Le code fourni est intéressant mais il manque le parsing.

    Il doit bien avoir du code qui a été développé déjà pour cela et qui a été testé par d'autres utilisateurs.

    Si vous pouviez m'orienter.

  12. #12
    Membre éclairé Avatar de ZaaN
    Inscrit en
    Novembre 2005
    Messages
    819
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 819
    Points : 661
    Points
    661
    Par défaut
    tu peux generer un lexer/parser C# (basé sur une grammaire) super vite avec ANTLR par exemple.
    Pour les details, cherche tout seul !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Calcul arithmétique avec un format date
    Par xavdore dans le forum Excel
    Réponses: 6
    Dernier message: 16/08/2013, 11h58
  2. Réponses: 4
    Dernier message: 17/03/2010, 15h54
  3. Calcul arithmétique sous access 2003
    Par KADOMINO dans le forum IHM
    Réponses: 1
    Dernier message: 08/06/2008, 21h50
  4. Problème calcul arithmétique avec des float
    Par tioneb369 dans le forum Langage
    Réponses: 4
    Dernier message: 18/09/2007, 14h35
  5. Petits calculs arithmétiques
    Par mirela dans le forum ASP.NET
    Réponses: 9
    Dernier message: 20/06/2007, 12h34

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