C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html

This commit is contained in:
Arash Partow 2014-02-09 20:20:15 +11:00
parent d5ae48c109
commit 5ebc630e25
3 changed files with 1065 additions and 612 deletions

View File

@ -815,7 +815,7 @@ namespace exprtk
return erfc_impl(static_cast<double>(v),real_type_tag()); return erfc_impl(static_cast<double>(v),real_type_tag());
} }
template <typename T> inline T abs_impl(const T v, real_type_tag) { return std::abs (v); } template <typename T> inline T abs_impl(const T v, real_type_tag) { return ((v >= T(0)) ? v : -v); }
template <typename T> inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } template <typename T> inline T acos_impl(const T v, real_type_tag) { return std::acos (v); }
template <typename T> inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } template <typename T> inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); }
template <typename T> inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } template <typename T> inline T asin_impl(const T v, real_type_tag) { return std::asin (v); }
@ -848,7 +848,7 @@ namespace exprtk
template <typename T> inline T frac_impl(const T v, real_type_tag) { return (v - static_cast<long long>(v)); } template <typename T> inline T frac_impl(const T v, real_type_tag) { return (v - static_cast<long long>(v)); }
template <typename T> inline T trunc_impl(const T v, real_type_tag) { return T(static_cast<long long>(v)); } template <typename T> inline T trunc_impl(const T v, real_type_tag) { return T(static_cast<long long>(v)); }
template <typename T> inline T abs_impl(const T v, int_type_tag) { return std::abs (v); } template <typename T> inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); }
template <typename T> inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } template <typename T> inline T exp_impl(const T v, int_type_tag) { return std::exp (v); }
template <typename T> inline T log_impl(const T v, int_type_tag) { return std::log (v); } template <typename T> inline T log_impl(const T v, int_type_tag) { return std::log (v); }
template <typename T> inline T log10_impl(const T v, int_type_tag) { return std::log10(v); } template <typename T> inline T log10_impl(const T v, int_type_tag) { return std::log10(v); }
@ -2522,7 +2522,17 @@ namespace exprtk
bool result() bool result()
{ {
return state_ && stack_.empty(); if (!stack_.empty())
{
lexer::token t;
t.value = stack_.top().first;
t.position = stack_.top().second;
error_token_ = t;
state_ = false;
return false;
}
else
return state_;
} }
lexer::token error_token() lexer::token error_token()
@ -2533,7 +2543,7 @@ namespace exprtk
void reset() void reset()
{ {
//why? because msvc doesn't support swap properly. //why? because msvc doesn't support swap properly.
stack_ = std::stack<char>(); stack_ = std::stack<std::pair<char,std::size_t> >();
state_ = true; state_ = true;
error_token_.clear(); error_token_.clear();
} }
@ -2547,9 +2557,9 @@ namespace exprtk
) )
{ {
char c = t.value[0]; char c = t.value[0];
if (t.type == lexer::token::e_lbracket) stack_.push(')'); if (t.type == lexer::token::e_lbracket) stack_.push(std::make_pair(')',t.position));
else if (t.type == lexer::token::e_lcrlbracket) stack_.push('}'); else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position));
else if (t.type == lexer::token::e_lsqrbracket) stack_.push(']'); else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position));
else if (exprtk::details::is_right_bracket(c)) else if (exprtk::details::is_right_bracket(c))
{ {
if (stack_.empty()) if (stack_.empty())
@ -2558,7 +2568,7 @@ namespace exprtk
error_token_ = t; error_token_ = t;
return false; return false;
} }
else if (c != stack_.top()) else if (c != stack_.top().first)
{ {
state_ = false; state_ = false;
error_token_ = t; error_token_ = t;
@ -2575,7 +2585,7 @@ namespace exprtk
private: private:
bool state_; bool state_;
std::stack<char> stack_; std::stack<std::pair<char,std::size_t> > stack_;
lexer::token error_token_; lexer::token error_token_;
}; };
@ -3063,7 +3073,8 @@ namespace exprtk
e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031, e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031,
e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035, e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035,
e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039,
e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043 e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043,
e_sf4ext44 = 2044, e_sf4ext45 = 2045
}; };
struct base_operation_t struct base_operation_t
@ -3798,7 +3809,7 @@ namespace exprtk
case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2))
return arg1; return arg1;
else else
return ((T(2.0) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2);
default : return std::numeric_limits<T>::quiet_NaN(); default : return std::numeric_limits<T>::quiet_NaN();
} }
} }
@ -4640,11 +4651,13 @@ namespace exprtk
template <typename T> struct sfext36_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) / (z - w); } static inline std::string id() { return "(t*t)/(t-t)";} }; template <typename T> struct sfext36_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) / (z - w); } static inline std::string id() { return "(t*t)/(t-t)";} };
template <typename T> struct sfext37_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x / y) / (z - w); } static inline std::string id() { return "(t/t)/(t-t)";} }; template <typename T> struct sfext37_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x / y) / (z - w); } static inline std::string id() { return "(t/t)/(t-t)";} };
template <typename T> struct sfext38_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) * (z - w); } static inline std::string id() { return "(t*t)*(t-t)";} }; template <typename T> struct sfext38_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) * (z - w); } static inline std::string id() { return "(t*t)*(t-t)";} };
template <typename T> struct sfext39_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x / y) * (z - w); } static inline std::string id() { return "(t/t)*(t-t)";} }; template <typename T> struct sfext39_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) / (z * w); } static inline std::string id() { return "(t*t)/(t*t)";} };
template <typename T> struct sfext40_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y * (z / w)); } static inline std::string id() { return "t+(t*(t/t))";} }; template <typename T> struct sfext40_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x / y) * (z - w); } static inline std::string id() { return "(t/t)*(t-t)";} };
template <typename T> struct sfext41_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y * (z / w)); } static inline std::string id() { return "t-(t*(t/t))";} }; template <typename T> struct sfext41_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) * (z * w); } static inline std::string id() { return "(t*t)*(t*t)";} };
template <typename T> struct sfext42_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y / (z * w)); } static inline std::string id() { return "t+(t/(t*t))";} }; template <typename T> struct sfext42_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y * (z / w)); } static inline std::string id() { return "t+(t*(t/t))";} };
template <typename T> struct sfext43_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y / (z * w)); } static inline std::string id() { return "t-(t/(t*t))";} }; template <typename T> struct sfext43_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y * (z / w)); } static inline std::string id() { return "t-(t*(t/t))";} };
template <typename T> struct sfext44_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y / (z * w)); } static inline std::string id() { return "t+(t/(t*t))";} };
template <typename T> struct sfext45_op : public sf_base<T> { typedef typename sf_base<T>::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y / (z * w)); } static inline std::string id() { return "t-(t/(t*t))";} };
template <typename T, typename SpecialFunction> template <typename T, typename SpecialFunction>
class sf3_node : public trinary_node<T> class sf3_node : public trinary_node<T>
@ -6287,6 +6300,8 @@ namespace exprtk
virtual const T c() const = 0; virtual const T c() const = 0;
virtual void set_c(const T) = 0; virtual void set_c(const T) = 0;
virtual expression_node<T>* move_branch(const std::size_t& index) = 0;
}; };
template <typename T> template <typename T>
@ -6345,8 +6360,6 @@ namespace exprtk
public: public:
virtual std::string type_id() const = 0; virtual std::string type_id() const = 0;
virtual std::string type_id2() const { return ""; }
}; };
template <typename T> template <typename T>
@ -7140,30 +7153,6 @@ namespace exprtk
return id(); return id();
} }
std::string type_id2() const
{
std::string t[] = {
param_to_str<is_const_ref<T0>::result>::result(),
param_to_str<is_const_ref<T1>::result>::result(),
param_to_str<is_const_ref<T2>::result>::result()
};
std::string sf3id = id();
for (std::size_t i = 0; i < 3; ++i)
{
std::size_t index = std::string::npos;
if (std::string::npos != (index = sf3id.find("t")))
{
sf3id[index] = t[i][0];
}
else
break;
}
return sf3id;
}
static inline std::string id() static inline std::string id()
{ {
return SF3Operation::id(); return SF3Operation::id();
@ -7701,6 +7690,12 @@ namespace exprtk
return branch_[0].first; return branch_[0].first;
} }
inline expression_node<T>* move_branch(const std::size_t&)
{
branch_[0].second = false;
return branch_[0].first;
}
private: private:
cob_node(const cob_node<T,Operation>&); cob_node(const cob_node<T,Operation>&);
@ -10147,7 +10142,8 @@ namespace exprtk
e_numeric_check = 4, e_numeric_check = 4,
e_bracket_check = 8, e_bracket_check = 8,
e_sequence_check = 16, e_sequence_check = 16,
e_commutative_check = 32 e_commutative_check = 32,
e_strength_reduction = 64
}; };
struct unknown_symbol_resolver struct unknown_symbol_resolver
@ -10171,16 +10167,17 @@ namespace exprtk
} }
}; };
static const std::size_t precompile_all_opts = e_replacer + static const std::size_t compile_all_opts = e_replacer +
e_joiner + e_joiner +
e_numeric_check + e_numeric_check +
e_bracket_check + e_bracket_check +
e_sequence_check + e_sequence_check +
e_commutative_check; e_commutative_check +
e_strength_reduction;
parser(const std::size_t precompile_options = precompile_all_opts) parser(const std::size_t compile_options = compile_all_opts)
: symbol_name_caching_(false), : symbol_name_caching_(false),
precompile_options_(precompile_options), compile_options_(compile_options),
resolve_unknown_symbol_(false), resolve_unknown_symbol_(false),
unknown_symbol_resolver_(reinterpret_cast<unknown_symbol_resolver*>(0)), unknown_symbol_resolver_(reinterpret_cast<unknown_symbol_resolver*>(0)),
operator_joiner_2_(2), operator_joiner_2_(2),
@ -10199,6 +10196,7 @@ namespace exprtk
expression_generator_.set_ibom(inv_binary_op_map_); expression_generator_.set_ibom(inv_binary_op_map_);
expression_generator_.set_sf3m(sf3_map_); expression_generator_.set_sf3m(sf3_map_);
expression_generator_.set_sf4m(sf4_map_); expression_generator_.set_sf4m(sf4_map_);
expression_generator_.set_strength_reduction_state(strength_reduction_enabled());
} }
inline void init_precompilation() inline void init_precompilation()
@ -10347,32 +10345,37 @@ namespace exprtk
inline bool replacer_enabled() const inline bool replacer_enabled() const
{ {
return ((precompile_options_ & e_replacer) == e_replacer); return ((compile_options_ & e_replacer) == e_replacer);
} }
inline bool commutative_check_enabled() const inline bool commutative_check_enabled() const
{ {
return ((precompile_options_ & e_commutative_check) == e_commutative_check); return ((compile_options_ & e_commutative_check) == e_commutative_check);
} }
inline bool joiner_enabled() const inline bool joiner_enabled() const
{ {
return ((precompile_options_ & e_joiner) == e_joiner); return ((compile_options_ & e_joiner) == e_joiner);
} }
inline bool numeric_check_enabled() const inline bool numeric_check_enabled() const
{ {
return ((precompile_options_ & e_numeric_check) == e_numeric_check); return ((compile_options_ & e_numeric_check) == e_numeric_check);
} }
inline bool bracket_check_enabled() const inline bool bracket_check_enabled() const
{ {
return ((precompile_options_ & e_bracket_check) == e_bracket_check); return ((compile_options_ & e_bracket_check) == e_bracket_check);
} }
inline bool sequence_check_enabled() const inline bool sequence_check_enabled() const
{ {
return ((precompile_options_ & e_sequence_check) == e_sequence_check); return ((compile_options_ & e_sequence_check) == e_sequence_check);
}
inline bool strength_reduction_enabled() const
{
return ((compile_options_ & e_strength_reduction) == e_strength_reduction);
} }
inline bool run_assemblies() inline bool run_assemblies()
@ -10411,7 +10414,7 @@ namespace exprtk
set_error( set_error(
make_error(parser_error::e_token, make_error(parser_error::e_token,
bracket_checker_ptr->error_token(), bracket_checker_ptr->error_token(),
"ERR04 - Mismatched brackets: " + bracket_checker_ptr->error_token().value)); "ERR04 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'"));
} }
else if (0 != (numeric_checker_ptr = dynamic_cast<lexer::helper::numeric_checker*>(helper_assembly_.error_token_scanner))) else if (0 != (numeric_checker_ptr = dynamic_cast<lexer::helper::numeric_checker*>(helper_assembly_.error_token_scanner)))
{ {
@ -10421,7 +10424,7 @@ namespace exprtk
set_error( set_error(
make_error(parser_error::e_token, make_error(parser_error::e_token,
error_token, error_token,
"ERR05 - Invalid numeric token: " + error_token.value)); "ERR05 - Invalid numeric token: '" + error_token.value + "'"));
} }
} }
else if (0 != (sequence_validator_ptr = dynamic_cast<lexer::helper::sequence_validator*>(helper_assembly_.error_token_scanner))) else if (0 != (sequence_validator_ptr = dynamic_cast<lexer::helper::sequence_validator*>(helper_assembly_.error_token_scanner)))
@ -11510,7 +11513,7 @@ namespace exprtk
{ {
if (expression_list.empty()) if (expression_list.empty())
return error_node(); return error_node();
if (1 == expression_list.size()) else if (1 == expression_list.size())
return expression_list[0]; return expression_list[0];
Sequence<expression_node_ptr,Allocator> tmp_expression_list; Sequence<expression_node_ptr,Allocator> tmp_expression_list;
@ -12471,6 +12474,16 @@ namespace exprtk
node_allocator_ = &na; node_allocator_ = &na;
} }
inline void set_strength_reduction_state(const bool strength_reduction_enabled)
{
strength_reduction_enabled_ = strength_reduction_enabled;
}
inline bool strength_reduction_enabled() const
{
return strength_reduction_enabled_;
}
inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop)
{ {
typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation);
@ -13737,6 +13750,11 @@ namespace exprtk
const unsigned int p = static_cast<unsigned int>(std::abs(c)); const unsigned int p = static_cast<unsigned int>(std::abs(c));
if (0 == p) if (0 == p)
return node_allocator_->allocate_c<literal_node_t>(T(1)); return node_allocator_->allocate_c<literal_node_t>(T(1));
else if (T(2) == c)
{
return node_allocator_->
template allocate_rr<typename details::vov_node<Type,details::mul_op<Type> > >(v,v);
}
else else
{ {
if (not_recipricol) if (not_recipricol)
@ -13879,6 +13897,56 @@ namespace exprtk
return cobnode; return cobnode;
} }
} }
if (operation == details::e_mul)
{
details::cob_base_node<Type>* cobnode = dynamic_cast<details::cob_base_node<Type>*>(branch[1]);
details::operator_type cob_opr = cobnode->operation();
if (
(details::e_div == cob_opr) ||
(details::e_mul == cob_opr)
)
{
switch (cob_opr)
{
case details::e_div : cobnode->set_c(c * cobnode->c()); break;
case details::e_mul : cobnode->set_c(cobnode->c() / c); break;
default : return error_node();
}
return cobnode;
}
}
else if (operation == details::e_div)
{
details::cob_base_node<Type>* cobnode = dynamic_cast<details::cob_base_node<Type>*>(branch[1]);
details::operator_type cob_opr = cobnode->operation();
if (
(details::e_div == cob_opr) ||
(details::e_mul == cob_opr)
)
{
details::expression_node<Type>* new_cobnode = error_node();
switch (cob_opr)
{
case details::e_div : new_cobnode = expr_gen.node_allocator_->
template allocate_tt<typename details::cob_node<Type,details::mul_op<Type> > >
(c / cobnode->c(),cobnode->move_branch(0));
break;
case details::e_mul : new_cobnode = expr_gen.node_allocator_->
template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > >
(c / cobnode->c(),cobnode->move_branch(0));
break;
default : return error_node();
}
free_node(*expr_gen.node_allocator_,branch[1]);
return new_cobnode;
}
}
} }
else if (details::is_sf3ext_node(branch[1])) else if (details::is_sf3ext_node(branch[1]))
{ {
@ -13894,7 +13962,7 @@ namespace exprtk
{ {
#define case_stmt(op0,op1) \ #define case_stmt(op0,op1) \
case op0 : return expr_gen.node_allocator_-> \ case op0 : return expr_gen.node_allocator_-> \
template allocate_rc<typename details::cob_node<Type,op1<Type> > > \ template allocate_tt<typename details::cob_node<Type,op1<Type> > > \
(c,branch[1]); \ (c,branch[1]); \
basic_opr_switch_statements basic_opr_switch_statements
@ -13935,6 +14003,25 @@ namespace exprtk
return bocnode; return bocnode;
} }
} }
else if (operation == details::e_div)
{
details::boc_base_node<Type>* bocnode = dynamic_cast<details::boc_base_node<Type>*>(branch[0]);
details::operator_type boc_opr = bocnode->operation();
if (
(details::e_div == boc_opr) ||
(details::e_mul == boc_opr)
)
{
switch (boc_opr)
{
case details::e_div : bocnode->set_c(c * bocnode->c()); break;
case details::e_mul : bocnode->set_c(bocnode->c() / c); break;
default : return error_node();
}
return bocnode;
}
}
} }
if (details::is_sf3ext_node(branch[0])) if (details::is_sf3ext_node(branch[0]))
@ -14037,6 +14124,9 @@ namespace exprtk
if (expr_gen.cardinal_pow_optimizable(operation,c)) if (expr_gen.cardinal_pow_optimizable(operation,c))
{ {
if (T(1) == c)
return branch[0];
else
return expr_gen.cardinal_pow_optimization(v,c); return expr_gen.cardinal_pow_optimization(v,c);
} }
@ -14157,6 +14247,7 @@ namespace exprtk
case_stmt(details::e_sf4ext38,details::sfext38_op) case_stmt(details::e_sf4ext39,details::sfext39_op) case_stmt(details::e_sf4ext38,details::sfext38_op) case_stmt(details::e_sf4ext39,details::sfext39_op)
case_stmt(details::e_sf4ext40,details::sfext40_op) case_stmt(details::e_sf4ext41,details::sfext41_op) case_stmt(details::e_sf4ext40,details::sfext40_op) case_stmt(details::e_sf4ext41,details::sfext41_op)
case_stmt(details::e_sf4ext42,details::sfext42_op) case_stmt(details::e_sf4ext43,details::sfext43_op) case_stmt(details::e_sf4ext42,details::sfext42_op) case_stmt(details::e_sf4ext43,details::sfext43_op)
case_stmt(details::e_sf4ext44,details::sfext44_op) case_stmt(details::e_sf4ext45,details::sfext45_op)
#undef case_stmt #undef case_stmt
default : return error_node(); default : return error_node();
} }
@ -14307,6 +14398,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[0]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) // (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)
if ((details::e_div == o0) && (details::e_div == o1)) if ((details::e_div == o0) && (details::e_div == o1))
{ {
@ -14315,7 +14408,9 @@ namespace exprtk
template compile<vtype,vtype,vtype>(expr_gen,"t/(t*t)",v0,v1,v2,result); template compile<vtype,vtype,vtype>(expr_gen,"t/(t*t)",v0,v1,v2,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf3ext_expression::template compile<vtype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) }
if (synthesize_sf3ext_expression::template compile<vtype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14352,6 +14447,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 // v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1
if ((details::e_div == o0) && (details::e_div == o1)) if ((details::e_div == o0) && (details::e_div == o1))
{ {
@ -14360,7 +14457,9 @@ namespace exprtk
template compile<vtype,vtype,vtype>(expr_gen,"(t*t)/t",v0,v2,v1,result); template compile<vtype,vtype,vtype>(expr_gen,"(t*t)/t",v0,v2,v1,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf3ext_expression::template compile<vtype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) }
if (synthesize_sf3ext_expression::template compile<vtype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14398,6 +14497,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (v0 / v1) / c --> (vovoc) v0 / (v1 * c) // (v0 / v1) / c --> (vovoc) v0 / (v1 * c)
if ((details::e_div == o0) && (details::e_div == o1)) if ((details::e_div == o0) && (details::e_div == o1))
{ {
@ -14406,7 +14507,9 @@ namespace exprtk
template compile<vtype,vtype,ctype>(expr_gen,"t/(t*t)",v0,v1,c,result); template compile<vtype,vtype,ctype>(expr_gen,"t/(t*t)",v0,v1,c,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf3ext_expression::template compile<vtype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) }
if (synthesize_sf3ext_expression::template compile<vtype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14443,6 +14546,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// v0 / (v1 / c) --> (vocov) (v0 * c) / v1 // v0 / (v1 / c) --> (vocov) (v0 * c) / v1
if ((details::e_div == o0) && (details::e_div == o1)) if ((details::e_div == o0) && (details::e_div == o1))
{ {
@ -14451,7 +14556,9 @@ namespace exprtk
template compile<vtype,ctype,vtype>(expr_gen,"(t*t)/t",v0,c,v1,result); template compile<vtype,ctype,vtype>(expr_gen,"(t*t)/t",v0,c,v1,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf3ext_expression::template compile<vtype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) }
if (synthesize_sf3ext_expression::template compile<vtype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14488,6 +14595,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[0]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) // (v0 / c) / v1 --> (vovoc) v0 / (v1 * c)
if ((details::e_div == o0) && (details::e_div == o1)) if ((details::e_div == o0) && (details::e_div == o1))
{ {
@ -14496,7 +14605,9 @@ namespace exprtk
template compile<vtype,vtype,ctype>(expr_gen,"t/(t*t)",v0,v1,c,result); template compile<vtype,vtype,ctype>(expr_gen,"t/(t*t)",v0,v1,c,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf3ext_expression::template compile<vtype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) }
if (synthesize_sf3ext_expression::template compile<vtype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14533,6 +14644,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// v0 / (c / v1) --> (vovoc) (v0 * v1) / c // v0 / (c / v1) --> (vovoc) (v0 * v1) / c
if ((details::e_div == o0) && (details::e_div == o1)) if ((details::e_div == o0) && (details::e_div == o1))
{ {
@ -14541,7 +14654,9 @@ namespace exprtk
template compile<vtype,vtype,ctype>(expr_gen,"(t*t)/t",v0,v1,c,result); template compile<vtype,vtype,ctype>(expr_gen,"(t*t)/t",v0,v1,c,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf3ext_expression::template compile<vtype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) }
if (synthesize_sf3ext_expression::template compile<vtype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14578,6 +14693,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[0]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (c / v0) / v1 --> (covov) c / (v0 * v1) // (c / v0) / v1 --> (covov) c / (v0 * v1)
if ((details::e_div == o0) && (details::e_div == o1)) if ((details::e_div == o0) && (details::e_div == o1))
{ {
@ -14586,7 +14703,9 @@ namespace exprtk
template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",c,v0,v1,result); template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",c,v0,v1,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf3ext_expression::template compile<ctype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) }
if (synthesize_sf3ext_expression::template compile<ctype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14624,6 +14743,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// c / (v0 / v1) --> (covov) (c * v1) / v0 // c / (v0 / v1) --> (covov) (c * v1) / v0
if ((details::e_div == o0) && (details::e_div == o1)) if ((details::e_div == o0) && (details::e_div == o1))
{ {
@ -14632,7 +14753,9 @@ namespace exprtk
template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",c,v1,v0,result); template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",c,v1,v0,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf3ext_expression::template compile<ctype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) }
if (synthesize_sf3ext_expression::template compile<ctype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14669,6 +14792,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (c0 + v) + c1 --> (cov) (c0 + c1) + v // (c0 + v) + c1 --> (cov) (c0 + c1) + v
if ((details::e_add == o0) && (details::e_add == o1)) if ((details::e_add == o0) && (details::e_add == o1))
{ {
@ -14717,7 +14842,9 @@ namespace exprtk
return expr_gen.node_allocator_-> return expr_gen.node_allocator_->
template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1,v); template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1,v);
} }
else if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) }
if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14755,6 +14882,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (c0) + (v + c1) --> (cov) (c0 + c1) + v // (c0) + (v + c1) --> (cov) (c0 + c1) + v
if ((details::e_add == o0) && (details::e_add == o1)) if ((details::e_add == o0) && (details::e_add == o1))
{ {
@ -14803,7 +14932,9 @@ namespace exprtk
return expr_gen.node_allocator_-> return expr_gen.node_allocator_->
template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1,v); template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1,v);
} }
else if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) }
if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14851,6 +14982,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (c0) + (c1 + v) --> (cov) (c0 + c1) + v // (c0) + (c1 + v) --> (cov) (c0 + c1) + v
if ((details::e_add == o0) && (details::e_add == o1)) if ((details::e_add == o0) && (details::e_add == o1))
{ {
@ -14899,7 +15032,9 @@ namespace exprtk
return expr_gen.node_allocator_-> return expr_gen.node_allocator_->
template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1,v); template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1,v);
} }
else if (synthesize_sf3ext_expression::template compile<ctype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),c0,c1,v,result)) }
if (synthesize_sf3ext_expression::template compile<ctype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),c0,c1,v,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -14936,6 +15071,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (v + c0) + c1 --> (voc) v + (c0 + c1) // (v + c0) + c1 --> (voc) v + (c0 + c1)
if ((details::e_add == o0) && (details::e_add == o1)) if ((details::e_add == o0) && (details::e_add == o1))
{ {
@ -14984,7 +15121,9 @@ namespace exprtk
return expr_gen.node_allocator_-> return expr_gen.node_allocator_->
template allocate_rc<typename details::voc_node<Type,details::div_op<Type> > >(v,c0 * c1); template allocate_rc<typename details::voc_node<Type,details::div_op<Type> > >(v,c0 * c1);
} }
else if (synthesize_sf3ext_expression::template compile<vtype,ctype,ctype>(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result)) }
if (synthesize_sf3ext_expression::template compile<vtype,ctype,ctype>(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -15040,6 +15179,27 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[0]);
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)
if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2))
{
const bool synthesis_result =
synthesize_sf4ext_expression::
template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v2,v1,v3,result);
return (synthesis_result) ? result : error_node();
}
// (v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)
if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2))
{
const bool synthesis_result =
synthesize_sf4ext_expression::
template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v3,v1,v2,result);
return (synthesis_result) ? result : error_node();
}
}
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
@ -15275,6 +15435,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 // (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1
if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2))
{ {
@ -15339,7 +15501,28 @@ namespace exprtk
template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) // (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1)
else if (
(details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) &&
((details::e_add == o1) || (details::e_sub == o1))
)
{
std::string specfunc;
switch (o1)
{
case details::e_add : specfunc = "t*(t+t)"; break;
case details::e_sub : specfunc = "t*(t-t)"; break;
default : return error_node();
}
const bool synthesis_result =
synthesize_sf3ext_expression::
template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result);
return (synthesis_result) ? result : error_node();
}
}
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -15387,6 +15570,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 // (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1
if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2))
{ {
@ -15451,7 +15636,28 @@ namespace exprtk
template compile<ctype,vtype,vtype>(expr_gen,"t*(t/t)",Type(1) / (c0 * c1),v0,v1,result); template compile<ctype,vtype,vtype>(expr_gen,"t*(t/t)",Type(1) / (c0 * c1),v0,v1,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) // (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)
else if (
(details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) &&
((details::e_add == o1) || (details::e_sub == o1))
)
{
std::string specfunc;
switch (o1)
{
case details::e_add : specfunc = "t*(t+t)"; break;
case details::e_sub : specfunc = "t*(t-t)"; break;
default : return error_node();
}
const bool synthesis_result =
synthesize_sf3ext_expression::
template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result);
return (synthesis_result) ? result : error_node();
}
}
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -15499,6 +15705,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 // (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1
if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2))
{ {
@ -15563,7 +15771,28 @@ namespace exprtk
template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) // (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)
else if (
(details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) &&
((details::e_add == o1) || (details::e_sub == o1))
)
{
std::string specfunc;
switch (o1)
{
case details::e_add : specfunc = "t*(t+t)"; break;
case details::e_sub : specfunc = "t*(t-t)"; break;
default : return error_node();
}
const bool synthesis_result =
synthesize_sf3ext_expression::
template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result);
return (synthesis_result) ? result : error_node();
}
}
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -15611,6 +15840,8 @@ namespace exprtk
details::free_node(*(expr_gen.node_allocator_),branch[1]); details::free_node(*(expr_gen.node_allocator_),branch[1]);
expression_node_ptr result = error_node(); expression_node_ptr result = error_node();
if (expr_gen.strength_reduction_enabled())
{
// (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 // (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1
if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2))
{ {
@ -15675,7 +15906,28 @@ namespace exprtk
template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",Type(1) / (c0 * c1),v0,v1,result); template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",Type(1) / (c0 * c1),v0,v1,result);
return (synthesis_result) ? result : error_node(); return (synthesis_result) ? result : error_node();
} }
else if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) // (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)
else if (
(details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) &&
((details::e_add == o1) || (details::e_sub == o1))
)
{
std::string specfunc;
switch (o1)
{
case details::e_add : specfunc = "t*(t+t)"; break;
case details::e_sub : specfunc = "t*(t-t)"; break;
default : return error_node();
}
const bool synthesis_result =
synthesize_sf3ext_expression::
template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result);
return (synthesis_result) ? result : error_node();
}
}
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result))
return result; return result;
else if (!expr_gen.valid_operator(o0,f0)) else if (!expr_gen.valid_operator(o0,f0))
return error_node(); return error_node();
@ -17710,6 +17962,7 @@ namespace exprtk
return expression_point; return expression_point;
} }
bool strength_reduction_enabled_;
details::node_allocator* node_allocator_; details::node_allocator* node_allocator_;
synthesize_map_t synthesize_map_; synthesize_map_t synthesize_map_;
unary_op_map_t* unary_op_map_; unary_op_map_t* unary_op_map_;
@ -17879,6 +18132,7 @@ namespace exprtk
register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35) register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35)
register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39) register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39)
register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43) register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43)
register_sf4ext(44) register_sf4ext(45)
#undef register_sf4ext #undef register_sf4ext
} }
@ -17894,7 +18148,7 @@ namespace exprtk
details::node_allocator node_allocator_; details::node_allocator node_allocator_;
symbol_table<T> symbol_table_; symbol_table<T> symbol_table_;
bool symbol_name_caching_; bool symbol_name_caching_;
std::size_t precompile_options_; std::size_t compile_options_;
std::deque<std::string> symbol_name_cache_; std::deque<std::string> symbol_name_cache_;
std::deque<parser_error::type> error_list_; std::deque<parser_error::type> error_list_;
bool resolve_unknown_symbol_; bool resolve_unknown_symbol_;

