Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Exercices] Venez vous entraîner !

Ce mois: Parseur de fonctions mathématiques

17 août 2009 à 13:56:41

Citation : Carma001

Non, ici le but est de créer son propre parseur, sans se servir d'outils externes.


J'imagine que l'on peut quant-même se servir d'une lib graphique... Non ?
(Je pense, bien-sûr, à Qt... :p )
  • Partager sur Facebook
  • Partager sur Twitter
Cuicui.
17 août 2009 à 14:00:49

Je ne vois pas ce qu'une lib graphique pourrait bien apporter. Tu vas avoir déjà bien assez à faire avec le parseur avant de chercher à tracer des courbes.
  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
17 août 2009 à 14:03:56

Je ne veux pas tracer des courbes, mais simplement permettre à l'utilisateur de taper son expression mathématique dans une fenêtre plus stylisée qu'une... console ! Avec "coloration syntaxique" (si j'ose dire) et tout et tout... :p
  • Partager sur Facebook
  • Partager sur Twitter
Cuicui.
Anonyme
17 août 2009 à 14:12:19

Citation : Cuicui73

Je ne veux pas tracer des courbes, mais simplement permettre à l'utilisateur de taper son expression mathématique dans une fenêtre plus stylisée qu'une... console ! Avec "coloration syntaxique" (si j'ose dire) et tout et tout... :p



Et comment fait tu si tu veux la charger depuis un fichier ?
C-o et recherche du dit-fichier ? Horrible ><
  • Partager sur Facebook
  • Partager sur Twitter
17 août 2009 à 14:22:50

Et où est-il spécifié qu'il faut pouvoir obtenir l'expression math depuis un fichier ?...
Fais comme tu veux, si tu préfères utiliser la console, libre à toi...

Je rappel pour info que je demandais (à la base) si l'utilisation d'une lib graphique est autorisée ou non... Je ne me souvient en aucun cas avoir demandé si ça vous paraissait être une bonne idée !
  • Partager sur Facebook
  • Partager sur Twitter
Cuicui.
Anonyme
17 août 2009 à 15:09:34

Dans ce genre d'exo, le but est de concentrer sur l'exo et pas sur les "fioritures" que est la présentation. Ce qui est demander c'est de concevoir une "procédure" qui parse.
Perds pas ton temps sur l'image.
  • Partager sur Facebook
  • Partager sur Twitter
17 août 2009 à 15:52:48

Comme l'a dit Hiura, l'intérêt de l'exercice est bien sûr la partie algorithmique. Maintenant, si tu veux en plus le présenter dans une fenêtre, et pourquoi pas tracer la courbe dans un repère : libre à toi. Cependant, je te demanderais de t'arranger pour séparer la partie Algo de la partie graphique (en clair, n'utilise pas Qt, sous n'importe laquelle de ses formes, pour la partie Algo.)

Bonne chance. ;)
  • Partager sur Facebook
  • Partager sur Twitter
20 août 2009 à 11:58:08

Les choses ayant évoluées depuis quelques temps, je propose une réévaluation bi-annuelle de la proposition suivante! :)

Citation : Nanoc

Citation : iNaKoll

Je faisais simplement la remarque que le cadre de ces exercices (ce sujet) n'incite pas forcément les gens à déposer des commentaires sur des exercices passés. Le mieux ça serait d'avoir les exercices dans un Big-Tuto pour profiter du système de commentaires des chapitres... :)



C'est ce que j'avais pensé faire au début. Cela avait été refusé. Et le forum a aussi l'avantage d'être plus visible.



On pourrait garder ce sujet visible sur le forum et proposer un big-tutos avec les exercices les moins récents dans chaque chapitre (ils y seraient plus visibles).

Je me permet aussi de faire le parallèle avec une suggestion faite il y a deux mois :
http://www.siteduzero.com/forum-83-395 [...] -sources.html

Dutonia et NoHaR y ont fait quelques interventions intéressantes au long des 4 pages de discussion. Cam quand à lui, s'est montré favorable à la proposition..

Voir les propositions faites dans ce sujet, principalement :
- doxygen
- système de vote
- integration avec les tutos...

On pourrait imaginer profiter de cet éventuel module pour présenter l'ensemble des corrections.
  • Partager sur Facebook
  • Partager sur Twitter
Inkamath on GitHub - Interpréteur d'expressions mathématiques. Reprise du développement en cours.
20 août 2009 à 13:57:47

Intégration avec les tutos ... il faudrait déjà corriger certains tutos... (typiquement les formes canoniques des opérateurs)

