From 187456164ef40e5b864d52e1c389012819d40211 Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Wed, 2 Dec 2015 19:30:27 +1100 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- exprtk.hpp | 328 ++++++++++++++++++++++++++++++++++-------------- exprtk_test.cpp | 36 +++--- readme.txt | 56 ++++----- 3 files changed, 283 insertions(+), 137 deletions(-) diff --git a/exprtk.hpp b/exprtk.hpp index 544cf81..5726160 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -57,7 +57,7 @@ namespace exprtk { - #if exprtk_enable_debugging + #ifdef exprtk_enable_debugging #define exprtk_debug(params) printf params #else #define exprtk_debug(params) (void)0 @@ -678,16 +678,16 @@ namespace exprtk { namespace constant { - static const double e = 2.718281828459045235360; - static const double pi = 3.141592653589793238462; - static const double pi_2 = 1.570796326794896619231; - static const double pi_4 = 0.785398163397448309616; - static const double pi_180 = 0.017453292519943295769; - static const double _1_pi = 0.318309886183790671538; - static const double _2_pi = 0.636619772367581343076; - static const double _180_pi = 57.295779513082320876798; - static const double log2 = 0.693147180559945309417; - static const double sqrt2 = 1.414213562373095048801; + static const double e = 2.71828182845904523536028747135266249775724709369996; + static const double pi = 3.14159265358979323846264338327950288419716939937510; + static const double pi_2 = 1.57079632679489661923132169163975144209858469968755; + static const double pi_4 = 0.78539816339744830961566084581987572104929234984378; + static const double pi_180 = 0.01745329251994329576923690768488612713442871888542; + static const double _1_pi = 0.31830988618379067153776752674502872406891929148091; + static const double _2_pi = 0.63661977236758134307553505349005744813783858296183; + static const double _180_pi = 57.29577951308232087679815481410517033240547246656443; + static const double log2 = 0.69314718055994530941723212145817656807550013436026; + static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695; } namespace details @@ -1760,7 +1760,7 @@ namespace exprtk if (curr != itr) { instate = true; - d += compute_pow10(tmp_d,-std::distance(curr,itr)); + d += compute_pow10(tmp_d,static_cast(-std::distance(curr,itr))); } #undef parse_digit_1 @@ -6733,9 +6733,9 @@ namespace exprtk std::string stringvar_node::null_value = std::string(""); template - class string_range_node : public expression_node , - public string_base_node, - public range_interface + class string_range_node : public expression_node , + public string_base_node, + public range_interface { public: @@ -11600,7 +11600,7 @@ namespace exprtk public: virtual ~boc_base_node() - {} + {} inline virtual operator_type operation() const { @@ -13554,6 +13554,43 @@ namespace exprtk const T& v_; }; + template + class bipow_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipow_node(expression_ptr brnch) + { + init_branches<1>(branch_, brnch); + } + + ~bipow_node() + { + cleanup_branches::execute(branch_); + } + + inline T value() const + { + return PowOp::result(branch_[0].first->value()); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_ipow; + } + + private: + + bipow_node(const bipow_node&); + bipow_node& operator=(const bipow_node&); + + branch_t branch_[1]; + }; + template class ipowinv_node : public expression_node { @@ -13584,6 +13621,43 @@ namespace exprtk const T& v_; }; + template + class bipowninv_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipowninv_node(expression_ptr brnch) + { + init_branches<1>(branch_, brnch); + } + + ~bipowninv_node() + { + cleanup_branches::execute(branch_); + } + + inline T value() const + { + return (T(1) / PowOp::result(branch_[0].first->value())); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_ipowinv; + } + + private: + + bipowninv_node(const bipowninv_node&); + bipowninv_node& operator=(const bipowninv_node&); + + branch_t branch_[1]; + }; + template inline bool is_vov_node(const expression_node* node) { @@ -17139,7 +17213,7 @@ namespace exprtk { st = e_usr_variable_type; default_value = T(0); - error_message = ""; + error_message.clear(); return true; } @@ -17698,7 +17772,7 @@ namespace exprtk settings_store& disable_inequality_operation(settings_inequality_opr inequality) { if ( - (e_assign_unknown != inequality) && + (e_ineq_unknown != inequality) && (static_cast(inequality) < details::inequality_ops_list_size) ) { @@ -20039,7 +20113,7 @@ namespace exprtk return error_node(); } - // Can we optimize away the case statement? + // Can we optimise away the case statement? if (is_constant_node(condition) && is_false(condition)) { free_node(node_allocator_, condition); @@ -20183,7 +20257,7 @@ namespace exprtk return error_node(); } - // Can we optimize away the case statement? + // Can we optimise away the case statement? if (is_constant_node(condition) && is_false(condition)) { free_node(node_allocator_, condition); @@ -23259,7 +23333,7 @@ namespace exprtk } #endif - inline bool unary_optimizable(const details::operator_type& operation) const + inline bool unary_optimisable(const details::operator_type& operation) const { return (details::e_abs == operation) || (details::e_acos == operation) || (details::e_acosh == operation) || (details::e_asin == operation) || @@ -23283,7 +23357,7 @@ namespace exprtk (details::e_frac == operation) || (details::e_trunc == operation); } - inline bool sf3_optimizable(const std::string& sf3id, trinary_functor_t& tfunc) + inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) { typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); @@ -23295,7 +23369,7 @@ namespace exprtk return true; } - inline bool sf4_optimizable(const std::string& sf4id, quaternary_functor_t& qfunc) + inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) { typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); @@ -23307,7 +23381,7 @@ namespace exprtk return true; } - inline bool sf3_optimizable(const std::string& sf3id, details::operator_type& operation) + inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) { typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); @@ -23319,7 +23393,7 @@ namespace exprtk return true; } - inline bool sf4_optimizable(const std::string& sf4id, details::operator_type& operation) + inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) { typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); @@ -23343,9 +23417,9 @@ namespace exprtk return error_node(); else if (details::is_constant_node(branch[0])) return synthesize_expression(operation,branch); - else if (unary_optimizable(operation) && details::is_variable_node(branch[0])) + else if (unary_optimisable(operation) && details::is_variable_node(branch[0])) return synthesize_uv_expression(operation,branch); - else if (unary_optimizable(operation) && details::is_ivector_node(branch[0])) + else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) return synthesize_uvec_expression(operation,branch); else return synthesize_unary_expression(operation,branch); @@ -23413,7 +23487,7 @@ namespace exprtk } } - inline bool operation_optimizable(const details::operator_type& operation) const + inline bool operation_optimisable(const details::operator_type& operation) const { return (details::e_add == operation) || (details::e_sub == operation) || @@ -23481,47 +23555,47 @@ namespace exprtk return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); } - inline bool cov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool cov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { - if (!operation_optimizable(operation)) + if (!operation_optimisable(operation)) return false; else return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1])); } - inline bool voc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { - if (!operation_optimizable(operation)) + if (!operation_optimisable(operation)) return false; else return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1])); } - inline bool vov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { - if (!operation_optimizable(operation)) + if (!operation_optimisable(operation)) return false; else return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); } - inline bool cob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { - if (!operation_optimizable(operation)) + if (!operation_optimisable(operation)) return false; else return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1])); } - inline bool boc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { - if (!operation_optimizable(operation)) + if (!operation_optimisable(operation)) return false; else return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1])); } - inline bool cocob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if ( (details::e_add == operation) || @@ -23537,7 +23611,7 @@ namespace exprtk return false; } - inline bool coboc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool coboc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if ( (details::e_add == operation) || @@ -23553,33 +23627,33 @@ namespace exprtk return false; } - inline bool uvouv_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { - if (!operation_optimizable(operation)) + if (!operation_optimisable(operation)) return false; else return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1])); } - inline bool vob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { - if (!operation_optimizable(operation)) + if (!operation_optimisable(operation)) return false; else return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1])); } - inline bool bov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { - if (!operation_optimizable(operation)) + if (!operation_optimisable(operation)) return false; else return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); } - inline bool binext_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { - if (!operation_optimizable(operation)) + if (!operation_optimisable(operation)) return false; else return (!details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1])); @@ -23605,6 +23679,22 @@ namespace exprtk return false; } + inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) + { + if ( + !is_constant_node(branch[1]) || + is_constant_node(branch[0]) || + is_variable_node(branch[0]) || + is_vector_node (branch[0]) || + is_generally_string_node(branch[0]) + ) + return false; + + const Type c = static_cast*>(branch[1])->value(); + + return cardinal_pow_optimisable(operation, c); + } + inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) { return ( @@ -23750,7 +23840,11 @@ namespace exprtk else if (is_string_operation(operation,branch)) return synthesize_string_expression(operation,branch); else if (is_null_present(branch)) - return synthesize_null_expression(operation,branch); + return synthesize_null_expression(operation, branch); + #ifndef exprtk_disable_cardinal_pow_optimisation + else if (is_constpow_operation(operation, branch)) + return cardinal_pow_optimisation(branch); + #endif expression_node_ptr result = error_node(); @@ -23770,30 +23864,30 @@ namespace exprtk */ result = error_node(); - if (cocob_optimizable(operation,branch)) + if (cocob_optimisable(operation,branch)) result = synthesize_cocob_expression::process(*this,operation,branch); - else if (coboc_optimizable(operation,branch) && (0 == result)) + else if (coboc_optimisable(operation,branch) && (0 == result)) result = synthesize_coboc_expression::process(*this,operation,branch); if (result) return result; } - if (uvouv_optimizable(operation,branch)) + if (uvouv_optimisable(operation,branch)) return synthesize_uvouv_expression(operation,branch); - else if (vob_optimizable(operation,branch)) + else if (vob_optimisable(operation,branch)) return synthesize_vob_expression::process(*this,operation,branch); - else if (bov_optimizable(operation,branch)) + else if (bov_optimisable(operation,branch)) return synthesize_bov_expression::process(*this,operation,branch); - else if (cob_optimizable(operation,branch)) + else if (cob_optimisable(operation,branch)) return synthesize_cob_expression::process(*this,operation,branch); - else if (boc_optimizable(operation,branch)) + else if (boc_optimisable(operation,branch)) return synthesize_boc_expression::process(*this,operation,branch); #ifndef exprtk_disable_enhanced_features - else if (cov_optimizable(operation,branch)) + else if (cov_optimisable(operation,branch)) return synthesize_cov_expression::process(*this,operation,branch); #endif - else if (binext_optimizable(operation,branch)) + else if (binext_optimisable(operation,branch)) return synthesize_binary_ext_expression::process(*this,operation,branch); else return synthesize_expression(operation,branch); @@ -23853,7 +23947,7 @@ namespace exprtk return error_node(); } - // Can the condition be immediately evaluated? if so optimize. + // Can the condition be immediately evaluated? if so optimise. else if (details::is_constant_node(condition)) { // True branch @@ -23899,7 +23993,7 @@ namespace exprtk return error_node(); } - // Can the condition be immediately evaluated? if so optimize. + // Can the condition be immediately evaluated? if so optimise. else if (details::is_constant_node(condition)) { // True branch @@ -23930,9 +24024,9 @@ namespace exprtk return error_node(); } #else - inline expression_node_ptr conditional_string(expression_node_ptr , - expression_node_ptr , - expression_node_ptr ) const + inline expression_node_ptr conditional_string(expression_node_ptr, + expression_node_ptr, + expression_node_ptr) const { return error_node(); } @@ -24055,7 +24149,7 @@ namespace exprtk template class Sequence> - inline expression_node_ptr const_optimize_switch(Sequence& arg_list) + inline expression_node_ptr const_optimise_switch(Sequence& arg_list) { expression_node_ptr result = error_node(); @@ -24091,7 +24185,7 @@ namespace exprtk template class Sequence> - inline expression_node_ptr const_optimize_mswitch(Sequence& arg_list) + inline expression_node_ptr const_optimise_mswitch(Sequence& arg_list) { expression_node_ptr result = error_node(); @@ -24224,7 +24318,7 @@ namespace exprtk return error_node(); } else if (is_constant_foldable(arg_list)) - return const_optimize_switch(arg_list); + return const_optimise_switch(arg_list); switch ((arg_list.size() - 1) / 2) { @@ -24258,7 +24352,7 @@ namespace exprtk return error_node(); } else if (is_constant_foldable(arg_list)) - return const_optimize_mswitch(arg_list); + return const_optimise_mswitch(arg_list); else return node_allocator_->allocate >(arg_list); } @@ -24353,7 +24447,7 @@ namespace exprtk } } - inline expression_node_ptr const_optimize_sf3(const details::operator_type& operation, + inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { expression_node_ptr temp_node = error_node(); @@ -24401,7 +24495,7 @@ namespace exprtk return node_allocator_->allocate(v); } - inline expression_node_ptr varnode_optimize_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { typedef details::variable_node* variable_ptr; @@ -24450,9 +24544,9 @@ namespace exprtk if (!all_nodes_valid(branch)) return error_node(); else if (is_constant_foldable(branch)) - return const_optimize_sf3(operation,branch); + return const_optimise_sf3(operation,branch); else if (all_nodes_variables(branch)) - return varnode_optimize_sf3(operation,branch); + return varnode_optimise_sf3(operation,branch); else { switch (operation) @@ -24491,7 +24585,7 @@ namespace exprtk } } - inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) { expression_node_ptr temp_node = error_node(); @@ -24538,7 +24632,7 @@ namespace exprtk return node_allocator_->allocate(v); } - inline expression_node_ptr varnode_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) { typedef details::variable_node* variable_ptr; @@ -24589,9 +24683,9 @@ namespace exprtk if (!all_nodes_valid(branch)) return error_node(); else if (is_constant_foldable(branch)) - return const_optimize_sf4(operation,branch); + return const_optimise_sf4(operation,branch); else if (all_nodes_variables(branch)) - return varnode_optimize_sf4(operation,branch); + return varnode_optimise_sf4(operation,branch); switch (operation) { #define case_stmt(op0,op1) \ @@ -24631,7 +24725,7 @@ namespace exprtk template class Sequence> - inline expression_node_ptr const_optimize_varargfunc(const details::operator_type& operation, Sequence& arg_list) + inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) { expression_node_ptr temp_node = error_node(); @@ -24674,7 +24768,7 @@ namespace exprtk template class Sequence> - inline expression_node_ptr varnode_optimize_varargfunc(const details::operator_type& operation, Sequence& arg_list) + inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) { switch (operation) { @@ -24731,13 +24825,13 @@ namespace exprtk return error_node(); } else if (is_constant_foldable(arg_list)) - return const_optimize_varargfunc(operation,arg_list); + return const_optimise_varargfunc(operation,arg_list); else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) return vectorize_func(operation,arg_list); else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) return arg_list[0]; else if (all_nodes_variables(arg_list)) - return varnode_optimize_varargfunc(operation,arg_list); + return varnode_optimise_varargfunc(operation,arg_list); switch (operation) { @@ -24768,7 +24862,7 @@ namespace exprtk return error_node(); else { - // Can the function call be completely optimized? + // Can the function call be completely optimised? if (details::is_constant_node(result)) return result; else if (!all_nodes_valid(b)) @@ -25519,8 +25613,8 @@ namespace exprtk case_stmt(details::e_xnor,details::xnor_op) \ #ifndef exprtk_disable_cardinal_pow_optimisation - template