Re[4]: Частые вычисления по неопределенной формуле!!!
От: WolfHound  
Дата: 26.04.04 11:17
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Не думаю что будет быстрее. (автору темы важна скорость)

Как я и предсказывал
calc1_parse
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
average all    = 2.3817
average middle = 2.38266

calc2_parse
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
average all    = 2.39925
average middle = 2.4002

calc3_parse
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
average all    = 2.32715
average middle = 2.34962

calc1_calculate
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
average all    = 0.307994
average middle = 0.307279

calc2_calculate
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
average all    = 0.285568
average middle = 0.285243

calc3_calculate
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
average all    = 0.2943
average middle = 0.294283

#pragma once
#define CALCULATOR3_CALL_CONVERSION __fastcall
struct calculator3
{
    calculator3()
        :grammar(*this)
    {}
    double& variable(std::string const& name);
    bool parse(std::string const& str);
    double calculate()
    {
        if(tokens.empty())
            return 0;
        double* s=&stack[0];
        for(std::vector<token>::iterator i=tokens.begin(), e=tokens.end();i!=e;++i)
            i->operation_fn(s, *i);
        return s[0];
    }
private:
    struct token;
    typedef void(CALCULATOR3_CALL_CONVERSION *operation_fn_t)(double*&, token const&);
    struct token
    {
        token(operation_fn_t _operation_fn)
            :operation_fn(_operation_fn)
        {}
        token(operation_fn_t _operation_fn, double _value)
            :operation_fn(_operation_fn)
            ,value(_value)
        {}
        token(operation_fn_t _operation_fn, double* _variable)
            :operation_fn(_operation_fn)
            ,variable(_variable)
        {}
        operation_fn_t operation_fn;
        union
        {
            double value;
            double* variable;
        };
    };
private:
    std::vector<token> tokens;
    std::vector<double> stack;
    spirit::symbols<double*> variables_p;
    std::map<std::string, double> variables;
private:
    size_t stack_deep;
    size_t stack_max_deep;

    void inc_stack()
    {
        if(++stack_deep>stack_max_deep)
            stack_max_deep=stack_deep;
    }
    void dec_stack()
    {
        --stack_deep;
    }
private:
    void add_binary_op(operation_fn_t op)
    {
        dec_stack();
        tokens.push_back(op);
    }
    void add_unary_op(operation_fn_t op)
    {
        tokens.push_back(op);
    }
    void add_variable(operation_fn_t _operation_fn, double* var)
    {
        inc_stack();
        tokens.push_back(token(_operation_fn, var));
    }
    void add_const(operation_fn_t _operation_fn, double val)
    {
        inc_stack();
        tokens.push_back(token(_operation_fn, val));
    }
private:
    static void CALCULATOR3_CALL_CONVERSION token_variable    (double*& s, token const& t){*++s=*t.variable;}
    static void CALCULATOR3_CALL_CONVERSION token_const        (double*& s, token const& t){*++s=t.value;}

    static void CALCULATOR3_CALL_CONVERSION token_op_add    (double*& s, token const& t){s[-1]=s[-1]+s[0];--s;}
    static void CALCULATOR3_CALL_CONVERSION token_op_sub    (double*& s, token const& t){s[-1]=s[-1]-s[0];--s;}
    static void CALCULATOR3_CALL_CONVERSION token_op_mul    (double*& s, token const& t){s[-1]=s[-1]*s[0];--s;}
    static void CALCULATOR3_CALL_CONVERSION token_op_div    (double*& s, token const& t){s[-1]=s[-1]/s[0];--s;}

    static void CALCULATOR3_CALL_CONVERSION token_op_neg    (double*& s, token const& t){s[0]=-s[0];}

    static void CALCULATOR3_CALL_CONVERSION token_fn_sin    (double*& s, token const& t){s[0]=sin(s[0]);}
    static void CALCULATOR3_CALL_CONVERSION token_fn_cos    (double*& s, token const& t){s[0]=cos(s[0]);}
private:
    struct calculator_grammar
        :spirit::grammar<calculator_grammar>
    {
        typedef calculator3 self_t;
        self_t& owner;
        calculator_grammar(self_t& _owner)
            :owner(_owner)
        {}
        template <typename ScannerT>
        struct definition
        {
            definition(calculator_grammar const& self_);

            spirit::rule<ScannerT> expression, term, factor;

            spirit::rule<ScannerT> const&
            start() const { return expression; }
        };
    };
    calculator_grammar grammar;
};
//cpp
#include "stdafx.h"
#include "calculator3.h"

double& calculator3::variable(std::string const& name)
{
    double& ref=variables[name];
    if(double** ptr=find(variables_p, name.c_str()))
        *ptr=&ref;
    else
        add(variables_p, name.c_str(), &ref);
    return ref;
}

bool calculator3::parse(std::string const& str)
{
    tokens.clear();
    stack_deep=0;
    stack_max_deep=0;
    if    (    !spirit::parse(str.c_str(), grammar, spirit::space_p).full
        ||    stack_deep!=1
        )
    {
        tokens.clear();
        return false;
    }
    stack.resize(stack_max_deep+2);
    return true;
}

template <typename ScannerT>
calculator3::calculator_grammar::definition<ScannerT>::definition(calculator_grammar const& self_)
{
    using namespace spirit;
    self_t& self=self_.owner;
    expression
        =   term
            >> *(   ('+' >> term)[lm::bind(&self_t::add_binary_op, &self, &self_t::token_op_add)]
                |   ('-' >> term)[lm::bind(&self_t::add_binary_op, &self, &self_t::token_op_sub)]
                )
        ;

    term
        =   factor
            >> *(   ('*' >> factor)[lm::bind(&self_t::add_binary_op, &self, &self_t::token_op_mul)]
                |   ('/' >> factor)[lm::bind(&self_t::add_binary_op, &self, &self_t::token_op_div)]
                )
        ;

    factor
        =   real_p[lm::bind(&self_t::add_const, &self, &self_t::token_const, _1)]
        |    self.variables_p[lm::bind(&self_t::add_variable, &self, &self_t::token_variable, _1)]

        |   (str_p("sin") >> '(' >> expression >> ')')[lm::bind(&self_t::add_unary_op, &self, &self_t::token_fn_sin)]
        |   (str_p("cos") >> '(' >> expression >> ')')[lm::bind(&self_t::add_unary_op, &self, &self_t::token_fn_cos)]

        |   '(' >> expression >> ')'
        |   ('-' >> factor)[lm::bind(&self_t::add_unary_op, &self, &self_t::token_op_neg)]
        |   ('+' >> factor)
        ;
}
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.