Sinon, il pourrait en effet être intéressant de mettre un sujet par exo. Mais le format "commentaire" des tutos est assez mauvais. Il ne nous permet pas d'intervenir de façon réactive (notifications) ou de répondre correctement ([quote]).

PS: Au début, je croyais que vous parliez de permettre de déposer et accéder aux participations. Chose que je ne pense pas qu'elle soit bonne.

PPS: vous parlez de doxygen, il faut aller plus loin -> test unitaires. Pour un site orienté débutant, il serait bon de leur montrer cet aspect trop souvent négligé.

PPPS: il vaudrait mieux discuter de tout cela dans un autre topic pour laisser celui-ci dédié aux exos pour l'instant encore.
  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
26 août 2009 à 23:53:39

En effet, ca serait pas mal de pouvoir avoir les exos Qt dans des pages spéciales pour chaque code, d'où le croisement avec ma proposition.
  • Partager sur Facebook
  • Partager sur Twitter
11 septembre 2009 à 19:18:53

dites je voudrais bien voire un code une foi fini d'un des programmes réussissant à l'exercice, car je n'ai aucune idée de comment faire, et a mon avis un niveau un peu faible, trop peu d'entrainement en algorithmique pour arriver à quelquechose de satisfaisant.

c'est pourquoi je voudrais avoir un code qui marche pour pouvoir l'étudier, voir comment se fait la résolution de l'expression.

A+
  • Partager sur Facebook
  • Partager sur Twitter
23 octobre 2009 à 19:29:04

Citation : hilnius

dites je voudrais bien voire un code une foi fini d'un des programmes réussissant à l'exercice, car je n'ai aucune idée de comment faire, et a mon avis un niveau un peu faible, trop peu d'entrainement en algorithmique pour arriver à quelquechose de satisfaisant.

c'est pourquoi je voudrais avoir un code qui marche pour pouvoir l'étudier, voir comment se fait la résolution de l'expression.

A+

+1.
  • Partager sur Facebook
  • Partager sur Twitter
26 octobre 2009 à 18:28:27

C'est vrai, il est où le topic pour voir les réponses des autres ?

Question subsidiaire :

2e+5 c'est deux fois la constante e plus l'entier 5, ou bien c'est 200000 ?
  • Partager sur Facebook
  • Partager sur Twitter
26 octobre 2009 à 20:09:23

Il n'y a pas de topic pour voir les réponses des autres.
Pour ta question, je dirais 2 fois e + 5.
  • Partager sur Facebook
  • Partager sur Twitter
27 octobre 2009 à 14:36:02

Ca dépend de ta syntaxe. Si pour toi une constante (pi, e, i) est simplement écrit normalement alors je ne pense pas que tu puisse faire en sorte que e équivaut à *10^n.
Pour regler ce problème, si tu veux vraiment mettre cette notation alors tu peux mettre les constantes de la forme : _nom ou nom() ou autre.

Je rédige ce message sans avoir pris connaissance du sujet de l'exo donc c'est possible que se soit un peu faux. Cependant il me semble que la syntaxe peut être choisi.
  • Partager sur Facebook
  • Partager sur Twitter
27 octobre 2009 à 17:41:56

C'est donc un petit bug dans l'énoncé ;)
  • Partager sur Facebook
  • Partager sur Twitter
27 octobre 2009 à 18:00:30

On a qu'à faire comme sur les calculatrices. C'est à dire que tout caractère ou chaine de caractère est considéré comme une constante, sauf si une parenthèse ouvrante est présente à la suite. ;)
  • Partager sur Facebook
  • Partager sur Twitter
19 novembre 2009 à 19:42:00

merci pour tous c est exercices ... :) !!
  • Partager sur Facebook
  • Partager sur Twitter
29 novembre 2009 à 17:10:15

Juste une petite question a propos de l'exercice compression RLE(oui je sais c'est loin) , ce serait pas plus simple d'ouvrir le fichier en binaire et en suite compresser ?
  • Partager sur Facebook
  • Partager sur Twitter
31 décembre 2009 à 4:16:12

@Lithrein : J'espère pas dire de connerie, mais justement le but est de le faire comme demandé dans l'exo, parce que si tu le fais en mode binaire, ça simplifie beaucoup plus l'exo (deux etats à gérer, 0 ou 1).

Sinon je suis en train de faire l'exo sur le Chiffre de Vigenère, mais je vois mal comment inclure la table de vigenère dans mon programme oO
  • Partager sur Facebook
  • Partager sur Twitter