View File

@ -1384,6 +1384,42 @@ inline bool run_test01()
test_xy<T>("((x / 2) * (3 / y))",T(7.0),T(9.0),T(((7.0 / 2.0) * (3.0 / 9.0)))), test_xy<T>("((x / 2) * (3 / y))",T(7.0),T(9.0),T(((7.0 / 2.0) * (3.0 / 9.0)))),
test_xy<T>("((x * 2) / (3 / y))",T(7.0),T(9.0),T(((7.0 * 2.0) / (3.0 / 9.0)))), test_xy<T>("((x * 2) / (3 / y))",T(7.0),T(9.0),T(((7.0 * 2.0) / (3.0 / 9.0)))),
test_xy<T>("((x / 2) / (3 * y))",T(7.0),T(9.0),T(((7.0 / 2.0) / (3.0 * 9.0)))), test_xy<T>("((x / 2) / (3 * y))",T(7.0),T(9.0),T(((7.0 / 2.0) / (3.0 * 9.0)))),
test_xy<T>("([(min(x,8) + y) + 3] - 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) + 3.0) - 4.0))),
test_xy<T>("([(min(x,8) + y) + 3] + 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) + 3.0) + 4.0))),
test_xy<T>("([(min(x,8) + y) + 3] * 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) + 3.0) * 4.0))),
test_xy<T>("([(min(x,8) + y) + 3] / 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) + 3.0) / 4.0))),
test_xy<T>("([(min(x,8) + y) - 3] - 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) - 3.0) - 4.0))),
test_xy<T>("([(min(x,8) + y) - 3] + 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) - 3.0) + 4.0))),
test_xy<T>("([(min(x,8) + y) - 3] * 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) - 3.0) * 4.0))),
test_xy<T>("([(min(x,8) + y) - 3] / 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) - 3.0) / 4.0))),
test_xy<T>("([(min(x,8) + y) * 3] - 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) * 3.0) - 4.0))),
test_xy<T>("([(min(x,8) + y) * 3] + 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) * 3.0) + 4.0))),
test_xy<T>("([(min(x,8) + y) * 3] * 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) * 3.0) * 4.0))),
test_xy<T>("([(min(x,8) + y) * 3] / 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) * 3.0) / 4.0))),
test_xy<T>("([(min(x,8) + y) / 3] - 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) / 3.0) - 4.0))),
test_xy<T>("([(min(x,8) + y) / 3] + 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) / 3.0) + 4.0))),
test_xy<T>("([(min(x,8) + y) / 3] * 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) / 3.0) * 4.0))),
test_xy<T>("([(min(x,8) + y) / 3] / 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) / 3.0) / 4.0))),
test_xy<T>("(4 - [3 + (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 - (3.0 + (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 + [3 + (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 + (3.0 + (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 * [3 + (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 * (3.0 + (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 / [3 + (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 / (3.0 + (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 - [3 - (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 - (3.0 - (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 + [3 - (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 + (3.0 - (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 * [3 - (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 * (3.0 - (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 / [3 - (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 / (3.0 - (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 - [3 * (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 - (3.0 * (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 + [3 * (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 + (3.0 * (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 * [3 * (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 * (3.0 * (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 / [3 * (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 / (3.0 * (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 - [3 / (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 - (3.0 / (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 + [3 / (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 + (3.0 / (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 * [3 / (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 * (3.0 / (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("(4 / [3 / (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 / (3.0 / (std::min(7.0,8.0) + 9.0))))),
test_xy<T>("((2 * x) + (2 * y))",T(7.0),T(9.0),T(((2.0 * 7.0) + (2.0 * 9.0)))),
test_xy<T>("((2 * x) - (2 * y))",T(7.0),T(9.0),T(((2.0 * 7.0) - (2.0 * 9.0)))),
test_xy<T>("((2 * x) + (y * 2))",T(7.0),T(9.0),T(((2.0 * 7.0) + (9.0 * 2.0)))),
test_xy<T>("((x * 2) - (y * 2))",T(7.0),T(9.0),T(((7.0 * 2.0) - (9.0 * 2.0)))),
test_xy<T>("0 * (abs (x) + acos (y) + asin (x) + atan (y))",T(1.0),T(1.0),T(0.0)), test_xy<T>("0 * (abs (x) + acos (y) + asin (x) + atan (y))",T(1.0),T(1.0),T(0.0)),
test_xy<T>("0 * (ceil (x) + cos (y) + cosh (x) + exp (y))",T(1.0),T(1.0),T(0.0)), test_xy<T>("0 * (ceil (x) + cos (y) + cosh (x) + exp (y))",T(1.0),T(1.0),T(0.0)),
test_xy<T>("0 * (floor(x) + log (y) + log10(x) + round(y))",T(1.0),T(1.0),T(0.0)), test_xy<T>("0 * (floor(x) + log (y) + log10(x) + round(y))",T(1.0),T(1.0),T(0.0)),
@ -1468,7 +1504,39 @@ inline bool run_test01()
test_xyz<T>("( x / (y / z))",T(7.0),T(9.0),T(3.0),T(( 7.0 / (9.0 / 3.0)))), test_xyz<T>("( x / (y / z))",T(7.0),T(9.0),T(3.0),T(( 7.0 / (9.0 / 3.0)))),
test_xyz<T>("( x / (y / 2))",T(7.0),T(9.0),T(3.0),T(( 7.0 / (9.0 / 2.0)))), test_xyz<T>("( x / (y / 2))",T(7.0),T(9.0),T(3.0),T(( 7.0 / (9.0 / 2.0)))),
test_xyz<T>("( x / (2 / y))",T(7.0),T(9.0),T(3.0),T(( 7.0 / (2.0 / 9.0)))), test_xyz<T>("( x / (2 / y))",T(7.0),T(9.0),T(3.0),T(( 7.0 / (2.0 / 9.0)))),
test_xyz<T>("( 2 / (x / y))",T(7.0),T(9.0),T(3.0),T(( 2.0 / (7.0 / 9.0)))) test_xyz<T>("( 2 / (x / y))",T(7.0),T(9.0),T(3.0),T(( 2.0 / (7.0 / 9.0)))),
test_xyz<T>("([(min(x,y) + z) + 3] - 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) + 3.0) - 4.0))),
test_xyz<T>("([(min(x,y) + z) + 3] + 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) + 3.0) + 4.0))),
test_xyz<T>("([(min(x,y) + z) + 3] * 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) + 3.0) * 4.0))),
test_xyz<T>("([(min(x,y) + z) + 3] / 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) + 3.0) / 4.0))),
test_xyz<T>("([(min(x,y) + z) - 3] - 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) - 3.0) - 4.0))),
test_xyz<T>("([(min(x,y) + z) - 3] + 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) - 3.0) + 4.0))),
test_xyz<T>("([(min(x,y) + z) - 3] * 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) - 3.0) * 4.0))),
test_xyz<T>("([(min(x,y) + z) - 3] / 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) - 3.0) / 4.0))),
test_xyz<T>("([(min(x,y) + z) * 3] - 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) * 3.0) - 4.0))),
test_xyz<T>("([(min(x,y) + z) * 3] + 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) * 3.0) + 4.0))),
test_xyz<T>("([(min(x,y) + z) * 3] * 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) * 3.0) * 4.0))),
test_xyz<T>("([(min(x,y) + z) * 3] / 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) * 3.0) / 4.0))),
test_xyz<T>("([(min(x,y) + z) / 3] - 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) / 3.0) - 4.0))),
test_xyz<T>("([(min(x,y) + z) / 3] + 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) / 3.0) + 4.0))),
test_xyz<T>("([(min(x,y) + z) / 3] * 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) / 3.0) * 4.0))),
test_xyz<T>("([(min(x,y) + z) / 3] / 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) / 3.0) / 4.0))),
test_xyz<T>("(4 - [3 + (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 - (3.0 + (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 + [3 + (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 + (3.0 + (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 * [3 + (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 * (3.0 + (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 / [3 + (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 / (3.0 + (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 - [3 - (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 - (3.0 - (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 + [3 - (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 + (3.0 - (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 * [3 - (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 * (3.0 - (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 / [3 - (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 / (3.0 - (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 - [3 * (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 - (3.0 * (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 + [3 * (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 + (3.0 * (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 * [3 * (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 * (3.0 * (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 / [3 * (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 / (3.0 * (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 - [3 / (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 - (3.0 / (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 + [3 / (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 + (3.0 / (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 * [3 / (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 * (3.0 / (std::min(5.0,7.0) + 9.0))))),
test_xyz<T>("(4 / [3 / (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 / (3.0 / (std::min(5.0,7.0) + 9.0))))),
}; };
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xyz<T>); static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xyz<T>);
@ -3854,6 +3922,12 @@ inline bool run_test19()
// gof(x) = g(f(x)) // gof(x) = g(f(x))
compositor.add("gof","g(f(x))","x"); compositor.add("gof","g(f(x))","x");
// fogof(x) = f(g(f(x)))
compositor.add("fogof","f(g(f(x)))","x");
// gofog(x) = g(f(g(x)))
compositor.add("gofog","g(f(g(x)))","x");
symbol_table_t& symbol_table = compositor.symbol_table(); symbol_table_t& symbol_table = compositor.symbol_table();
symbol_table.add_constants(); symbol_table.add_constants();
symbol_table.add_variable("x",x); symbol_table.add_variable("x",x);
@ -3866,6 +3940,8 @@ inline bool run_test19()
"equal(gog(x),(x^4 - 6x^2 + 6))", "equal(gog(x),(x^4 - 6x^2 + 6))",
"equal(fog(x),(x^2 - 1))", "equal(fog(x),(x^2 - 1))",
"equal(gof(x),(x^2 + 4x + 1))", "equal(gof(x),(x^2 + 4x + 1))",
"equal(fogof(x),(x^2 + 4x + 3))",
"equal(gofog(x),(x^4 - 2x^2 - 2))"
}; };
static const std::size_t expr_str_list_size = sizeof(expr_str_list) / sizeof(std::string); static const std::size_t expr_str_list_size = sizeof(expr_str_list) / sizeof(std::string);

View File

@ -101,6 +101,7 @@ include path (e.g: /usr/include/).
(1) For a complete build: make clean all (1) For a complete build: make clean all
(2) For a PGO build: make clean pgo (2) For a PGO build: make clean pgo
(3) To strip executables: make strip_bin (3) To strip executables: make strip_bin
(5) Execute valgrind check: make valgrind_check
@ -424,7 +425,11 @@ follows:
(1) Symbol Table (1) Symbol Table
A structure that is used to store references to variables, constants A structure that is used to store references to variables, constants
and functions that are to be used within expressions. and functions that are to be used within expressions. Furthermore in
the context of composited recursive functions the symbol table can
also be thought of as a simple representation of a stack specific for
the expression(s) that reference it.
(2) Expression (2) Expression
A structure that holds an AST for a specified expression and is used A structure that holds an AST for a specified expression and is used
@ -459,6 +464,7 @@ Expression: z := (x + y^-2.345) * sin(pi / min(w - 7.3,v))
/ \ / \
Variable(w) Constant(7.3) Variable(w) Constant(7.3)
(3) Parser (3) Parser
A structure which takes as input a string representation of an A structure which takes as input a string representation of an
expression and attempts to compile said input with the result being an expression and attempts to compile said input with the result being an
@ -470,7 +476,118 @@ interface.
[10 - SPECIAL FUNCTIONS] [10 - COMPILATION OPTIONS]
The exprtk::parser when being instantiated takes as input a set of
options to be used during the compilation process of expressions.
An example instantiation of exprtk::parser where only the joiner,
commutative and strength reduction options are enabled is as follows:
const std::size_t compile_options = e_joiner +
e_commutative_check +
e_strength_reduction;
exprtk::parser<NumericType> parser(compile_options);
Currently seven types of options are supported, and enabled by
default. The options and their explanations are as follows:
(1) Replacer (e_replacer)
Enable replacement of specific tokens with other tokens. For example
the token "true" of type symbol will be replaced with the numeric
token of value one.
(a) (x < y) == true ---> (x < y) == 1
(b) false == (x > y) ---> 0 == (x > y)
(2) Joiner (e_joiner)
Enable joining of multi-character operators that may have been
incorrectly disjoint in the string representation of the specified
expression. For example the consecutive tokens of ">" "=" will become
">=" representing the "greater than or equal to" operator. If not
properly resolved the original form will cause a compilation error.
The following is a listing of the scenarios that the joiner can
handle:
(a) ':' '=' ---> ':=' (assignment)
(b) '>' '=' ---> '>=' (gte)
(c) '<' '=' ---> '<=' (lte)
(d) '=' '=' ---> '==' (equal)
(e) '!' '=' ---> '!=' (not-equal)
(f) '<' '>' ---> '<>' (not-equal)
An example of the transformation that takes place is as follows:
(a) (x > = y) and (z ! = w) ---> (x >= y) and (z != w)
(3) Numeric Check (e_numeric_check)
Enable validation of tokens representing numeric types so as to catch
any errors prior to the costly process of the main compilation step
commencing.
(4) Bracket Check (e_bracket_check)
Enable the check for validating the ordering of brackets in the
specified expression.
(5) Sequence Check (e_sequence_check)
Enable the check for validating that sequences of either pairs or
triplets of tokens make sense. For example the following sequence of
tokens when encountered will raise an error:
(a) (x + * 3) ---> sequence error
(6) Commutative Check (e_commutative_check)
Enable the check that will transform sequences of pairs of tokens that
imply a multiplication operation. The following are some examples of
such transformations:
(a) 2x ---> 2 * x
(b) 25x^3 ---> 25 * x^3
(c) 3(x + 1) ---> 3 * (x + 1)
(d) (x + 1)4 ---> (x + 1) * 4
(e) 5foo(x,y) ---> 5 * foo(x,y)
(f) foo(x,y)6 + 1 ---> foo(x,y) * 6 + 1
(7) Strength Reduction Check (e_strength_reduction)
Enable the use of strength reduction optimisations during the
compilation process. In ExprTk strength reduction optimisations
predominantly involve transforming sub-expressions into other forms
that are algebraically equivalent yet less costly to compute. The
following are examples of the various transformations that can occur:
(a) (x / y) / z ---> x / (y * z)
(b) (x / y) / (z / w) ---> (x * w) / (y * z)
(c) (2 * x) - (2 * y) ---> 2 * (x - y)
(d) (2 / x) / (3 / y) ---> (2 / 3) / (x * y)
(e) (2 * x) * (3 * y) ---> (2 * 3) * (x * y)
Note:
When using strength reduction in conjunction with expressions whose
inputs or sub-expressions may result in values nearing either of the
bounds of the underlying numeric type (eg: double), there may be the
possibility of a decrease in the precision of results.
In the following example the given expression which represents an
attempt at computing the average between x and y will be transformed
as follows:
(x * 0.5) + (y * 0.5) ---> 0.5 * (x + y)
There may be situations where the above transformation will cause
numerical overflows and that the original form of the expression is
desired over the strength reduced form. In these situations it is best
to turn off strength reduction optimisations or to use a type with a
larger numerical bound.
[11 - SPECIAL FUNCTIONS]
The purpose of special functions in ExprTk is to provide compiler The purpose of special functions in ExprTk is to provide compiler
generated equivalents of common mathematical expressions which can be generated equivalents of common mathematical expressions which can be
invoked by using the 'special function' syntax (eg: $f12(x,y,z) or invoked by using the 'special function' syntax (eg: $f12(x,y,z) or
@ -541,7 +658,7 @@ correctly optimize such expressions for a given architecture.
[11 - EXPRTK NOTES] [12 - EXPRTK NOTES]
(00) Precision and performance of expression evaluations are the (00) Precision and performance of expression evaluations are the
dominant principles of the ExprTk library. dominant principles of the ExprTk library.
@ -596,10 +713,9 @@ correctly optimize such expressions for a given architecture.
(15) Where appropriate constant folding optimisations may be (15) Where appropriate constant folding optimisations may be
applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)') applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)')
(16) Where applicable strength reduction optimisations may be (16) If the strength reduction compilation option has been enabled,
applied. The following are example of such optimisations: then where applicable strength reduction optimisations may be
(a) '(x / y) / z' --> 'x / (y * z)' applied.
(b) '(x / 3)' --> 'x * (1 / 3)'
(17) String processing capabilities are available by default. (17) String processing capabilities are available by default.
To turn them off, the following needs to be defined at To turn them off, the following needs to be defined at
@ -614,8 +730,7 @@ correctly optimize such expressions for a given architecture.
(20) The entity relationship between symbol_table and an expression (20) The entity relationship between symbol_table and an expression
is one-to-many. Hence the intended use case is to have a single is one-to-many. Hence the intended use case is to have a single
symbol table manage the variable and function requirements of symbol table manage the variable and function requirements of
multiple expressions. An inappropriate approach would be to have multiple expressions.
a unique symbol table for each unique expression.
(21) The common use-case for an expression is to have it compiled (21) The common use-case for an expression is to have it compiled
only once and then subsequently have it evaluated multiple only once and then subsequently have it evaluated multiple
@ -637,7 +752,7 @@ correctly optimize such expressions for a given architecture.
[12 - SIMPLE EXPRTK EXAMPLE] [13 - SIMPLE EXPRTK EXAMPLE]
--- snip --- --- snip ---
#include <cstdio> #include <cstdio>
#include <string> #include <string>
@ -684,12 +799,18 @@ int main()
if (!parser.compile(expression_str,expression)) if (!parser.compile(expression_str,expression))
{ {
// A compilation error has occured. Attempt to
// print all errors to the stdout.
printf("Error: %s\tExpression: %s\n", printf("Error: %s\tExpression: %s\n",
parser.error().c_str(), parser.error().c_str(),
expression_str.c_str()); expression_str.c_str());
for (std::size_t i = 0; i < parser.error_count(); ++i) for (std::size_t i = 0; i < parser.error_count(); ++i)
{ {
// Include the specific nature of each error
// and its position in the expression string.
error_t error = parser.get_error(i); error_t error = parser.get_error(i);
printf("Error: %02d Position: %02d " printf("Error: %02d Position: %02d "
"Type: [%s] " "Type: [%s] "
@ -705,6 +826,8 @@ int main()
return 1; return 1;
} }
// Evaluate the expression and obtain its result.
double result = expression.value(); double result = expression.value();
printf("Result: %10.5f\n",result); printf("Result: %10.5f\n",result);
@ -715,7 +838,7 @@ int main()
[13 - FILES] [14 - FILES]
(00) Makefile (00) Makefile
(01) readme.txt (01) readme.txt
(02) exprtk.hpp (02) exprtk.hpp