Здравствуйте, 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 >>