31 décembre 2009 à 14:48:00

<citation rid="4513060">@Lithrein : J'espère pas dire de connerie, mais justement le but est de le faire comme demandé dans l'exo, parce que si tu le fais en mode binaire, ça simplifie beaucoup plus l'exo (deux etats à gérer, 0 ou 1)./citation>
N'y a-t-il pas plus de probabilités de voir apparaître des suites de 1 ou de 0 dans un fichier que des suites de lettres ?
  • Partager sur Facebook
  • Partager sur Twitter
31 décembre 2009 à 15:34:18

@Dr. Tenma : Ouvrir le fichier en binaire et le compresser donnerait un meilleur taux de compression du fichier, les suites de 0 ou de 1 serait bien plus frequente que une suite lettres
  • Partager sur Facebook
  • Partager sur Twitter
31 décembre 2009 à 18:20:09

Oui oui j'ai jamais dis qu'une compression binaire serait moins éfficace.
  • Partager sur Facebook
  • Partager sur Twitter
1 janvier 2010 à 18:05:47

Citation : hilnius

dites je voudrais bien voire un code une foi fini d'un des programmes réussissant à l'exercice, car je n'ai aucune idée de comment faire, et a mon avis un niveau un peu faible, trop peu d'entrainement en algorithmique pour arriver à quelquechose de satisfaisant.

c'est pourquoi je voudrais avoir un code qui marche pour pouvoir l'étudier, voir comment se fait la résolution de l'expression.



Voici un petit embryon de solution rapidement écrit à l'huile de coude comme c'est demandé :

#include <iostream>
#include <string>
#include <cctype>
#include <exception>

#include <boost/variant.hpp>
#include <boost/pool/object_pool.hpp>

namespace parser
{
    struct Lex_unit
    {
        enum Type
        { constant, op_low, op_high, x, opth, cpth, undef
        } type;

        boost::variant < char, double > attribut; // constant or operator

        Lex_unit(char op)
        {
            if(op == '+' || op == '-')
                type = op_low;
            else if(op == '*' || op == '/')
                type = op_high;
            else throw std::string("unexpected operator");
            attribut = op;
        }

        Lex_unit(double cst) : attribut(cst)
        { type = constant; }

        Lex_unit(Type t)
        {
            if(t != x && t != opth && t != cpth)
                throw std::string("unexpected token type");
            type = t;
        }

        Lex_unit() : type(undef) {}
    }; // struct Lex_unit

    struct Lexer
    {
        typedef std::string::const_iterator Iterator;
        Iterator begin, end;

        Lexer(Iterator b, Iterator e)
            : begin(b), end(e) {}

        bool match(char c)
        {
            if(*begin != c)
                return false;
            ++begin;
            return true;
        }

        Lex_unit next_unit()
        {
            while(begin != end && std::isspace(*begin))
                ++begin;

            if(begin == end)
                return Lex_unit();

            if(std::isdigit(*begin))
            {
                double accumulator = 0;
                do accumulator = 10 * accumulator + (*begin - '0');
                    while(++begin != end && std::isdigit(*begin));
                if(begin != end && *begin == '.')
                {
                    double dec = 10;
                    for(; ++begin != end && std::isdigit(*begin); dec *= 10)
                        accumulator += (*begin - '0') / dec;
                }
                return Lex_unit(accumulator);
            }

            char ret = *begin;
            if(match('+') || match('-') || match('*') || match('/'))
                return Lex_unit(ret);
            if(match('('))
                return Lex_unit(Lex_unit::opth);
            if(match(')'))
                return Lex_unit(Lex_unit::cpth);
            if(match('x'))
                return Lex_unit(Lex_unit::x);

            throw std::string("lexer : unexpected character");
        }
    }; // struct Lexer

    namespace ast
    {
        namespace x_value
        { double val; }

        struct Expr
        {
            virtual ~Expr() {}
            virtual double eval()
            { throw std::string("undefined ast node"); }
        };

        struct Binary_op : public Expr
        {
            char oprt;
            Expr* opr1, *opr2;
            Binary_op(char op, Expr* op1, Expr* op2)
                : oprt(op), opr1(op1), opr2(op2) {}

            double eval()
            {
                double r1 = opr1 -> eval();
                double r2 = opr2 -> eval();
                switch(oprt)
                {
                    case '+' : return r1 + r2;
                    case '-' : return r1 - r2;
                    case '*' : return r1 * r2;
                    case '/' : return r1 / r2;
                }
                throw std::string("ast eval : unexpected operator");
            }
        };

