diff --git a/exprtk.hpp b/exprtk.hpp index 1fc1bd7..aa058bf 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -153,7 +154,8 @@ namespace exprtk static const std::string reserved_words[] = { - "and", "for", "if", "ilike", "in", "like", "nand", "nor", "not", "or", "while", "xor" + "and", "false", "for", "if", "ilike", "in", "like", "nand", "nor", "not", + "or", "true", "while", "xor" }; static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); @@ -161,11 +163,11 @@ namespace exprtk { "abs", "acos", "and", "asin", "atan", "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", "csc", "deg2grad", "deg2rad", "equal", "erf", "erfc", - "exp", "floor", "for", "grad2deg", "hyp", "if", "ilike", "in", "inrange", - "like", "log", "log10", "logn", "max", "min", "mod", "mul", "nand", - "nor", "not", "not_equal", "or", "rad2deg", "root", "round", "roundn", - "sec", "sgn", "shl", "shr", "sin", "sinh", "sqrt", "sum", "tan", "tanh", - "while", "xor" + "exp", "false", "floor", "for", "grad2deg", "hyp", "if", "ilike", "in", + "inrange", "like", "log", "log10", "logn", "max", "min", "mod", "mul", + "nand", "nor", "not", "not_equal", "or", "rad2deg", "root", "round", + "roundn", "sec", "sgn", "shl", "shr", "sin", "sinh", "sqrt", "sum", + "tan", "tanh", "true", "while", "xor" }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); @@ -544,6 +546,58 @@ namespace exprtk return erfc_impl(static_cast(v),real_type_tag()); } + template inline T abs_impl (const T v, real_type_tag) { return std::abs (v); } + template inline T acos_impl (const T v, real_type_tag) { return std::acos (v); } + template inline T asin_impl (const T v, real_type_tag) { return std::asin (v); } + template inline T atan_impl (const T v, real_type_tag) { return std::atan (v); } + template inline T ceil_impl (const T v, real_type_tag) { return std::ceil (v); } + template inline T cos_impl (const T v, real_type_tag) { return std::cos (v); } + template inline T cosh_impl (const T v, real_type_tag) { return std::cosh (v); } + template inline T exp_impl (const T v, real_type_tag) { return std::exp (v); } + template inline T floor_impl(const T v, real_type_tag) { return std::floor(v); } + template inline T log_impl (const T v, real_type_tag) { return std::log (v); } + template inline T log10_impl(const T v, real_type_tag) { return std::log10(v); } + template inline T neg_impl (const T v, real_type_tag) { return -v; } + template inline T pos_impl (const T v, real_type_tag) { return +v; } + template inline T round_impl(const T v, real_type_tag) { return std::floor(v + T(0.5)); } + template inline T sin_impl (const T v, real_type_tag) { return std::sin (v); } + template inline T sinh_impl (const T v, real_type_tag) { return std::sinh (v); } + template inline T sqrt_impl (const T v, real_type_tag) { return std::sqrt (v); } + template inline T tan_impl (const T v, real_type_tag) { return std::tan (v); } + template inline T tanh_impl (const T v, real_type_tag) { return std::tanh (v); } + template inline T cot_impl (const T v, real_type_tag) { return T(1) / std::tan(v); } + template inline T sec_impl (const T v, real_type_tag) { return T(1) / std::cos(v); } + template inline T csc_impl (const T v, real_type_tag) { return T(1) / std::sin(v); } + template inline T r2d_impl (const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } + template inline T d2r_impl (const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } + template inline T d2g_impl (const T v, real_type_tag) { return (v * T(20.0/9.0)); } + template inline T g2d_impl (const T v, real_type_tag) { return (v * T(9.0/20.0)); } + template inline T notl_impl (const T v, real_type_tag) { return (v != T(0) ? T(0) : T(1)); } + + template inline T abs_impl (const T v, int_type_tag) { return std::abs (v); } + template inline T exp_impl (const T v, int_type_tag) { return std::exp (v); } + template inline T log_impl (const T v, int_type_tag) { return std::log (v); } + template inline T log10_impl(const T v, int_type_tag) { return std::log10(v); } + template inline T neg_impl (const T v, int_type_tag) { return -v; } + template inline T pos_impl (const T v, int_type_tag) { return +v; } + template inline T ceil_impl (const T v, int_type_tag) { return v; } + template inline T floor_impl(const T v, int_type_tag) { return v; } + template inline T round_impl(const T v, int_type_tag) { return v; } + template inline T notl_impl (const T v, int_type_tag) { return !v; } + template inline T sqrt_impl (const T v, int_type_tag) { return std::sqrt (v); } + template inline T acos_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T asin_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T atan_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T cos_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T cosh_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T sin_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T sinh_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T tan_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T tanh_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T cot_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T sec_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T csc_impl (const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline bool is_integer_impl(const T& v, real_type_tag) { @@ -643,13 +697,6 @@ namespace exprtk return details::shl_impl(v0,v1,num_type); } - template - inline T sgn(const T& v) - { - typename details::number_type::type num_type; - return details::sgn_impl(v,num_type); - } - template inline T xor_opr(const T& v0, const T& v1) { @@ -657,20 +704,6 @@ namespace exprtk return details::xor_impl(v0,v1,num_type); } - template - inline T erf(const T& v) - { - typename details::number_type::type num_type; - return details::erf_impl(v,num_type); - } - - template - inline T erfc(const T& v) - { - typename details::number_type::type num_type; - return details::erfc_impl(v,num_type); - } - template inline bool is_integer(const T& v) { @@ -711,6 +744,45 @@ namespace exprtk template struct fast_exp { static inline T result(T v) { return v; } }; template struct fast_exp { static inline T result(T ) { return T(1); } }; + #define exprtk_define_unary_function(FunctionName) \ + template \ + inline T FunctionName (const T& v) \ + { \ + typename details::number_type::type num_type; \ + return details:: FunctionName##_impl(v,num_type); \ + } + + exprtk_define_unary_function(abs ) + exprtk_define_unary_function(acos ) + exprtk_define_unary_function(asin ) + exprtk_define_unary_function(atan ) + exprtk_define_unary_function(ceil ) + exprtk_define_unary_function(cos ) + exprtk_define_unary_function(cosh ) + exprtk_define_unary_function(exp ) + exprtk_define_unary_function(floor) + exprtk_define_unary_function(log ) + exprtk_define_unary_function(log10) + exprtk_define_unary_function(neg ) + exprtk_define_unary_function(pos ) + exprtk_define_unary_function(round) + exprtk_define_unary_function(sin ) + exprtk_define_unary_function(sinh ) + exprtk_define_unary_function(sqrt ) + exprtk_define_unary_function(tan ) + exprtk_define_unary_function(tanh ) + exprtk_define_unary_function(cot ) + exprtk_define_unary_function(sec ) + exprtk_define_unary_function(csc ) + exprtk_define_unary_function(r2d ) + exprtk_define_unary_function(d2r ) + exprtk_define_unary_function(d2g ) + exprtk_define_unary_function(g2d ) + exprtk_define_unary_function(notl ) + exprtk_define_unary_function(sgn ) + exprtk_define_unary_function(erf ) + exprtk_define_unary_function(erfc ) + #undef exprtk_define_unary_function } template @@ -758,12 +830,14 @@ namespace exprtk token(token_type ttype, const char* begin, const char* end) : type(ttype), - value(std::string(begin,end)) + value(std::string(begin,end)), + numeric_value(T(0)) {} token(token_type ttype, const std::string& v) : type(ttype), - value(v) + value(v), + numeric_value(T(0)) {} token(token_type ttype, const T& num_val) @@ -919,7 +993,14 @@ namespace exprtk { ++s_itr; } - token_list_.push_back(token_t(token_t::symbol,begin,s_itr)); + static const std::string true_string = "true"; + static const std::string false_string = "false"; + if (details::imatch(std::string(begin,s_itr),true_string)) + token_list_.push_back(token_t(token_t::number,T(1))); + else if (details::imatch(std::string(begin,s_itr),false_string)) + token_list_.push_back(token_t(token_t::number,T(0))); + else + token_list_.push_back(token_t(token_t::symbol,begin,s_itr)); } inline void scan_number() @@ -1511,7 +1592,7 @@ namespace exprtk e_d2g , e_g2d , e_hyp , - e_not , + e_notl , e_erf , e_erfc , e_assign , @@ -1591,36 +1672,36 @@ namespace exprtk { switch (operation) { - case e_abs : return std::abs (arg); - case e_acos : return std::acos (arg); - case e_asin : return std::asin (arg); - case e_atan : return std::atan (arg); - case e_ceil : return std::ceil (arg); - case e_cos : return std::cos (arg); - case e_cosh : return std::cosh (arg); - case e_exp : return std::exp (arg); - case e_floor : return std::floor(arg); - case e_log : return std::log (arg); - case e_log10 : return std::log10(arg); - case e_neg : return -arg; - case e_pos : return +arg; - case e_round : return std::floor(arg + T(0.5)); - case e_sin : return std::sin (arg); - case e_sinh : return std::sinh (arg); - case e_sqrt : return std::sqrt (arg); - case e_tan : return std::tan (arg); - case e_tanh : return std::tanh (arg); - case e_cot : return T(1) / std::tan(arg); - case e_sec : return T(1) / std::cos(arg); - case e_csc : return T(1) / std::sin(arg); - case e_r2d : return (arg * T(numeric::constant::_180_pi)); - case e_d2r : return (arg * T(numeric::constant::pi_180)); - case e_d2g : return (arg * T(20/9)); - case e_g2d : return (arg * T(9/20)); - case e_not : return (arg != T(0) ? T(0) : T(1)); - case e_sgn : return numeric::sgn(arg); - case e_erf : return numeric::erf(arg); - case e_erfc : return numeric::erfc(arg); + case e_abs : return numeric::abs (arg); + case e_acos : return numeric::acos (arg); + case e_asin : return numeric::asin (arg); + case e_atan : return numeric::atan (arg); + case e_ceil : return numeric::ceil (arg); + case e_cos : return numeric::cos (arg); + case e_cosh : return numeric::cosh (arg); + case e_exp : return numeric::exp (arg); + case e_floor : return numeric::floor(arg); + case e_log : return numeric::log (arg); + case e_log10 : return numeric::log10(arg); + case e_neg : return numeric::neg (arg); + case e_pos : return numeric::pos (arg); + case e_round : return numeric::round(arg); + case e_sin : return numeric::sin (arg); + case e_sinh : return numeric::sinh (arg); + case e_sqrt : return numeric::sqrt (arg); + case e_tan : return numeric::tan (arg); + case e_tanh : return numeric::tanh (arg); + case e_cot : return numeric::cot (arg); + case e_sec : return numeric::sec (arg); + case e_csc : return numeric::csc (arg); + case e_r2d : return numeric::r2d (arg); + case e_d2r : return numeric::d2r (arg); + case e_d2g : return numeric::d2g (arg); + case e_g2d : return numeric::g2d (arg); + case e_notl : return numeric::notl (arg); + case e_sgn : return numeric::sgn (arg); + case e_erf : return numeric::erf (arg); + case e_erfc : return numeric::erfc (arg); default : return std::numeric_limits::quiet_NaN(); } } @@ -1630,15 +1711,15 @@ namespace exprtk { switch (operation) { - case e_abs : return std::abs (arg); - case e_exp : return std::exp (arg); - case e_log : return std::log (arg); - case e_log10 : return std::log10(arg); - case e_neg : return -arg; - case e_pos : return +arg; - case e_sqrt : return std::sqrt (arg); - case e_not : return !arg; - case e_sgn : return numeric::sgn(arg); + case e_abs : return numeric::abs (arg); + case e_exp : return numeric::exp (arg); + case e_log : return numeric::log (arg); + case e_log10 : return numeric::log10(arg); + case e_neg : return numeric::neg (arg); + case e_pos : return numeric::pos (arg); + case e_sqrt : return numeric::sqrt (arg); + case e_notl : return numeric::notl (arg); + case e_sgn : return numeric::sgn (arg); default : return std::numeric_limits::quiet_NaN(); } } @@ -2815,6 +2896,47 @@ namespace exprtk std::size_t parameter_count_; }; + #define exprtk_def_unary_op(OpName) \ + template \ + struct OpName##_op \ + { \ + static inline T process(const T& v) { return numeric:: OpName (v); } \ + static inline typename expression_node::node_type type() { return expression_node::e_##OpName; } \ + static inline details::operator_type operation() { return details::e_##OpName; } \ + }; + + exprtk_def_unary_op(abs ) + exprtk_def_unary_op(acos ) + exprtk_def_unary_op(asin ) + exprtk_def_unary_op(atan ) + exprtk_def_unary_op(ceil ) + exprtk_def_unary_op(cos ) + exprtk_def_unary_op(cosh ) + exprtk_def_unary_op(exp ) + exprtk_def_unary_op(floor) + exprtk_def_unary_op(log ) + exprtk_def_unary_op(log10) + exprtk_def_unary_op(neg ) + exprtk_def_unary_op(pos ) + exprtk_def_unary_op(round) + exprtk_def_unary_op(sin ) + exprtk_def_unary_op(sinh ) + exprtk_def_unary_op(sqrt ) + exprtk_def_unary_op(tan ) + exprtk_def_unary_op(tanh ) + exprtk_def_unary_op(cot ) + exprtk_def_unary_op(sec ) + exprtk_def_unary_op(csc ) + exprtk_def_unary_op(r2d ) + exprtk_def_unary_op(d2r ) + exprtk_def_unary_op(d2g ) + exprtk_def_unary_op(g2d ) + exprtk_def_unary_op(notl ) + exprtk_def_unary_op(sgn ) + exprtk_def_unary_op(erf ) + exprtk_def_unary_op(erfc ) + #undef exprtk_def_unary_op + template struct add_op { @@ -3867,7 +3989,7 @@ namespace exprtk operation_t( "deg2grad" , e_d2g , 1), operation_t( "grad2deg" , e_g2d , 1), operation_t( "sgn" , e_sgn , 1), - operation_t( "not" , e_not , 1), + operation_t( "not" , e_notl , 1), operation_t( "erf" , e_erf , 1), operation_t( "erfc" , e_erfc , 1), operation_t( "atan2", e_atan2 , 2), @@ -4042,7 +4164,16 @@ namespace exprtk inline bool is_constant(const std::string& symbol_name) const { - return short_type_lut[static_cast(symbol_name[0])].first; + if (1 == symbol_name.size() && short_type_lut[static_cast(symbol_name[0])].first) + return true; + else + { + tm_const_itr_t itr = map.find(symbol_name); + if (map.end() == itr) + return false; + else + return (*itr).second.first; + } } inline bool add(const std::string& symbol_name, RawType& t, const bool is_constant = false) @@ -4293,8 +4424,26 @@ namespace exprtk #endif type_store,ifunction > function_store; + st_data() + { + for (std::size_t i = 0; i < details::reserved_words_size; ++i) + { + reserved_symbol_table_.insert(details::reserved_words[i]); + } + for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) + { + reserved_symbol_table_.insert(details::reserved_symbols[i]); + } + } + + inline bool is_reserved_symbol(const std::string& symbol) const + { + return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); + } + std::list local_symbol_list_; std::list local_stringvar_list_; + std::set reserved_symbol_table_; }; st_holder() @@ -4641,7 +4790,7 @@ namespace exprtk inline bool symbol_exists(const std::string& symbol_name) const { /* - Will return true if symbol_name exists as either a + Will return true if symbol_name exists as either a reserved symbol, variable, stringvar or function name in any of the type stores. */ if (!valid()) @@ -4654,6 +4803,8 @@ namespace exprtk #endif else if (local_data().function_store.symbol_exists(symbol_name)) return true; + else if (local_data().is_reserved_symbol(symbol_name)) + return true; else return false; } @@ -4710,7 +4861,7 @@ namespace exprtk return false; } } - return true; + return (!local_data().is_reserved_symbol(symbol)); } inline typename st_holder::st_data& local_data() @@ -4728,6 +4879,7 @@ namespace exprtk }; template class parser; + template class expression_helper; template class expression @@ -4880,6 +5032,38 @@ namespace exprtk symbol_table symbol_table_; friend class parser; + friend class expression_helper; + }; + + template + class expression_helper + { + public: + + static inline bool is_head_constant(const expression& expr) + { + return details::is_constant_node(expr.expression_holder_->expr); + } + + static inline bool is_head_variable(const expression& expr) + { + return details::is_variable_node(expr.expression_holder_->expr); + } + + static inline bool is_head_unary(const expression& expr) + { + return details::is_unary_node(expr.expression_holder_->expr); + } + + static inline bool is_head_binary(const expression& expr) + { + return details::is_binary_node(expr.expression_holder_->expr); + } + + static inline bool is_head_function(const expression& expr) + { + return details::is_function(expr.expression_holder_->expr); + } }; template @@ -5406,7 +5590,7 @@ namespace exprtk } else if (symbol_table_.valid()) { - const std::string symbol = current_token_.value; + const std::string& symbol = current_token_.value; //Are we dealing with a variable or a special constant? expression_node_ptr variable = symbol_table_.get_variable(symbol); if (variable) @@ -5908,10 +6092,52 @@ namespace exprtk return node_allocator_->allocate(condition,branch); } + inline expression_node_ptr const_optimize_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + expression_node_ptr temp_node = error_node(); + switch (operation) + { + #define case_stmt(op0,op1) case op0 : temp_node = node_allocator_->allocate > >(operation,branch); break; + case_stmt(details::e_sf00,details::sf00_op) + case_stmt(details::e_sf01,details::sf01_op) + case_stmt(details::e_sf02,details::sf02_op) + case_stmt(details::e_sf03,details::sf03_op) + case_stmt(details::e_sf04,details::sf04_op) + case_stmt(details::e_sf05,details::sf05_op) + case_stmt(details::e_sf06,details::sf06_op) + case_stmt(details::e_sf07,details::sf07_op) + case_stmt(details::e_sf08,details::sf08_op) + case_stmt(details::e_sf09,details::sf09_op) + case_stmt(details::e_sf10,details::sf10_op) + case_stmt(details::e_sf11,details::sf11_op) + case_stmt(details::e_sf12,details::sf12_op) + case_stmt(details::e_sf13,details::sf13_op) + case_stmt(details::e_sf14,details::sf14_op) + case_stmt(details::e_sf15,details::sf15_op) + case_stmt(details::e_sf16,details::sf16_op) + case_stmt(details::e_sf17,details::sf17_op) + case_stmt(details::e_sf18,details::sf18_op) + case_stmt(details::e_sf19,details::sf19_op) + case_stmt(details::e_sf20,details::sf20_op) + case_stmt(details::e_sf21,details::sf21_op) + case_stmt(details::e_sf22,details::sf22_op) + case_stmt(details::e_sf23,details::sf23_op) + case_stmt(details::e_sf24,details::sf24_op) + case_stmt(details::e_sf25,details::sf25_op) + default : return error_node(); + #undef case_stmt + } + T v = temp_node->value(); + node_allocator_->free(temp_node); + return node_allocator_->allocate(v); + } + inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { if (!all_nodes_valid(branch)) return error_node(); + else if (is_constant_foldable(branch)) + return const_optimize_sf3(operation,branch); switch (operation) { #define case_stmt(op0,op1) case op0 : return node_allocator_->allocate > >(operation,branch); @@ -5946,10 +6172,59 @@ namespace exprtk } } + inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + expression_node_ptr temp_node = error_node(); + switch (operation) + { + #define case_stmt(op0,op1) case op0 : temp_node = node_allocator_->allocate > >(operation,branch); break; + case_stmt(details::e_sf26,details::sf26_op) + case_stmt(details::e_sf27,details::sf27_op) + case_stmt(details::e_sf28,details::sf28_op) + case_stmt(details::e_sf29,details::sf29_op) + case_stmt(details::e_sf30,details::sf30_op) + case_stmt(details::e_sf31,details::sf31_op) + case_stmt(details::e_sf32,details::sf32_op) + case_stmt(details::e_sf33,details::sf33_op) + case_stmt(details::e_sf34,details::sf34_op) + case_stmt(details::e_sf35,details::sf35_op) + case_stmt(details::e_sf36,details::sf36_op) + case_stmt(details::e_sf37,details::sf37_op) + case_stmt(details::e_sf38,details::sf38_op) + case_stmt(details::e_sf39,details::sf39_op) + case_stmt(details::e_sf40,details::sf40_op) + case_stmt(details::e_sf41,details::sf41_op) + case_stmt(details::e_sf42,details::sf42_op) + case_stmt(details::e_sf43,details::sf43_op) + case_stmt(details::e_sf44,details::sf44_op) + case_stmt(details::e_sf45,details::sf45_op) + case_stmt(details::e_sf46,details::sf46_op) + case_stmt(details::e_sf47,details::sf47_op) + case_stmt(details::e_sf48,details::sf48_op) + case_stmt(details::e_sf49,details::sf49_op) + case_stmt(details::e_sf50,details::sf50_op) + case_stmt(details::e_sf51,details::sf51_op) + case_stmt(details::e_sf52,details::sf52_op) + case_stmt(details::e_sf53,details::sf53_op) + case_stmt(details::e_sf54,details::sf54_op) + case_stmt(details::e_sf55,details::sf55_op) + case_stmt(details::e_sf56,details::sf56_op) + case_stmt(details::e_sf57,details::sf57_op) + case_stmt(details::e_sf58,details::sf58_op) + default : return error_node(); + #undef case_stmt + } + T v = temp_node->value(); + node_allocator_->free(temp_node); + return node_allocator_->allocate(v); + } + inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) { if (!all_nodes_valid(branch)) return error_node(); + else if (is_constant_foldable(branch)) + return const_optimize_sf4(operation,branch); switch (operation) { #define case_stmt(op0,op1) case op0 : return node_allocator_->allocate > >(operation,branch); diff --git a/exprtk_benchmark.cpp b/exprtk_benchmark.cpp index 6447786..cc4f5a2 100644 --- a/exprtk_benchmark.cpp +++ b/exprtk_benchmark.cpp @@ -35,13 +35,13 @@ const std::string expression_list[] = { "1 - sin(2 * x) + cos(pi / y)", "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", "(x^2 / sin(2 * pi / y)) -x / 2", + "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x" }; const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); - template class Sequence> @@ -85,10 +85,13 @@ void run_benchmark(T& x, T& y, } } timer.stop(); - printf("[exprtk] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n", - timer.time(), - count / timer.time(), - expr_string.c_str()); + if (T(0.0) != total) + printf("[exprtk] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n", + timer.time(), + count / timer.time(), + expr_string.c_str()); + else + std::cerr << "Error - expression: " << expr_string << "\n"; } const double pi = 3.14159265358979323846; @@ -108,20 +111,21 @@ inline T clamp(const T& l, const T& v, const T& u) return (v > u) ? u : v; } -template inline T func00(const T& x, const T& y) { return (y + x); } -template inline T func01(const T& x, const T& y) { return T(2.0) * (y + x); } -template inline T func02(const T& x, const T& y) { return (T(2.0) * y + T(2.0) * x); } -template inline T func03(const T& x, const T& y) { return (y + x / y) * (x - y / x); } -template inline T func04(const T& x, const T& y) { return x / ((x + y) * (x - y)) / y; } -template inline T func05(const T& x, const T& y) { return T(1.0) - ((x * y) + (y / x)) - T(3.0); } -template inline T func06(const T& x, const T& y) { return (1.1*pow(x,T(1.0))+2.2*pow(y,T(2.0))-3.3*pow(x,T(3.0))+4.4*pow(y,T(15.0))-5.5*pow(x,T(23.0))+6.6*pow(y,T(55.0))); } -template inline T func07(const T& x, const T& y) { return std::sin(T(2.0) * x) + std::cos(pi / y); } -template inline T func08(const T& x, const T& y) { return T(1.0) - std::sin(2.0 * x) + std::cos(pi / y); } -template inline T func09(const T& x, const T& y) { return std::sqrt(T(1.0) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(3.0)); } -template inline T func10(const T& x, const T& y) { return (std::pow(x,T(2.0)) / std::sin(T(2.0) * pi / y)) -x / T(2.0); } -template inline T func11(const T& x, const T& y) { return clamp(T(-1.0), std::sin(T(2.0) * pi * x) + std::cos(y / T(2.0) * pi), + T(1.0)); } -template inline T func12(const T& x, const T& y) { return std::max(T(3.33), std::min(sqrt(T(1.0) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(3.0)), T(1.11))); } -template inline T func13(const T& x, const T& y) { return ((avg(x,y) <= x + y) ? x - y : x * y) + T(2.0) * pi / x; } +template inline T func00(const T x, const T y) { return (y + x); } +template inline T func01(const T x, const T y) { return T(2.0) * (y + x); } +template inline T func02(const T x, const T y) { return (T(2.0) * y + T(2.0) * x); } +template inline T func03(const T x, const T y) { return (y + x / y) * (x - y / x); } +template inline T func04(const T x, const T y) { return x / ((x + y) * (x - y)) / y; } +template inline T func05(const T x, const T y) { return T(1.0) - ((x * y) + (y / x)) - T(3.0); } +template inline T func06(const T x, const T y) { return (1.1*pow(x,T(1.0))+2.2*pow(y,T(2.0))-3.3*pow(x,T(3.0))+4.4*pow(y,T(15.0))-5.5*pow(x,T(23.0))+6.6*pow(y,T(55.0))); } +template inline T func07(const T x, const T y) { return std::sin(T(2.0) * x) + std::cos(pi / y); } +template inline T func08(const T x, const T y) { return T(1.0) - std::sin(2.0 * x) + std::cos(pi / y); } +template inline T func09(const T x, const T y) { return std::sqrt(T(1.0) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(3.0)); } +template inline T func10(const T x, const T y) { return (std::pow(x,T(2.0)) / std::sin(T(2.0) * pi / y)) -x / T(2.0); } +template inline T func11(const T x, const T y) { return (x + (std::cos(y - std::sin(2 / x * pi)) - std::sin(x - std::cos(2 * y / pi))) - y); } +template inline T func12(const T x, const T y) { return clamp(T(-1.0), std::sin(T(2.0) * pi * x) + std::cos(y / T(2.0) * pi), + T(1.0)); } +template inline T func13(const T x, const T y) { return std::max(T(3.33), std::min(sqrt(T(1.0) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(3.0)), T(1.11))); } +template inline T func14(const T x, const T y) { return ((avg(x,y) <= x + y) ? x - y : x * y) + T(2.0) * pi / x; } template void run_native_benchmark(T& x, T& y, NativeFunction f, const std::string& expr_string) @@ -142,13 +146,16 @@ void run_native_benchmark(T& x, T& y, NativeFunction f, const std::string& expr_ } } timer.stop(); - printf("[native] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n", - timer.time(), - count / timer.time(), - expr_string.c_str()); + if (T(0.0) != total) + printf("[native] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n", + timer.time(), + count / timer.time(), + expr_string.c_str()); + else + std::cerr << "Error - expression: " << expr_string << "\n"; } -template +template bool run_parse_benchmark(exprtk::symbol_table& symbol_table) { static const std::size_t rounds = 1000000; @@ -229,6 +236,7 @@ int main() run_native_benchmark(x,y,func11,expression_list[11]); run_native_benchmark(x,y,func12,expression_list[12]); run_native_benchmark(x,y,func13,expression_list[13]); + run_native_benchmark(x,y,func14,expression_list[14]); } { diff --git a/exprtk_test.cpp b/exprtk_test.cpp index ef0c42d..4c786b2 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -608,6 +608,26 @@ static const test_t test_list[] = test_t("if((1.0+1.1) >= (2.0+1.2), 3.3, 4.4)",4.4), test_t("if(((1.0 + 2.0) == 3.0) and ((4.0 + 5.0) < 9.0),1,2)",2.0), test_t("(3.0 - 1.0 - 2.0) == ((3.0 - 1.0) - 2.0)",1.0), + test_t("true == true",1.0), + test_t("false == false",1.0), + test_t("true != false",1.0), + test_t("false != true",1.0), + test_t("(1 < 2) == true",1.0), + test_t("(1 > 2) == false",1.0), + test_t("true == (1 < 2)",1.0), + test_t("false == (1 > 2)",1.0), + test_t("(1 > 2) != true",1.0), + test_t("(1 < 2) != false",1.0), + test_t("true != (1 > 2)",1.0), + test_t("false != (1 < 2)",1.0), + test_t("(true and true) == true",1.0), + test_t("(false and false) == false",1.0), + test_t("(true or true) == true",1.0), + test_t("(false or false) == false",1.0), + test_t("(true and false) == false",1.0), + test_t("(false and true) == false",1.0), + test_t("(true or false) == true",1.0), + test_t("(false or true) == true",1.0), test_t("clamp(-1,1,+1)",1.0), test_t("clamp(-1,-1.5,+1.0)",-1.0), test_t("clamp(-1,+1.5,+1.0)",+1.0), @@ -737,6 +757,12 @@ inline bool test_expression(const std::string& expression_string, const T& expec } } + if (!exprtk::expression_helper::is_head_constant(expression)) + { + std::cout << "test_expression() - Error: Expression did not compile to a constant!\tExpression: " << expression_string << std::endl; + return false; + } + T result = expression.value(); if (not_equal(result,expected_result)) { diff --git a/readme.txt b/readme.txt index 8e62a08..c2bccc3 100644 --- a/readme.txt +++ b/readme.txt @@ -25,7 +25,8 @@ operations, functions and processes: (4) Equalities & Inequalities: =, ==, <>, !=, <, <=, >, >=, -(5) Boolean logic: and, or, xor, not, nand, nor, shr, shl +(5) Boolean logic: and, or, xor, not, nand, nor, shr, shl, true, + false (6) Conditional & Loop statement: if-then-else, while