        struct Constant : public Expr
        {
            double value;
            Constant(double val) : value(val) {}

            double eval()
            { return value; }
        };

        struct X : public Expr
        {
            double eval()
            { return x_value::val; }
        };

        namespace pool
        {
            boost::object_pool < Binary_op > op_pool;
            boost::object_pool < Constant > const_pool;
            boost::object_pool < X > x_pool;
        }
    } // namespace ast

    struct Parser
    {
        typedef Lexer::Iterator Iterator;
        Lexer lexer;
        Lex_unit unit;

        Parser(Iterator begin, Iterator end)
            : lexer(begin, end) {}

        void next_unit()
        { unit = lexer.next_unit(); }

        char ret_op()
        {
            char ret = boost::get < char >(unit.attribut);
            next_unit();
            return ret;
        }

        double ret_const()
        {
            double ret = boost::get < double >(unit.attribut);
            next_unit();
            return ret;
        }

        ast::Expr* fact()
        {
            using namespace ast;
            if(unit.type == Lex_unit::constant)
                return new (pool::const_pool.malloc()) Constant(ret_const());
            if(unit.type == Lex_unit::opth)
            {
                next_unit();
                Expr* e = expr();
                if(unit.type != Lex_unit::cpth)
                    throw std::string("missing closing parenthesis");
                next_unit();
                return e;
            }
            if(unit.type == Lex_unit::x)
            {
                next_unit();
                return new (pool::x_pool.malloc()) X;
            }
            throw std::string("parser : unexpected factor form");
        }

        ast::Expr* term()
        {
            using namespace ast;
            Expr* t = fact();
            while(unit.type == Lex_unit::op_high)
            {
                char ret = ret_op();
                t = new (pool::op_pool.malloc()) Binary_op(ret, t, fact());
            }
            return t;
        }

        ast::Expr* expr()
        {
            using namespace ast;
            Expr* t = term();
            while(unit.type == Lex_unit::op_low)
            {
                char ret = ret_op();
                t = new (pool::op_pool.malloc()) Binary_op(ret, t, term());
            }
            return t;
        }

        ast::Expr* parse()
        {
            next_unit();
            ast::Expr* ast = expr();
            if(lexer.begin != lexer.end)
                throw std::string("incomplete parsing");
            return ast;
        }
    }; // struct Parser
} // namespace parser

double eval(const std::string& expr, double x)
{
    using namespace parser;
    Parser pars(expr.begin(), expr.end());
    ast::Expr* ast = pars.parse();
    ast::x_value::val = x;
    return ast -> eval();
}

int main()
{
    try
    { std::cout << eval("4.2*x+(x-(1.00))", 4); } // 19.8
    catch(const std::exception& e)
    { std::cerr << e.what(); }
    catch(const std::string& s)
    { std::cerr << s; }
    return 0;
}


Tout est écrit à la main, l'analyseur lexicale, l'analyseur syntaxique, l'arbre syntaxique abstrait, etc. Comme demandé. Ce code ne répond pas totalement à l'exercice : je ne gère pas les crochets, l'opérateur puissance, les fonctions citées (sqrt, etc.), les constantes e et pi, etc. Ce n'est qu'un squelette de base loin d'être parfait (gérant les parenthèses, quelques erreurs, + - * /, et qui répond à l'exercice avec l'inconnu x et la fonction eval) pour te donner une idée. ;)
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 18:24:14

T'as bencher boost.pool vs un truc fait à la main ou vs l'allocateur de la stl? Parce que boost.pool est plus ou moins controversé (et plus maintenu me semble).
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 18:49:30

Bah je ne voulais tout de même pas avoir à gérer la mémoire moi-même, déjà que tout le reste est écrit à la main (ce que je fais assez rarement en fait) :p, donc j'ai choisi entre l'allocateur de la STL, un truc à base de boost::shared_ptr ou Boost.Pool. Après, que cette bibliothèque soit controversée, je n'étais pas courant ; tu as un article ou quelque chose du genre à ce propos ?
  • Partager sur Facebook
  • Partager sur Twitter
3 janvier 2010 à 18:56:51

C'était sur la ML qu'ils en avaient discuté récemment mais j'ai plus de lien désolé, faudrait que je regarde les archives. Si je trouves ça jte fais signe. Mais après jvois pas pourquoi t'as pas tester avec l'alloc de la STL, ok il est pas super perf sur des objets légers mais t'es pas non plus sur du code critique :p. (je dis ça pour la clarté du code, étant donné le forum).
  • Partager sur Facebook
  • Partager sur Twitter
9 janvier 2010 à 11:25:17

Voilà je suis en train d'essayer de comprendre le code Chlab_lak sur le cryptage de Caesar mais je bloque à un endroit, sur une fonction que je ne comprends toujours pas :

private:

    /* Predicat for count_if() */
    struct NoCaseMatch
    : std::binary_function<char, char, bool>
    {
        bool operator()(char CS, char C) const
        {
            return std::toupper(CS) == C;
        }
    };

public:

    /* Resolve (frequency analysis with C) */
    std::string Resolve(char C) const
    {
        /* Get F */
        /* This is not the best method because
           if two letter have the same frequency
           the second letter is unused, but that
           isn't a problem */
        std::pair<char, size_t> F; // Most frequency letter
        const std::string Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for (size_t i = 0; i < Table.size(); ++i)
        {
            const char C = Table[i];
            size_t R = std::count_if(myString.begin(), myString.end(),
                std::bind2nd(NoCaseMatch(), C));

            if (R > F.second)
                F = std::make_pair(C, R);
        }

        /* Build resolved string */
        return Apply(C - F.first);
    }


Je vois pas ce que fait bind2nd (j'ai regardé sur les liens donnés mais j'ai pas réussi à comprendre éxactement). Aussi, pourquoi utilise-t-on une structure "compliquée" alors qu'on pourrait le faire avec une fonction ?

Merci.
  • Partager sur Facebook
  • Partager sur Twitter
9 janvier 2010 à 20:47:19

Bonjour,
Je suis en train de faire tous les exercices, mais ...
En attaquant BigInt, je me suis dit que ce serait pour après (et le reste du racontage de ma vie aussi :lol: )
Mais, me voilà donc attaquant RLE, et ... Il y a une meilleure compression possible, sauf dans les cas où il y a beaucoup de chiffres ('1', '2', '3', ... ) :
  • Réduire AAAA en 4A
  • Si il n'y a qu'un caractère : A
    • Si c'est une lettre, on la met
    • Si c'est un chiffre, on met 1 suivi du chiffre

Déroulement :
AAAAAUEEE9882
AAAAA => 5A
U     => U
EEE   => 3E
9     => 19
88    => 28
2     => 12
5AU3E192812

On voit que donc lorsqu'il y a beaucoup de chiffres seuls, on a une compression moins bonne. Cependant, leur probabilité d'apparition (dans une image ?) est très faible !
Je trouve donc qu'un système sans flag est plus simple, et plus efficace (dans l'exemple j'obtiens 17 au lieu de 21 caractères (de tête :) )

Et, ensuite, pour l'opérateur virgule.
Pourquoi ne pas permettre une initialisation complète ? Je viens d'inventer le mot, donc un bout de code :
Tableau<char> t;
t = '1','a','2','b','3','z','2';
cout << t; // Affiche 1,a,2,b,3,z,2

Je trouve çà plus simple pour l'utilisateur, même si c'est pareil pour le développeur. Mais, du coup, le niveau 2 n'existe plus ...
Avec un code bien aéré (formatage ANSI via Code::Blocks), j'ai précisément 60 lignes, en comptant le main, et 52 sans le compter ...
C'est plus court et plus simple d'utilisation que le code de l'exemple (je trouve :D )

Je reviens bientôt pour mes "critiques" sur les autres exercices :lol:

EDIT :
Me revoilà, et j'ai trouvé un autre problème (cette fois-ce de moi :'( ) ...
Mon compilateur BF, sur le programme de Nanoc, affiche 0 puis se met à mouliner sans rien afficher pendant plusieurs secondes (je n'ai pas testé plus longtemps, je devrais ?)
C'est normal ou c'est un problème de moi ?
En faisant un micro-log, j'ai vu que çà montait jusqu'à des index énormes, à une vitesse de plusieurs par tours ... Etrange ...

RE-EDIT :
Après avoir regardé la solution, le problème semble venir du fait que le programme affiche 0 au début, ce que est impossible avec Fibonacci ... Or le Hello World marche sans arrêt ... ?
  • Partager sur Facebook
  • Partager sur Twitter
10 janvier 2010 à 15:48:11

J'ai eu le même problème que toi pour le programme BF Lenoa...mais j'ai fini par regarder la solution sans avoir trouvé ce qui clochait :/
  • Partager sur Facebook
  • Partager sur Twitter