diff --git a/exprtk.hpp b/exprtk.hpp index aa058bf..49edaf2 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -1861,7 +1861,37 @@ namespace exprtk e_ilike , e_inranges , e_ipow , - e_vov + e_vov , + e_abs , + e_acos , + e_asin , + e_atan , + e_ceil , + e_cos , + e_cosh , + e_exp , + e_floor , + e_log , + e_log10 , + e_neg , + e_pos , + e_round , + e_sin , + e_sinh , + e_sqrt , + e_tan , + e_tanh , + e_cot , + e_sec , + e_csc , + e_r2d , + e_d2r , + e_d2g , + e_g2d , + e_notl , + e_sgn , + e_erf , + e_erfc }; typedef T value_type; @@ -3118,6 +3148,94 @@ namespace exprtk static inline details::operator_type operation() { return details::e_ilike; } }; + template + class unary_variable_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + explicit unary_variable_node(T& v) + : v_(v) + {} + + inline T value() const + { + return Operation::process(v_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline T& v() + { + return v_; + } + + private: + + unary_variable_node(unary_variable_node&); + unary_variable_node& operator=(unary_variable_node&); + + T& v_; + }; + + template + class unary_branch_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + explicit unary_branch_node(expression_ptr branch) + : branch_(branch), + branch_deletable_(branch_deletable(branch_)) + + {} + + ~unary_branch_node() + { + if (branch_ && branch_deletable_) + { + delete branch_; + branch_ = 0; + } + } + + inline T value() const + { + T v = branch_->value(); + return Operation::process(v); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + private: + + unary_branch_node(unary_branch_node&); + unary_branch_node& operator=(unary_branch_node&); + + expression_ptr branch_; + bool branch_deletable_; + }; + template class vov_base_node : public expression_node { @@ -5782,12 +5900,35 @@ namespace exprtk return node_allocator_->allocate(s); } + inline bool unary_optimizable(const details::operator_type& operation) const + { + return (details::e_abs == operation) || (details::e_acos == operation) || + (details::e_asin == operation) || (details::e_atan == operation) || + (details::e_ceil == operation) || (details::e_cos == operation) || + (details::e_cosh == operation) || (details::e_exp == operation) || + (details::e_floor == operation) || (details::e_log == operation) || + (details::e_log10 == operation) || (details::e_neg == operation) || + (details::e_pos == operation) || (details::e_round == operation) || + (details::e_sin == operation) || (details::e_sinh == operation) || + (details::e_sqrt == operation) || (details::e_tan == operation) || + (details::e_tanh == operation) || (details::e_cot == operation) || + (details::e_sec == operation) || (details::e_csc == operation) || + (details::e_r2d == operation) || (details::e_d2r == operation) || + (details::e_d2g == operation) || (details::e_g2d == operation) || + (details::e_notl == operation) || (details::e_sgn == operation) || + (details::e_erf == operation) || (details::e_erfc == operation); + } + inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[1]) { - if (0 != branch[0]) - return synthesize_expression(operation,branch); - else + if (0 == branch[0]) 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])) + return synthesize_uv_expression(operation,branch); + else + return synthesize_unary_expression(operation,branch); } #ifndef exprtk_disable_string_capabilities @@ -6092,6 +6233,87 @@ namespace exprtk return node_allocator_->allocate(condition,branch); } + inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[1]) + { + T& v = dynamic_cast*>(branch[0])->ref(); + switch (operation) + { + #define case_stmt(op0,op1) case op0 : return node_allocator_->allocate > >(v); + case_stmt(details:: e_abs,details:: abs_op) + case_stmt(details:: e_acos,details:: acos_op) + case_stmt(details:: e_asin,details:: asin_op) + case_stmt(details:: e_atan,details:: atan_op) + case_stmt(details:: e_ceil,details:: ceil_op) + case_stmt(details:: e_cos,details:: cos_op) + case_stmt(details:: e_cosh,details:: cosh_op) + case_stmt(details:: e_exp,details:: exp_op) + case_stmt(details::e_floor,details::floor_op) + case_stmt(details:: e_log,details:: log_op) + case_stmt(details::e_log10,details::log10_op) + case_stmt(details:: e_neg,details:: neg_op) + case_stmt(details:: e_pos,details:: pos_op) + case_stmt(details::e_round,details::round_op) + case_stmt(details:: e_sin,details:: sin_op) + case_stmt(details:: e_sinh,details:: sinh_op) + case_stmt(details:: e_sqrt,details:: sqrt_op) + case_stmt(details:: e_tan,details:: tan_op) + case_stmt(details:: e_tanh,details:: tanh_op) + case_stmt(details:: e_cot,details:: cot_op) + case_stmt(details:: e_sec,details:: sec_op) + case_stmt(details:: e_csc,details:: csc_op) + case_stmt(details:: e_r2d,details:: r2d_op) + case_stmt(details:: e_d2r,details:: d2r_op) + case_stmt(details:: e_d2g,details:: d2g_op) + case_stmt(details:: e_g2d,details:: g2d_op) + case_stmt(details:: e_notl,details:: notl_op) + case_stmt(details:: e_sgn,details:: sgn_op) + case_stmt(details:: e_erf,details:: erf_op) + case_stmt(details:: e_erfc,details:: erfc_op) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, expression_node_ptr (&branch)[1]) + { + switch (operation) + { + #define case_stmt(op0,op1) case op0 : return node_allocator_->allocate > >(branch[0]); + case_stmt(details:: e_abs,details:: abs_op) + case_stmt(details:: e_acos,details:: acos_op) + case_stmt(details:: e_asin,details:: asin_op) + case_stmt(details:: e_atan,details:: atan_op) + case_stmt(details:: e_ceil,details:: ceil_op) + case_stmt(details:: e_cos,details:: cos_op) + case_stmt(details:: e_cosh,details:: cosh_op) + case_stmt(details:: e_exp,details:: exp_op) + case_stmt(details::e_floor,details::floor_op) + case_stmt(details:: e_log,details:: log_op) + case_stmt(details::e_log10,details::log10_op) + case_stmt(details:: e_neg,details:: neg_op) + case_stmt(details:: e_pos,details:: pos_op) + case_stmt(details::e_round,details::round_op) + case_stmt(details:: e_sin,details:: sin_op) + case_stmt(details:: e_sinh,details:: sinh_op) + case_stmt(details:: e_sqrt,details:: sqrt_op) + case_stmt(details:: e_tan,details:: tan_op) + case_stmt(details:: e_tanh,details:: tanh_op) + case_stmt(details:: e_cot,details:: cot_op) + case_stmt(details:: e_sec,details:: sec_op) + case_stmt(details:: e_csc,details:: csc_op) + case_stmt(details:: e_r2d,details:: r2d_op) + case_stmt(details:: e_d2r,details:: d2r_op) + case_stmt(details:: e_d2g,details:: d2g_op) + case_stmt(details:: e_g2d,details:: g2d_op) + case_stmt(details:: e_notl,details:: notl_op) + case_stmt(details:: e_sgn,details:: sgn_op) + case_stmt(details:: e_erf,details:: erf_op) + case_stmt(details:: e_erfc,details:: erfc_op) + #undef case_stmt + default : return error_node(); + } + } + inline expression_node_ptr const_optimize_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { expression_node_ptr temp_node = error_node(); @@ -6124,8 +6346,8 @@ namespace exprtk 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 + default : return error_node(); } T v = temp_node->value(); node_allocator_->free(temp_node); @@ -6167,8 +6389,8 @@ namespace exprtk 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 + default : return error_node(); } } @@ -6211,8 +6433,8 @@ namespace exprtk 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 + default : return error_node(); } T v = temp_node->value(); node_allocator_->free(temp_node); @@ -6261,8 +6483,8 @@ namespace exprtk 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 + default : return error_node(); } } @@ -6362,8 +6584,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } } @@ -6394,8 +6616,8 @@ namespace exprtk case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) - default : return error_node(); #undef case_stmt + default : return error_node(); } } } @@ -6448,8 +6670,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } } @@ -6479,8 +6701,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } } @@ -6510,8 +6732,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } } @@ -6541,8 +6763,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } node_allocator_->free(branch[1]); return result; @@ -6574,8 +6796,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } } @@ -6605,8 +6827,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } node_allocator_->free(branch[0]); return result; @@ -6638,8 +6860,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } } @@ -6669,8 +6891,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } node_allocator_->free(branch[1]); return result; @@ -6702,8 +6924,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } } @@ -6733,8 +6955,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } node_allocator_->free(branch[0]); return result; @@ -6767,8 +6989,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } #else template @@ -6805,8 +7027,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } } #else @@ -6843,8 +7065,8 @@ namespace exprtk case_stmt(details:: e_nor,details:: nor_op) case_stmt(details:: e_xor,details:: xor_op) #endif - default : return error_node(); #undef case_stmt + default : return error_node(); } node_allocator_->free(branch[0]); node_allocator_->free(branch[1]); @@ -6873,8 +7095,8 @@ namespace exprtk case_stmt(details::e_in ,details:: in_op) case_stmt(details::e_like ,details:: like_op) case_stmt(details::e_ilike,details::ilike_op) - default : return error_node(); #undef case_stmt + default : return error_node(); } } diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 4c786b2..5d8494d 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -963,7 +963,14 @@ inline bool run_test01() test_xy("equal(y^-22,1/(y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y))",T(0.0),T(12.34),T(1.0)), test_xy("equal(y^-23,1/(y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y))",T(0.0),T(12.34),T(1.0)), test_xy("equal(y^-24,1/(y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y))",T(0.0),T(12.34),T(1.0)), - test_xy("equal(y^-25,1/(y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y))",T(0.0),T(12.34),T(1.0)) + test_xy("equal(y^-25,1/(y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y*y))",T(0.0),T(12.34),T(1.0)), + test_xy("0 * (abs (x) + acos (y) + asin (x) + atan (y))",T(1.0),T(1.0),T(0.0)), + test_xy("0 * (ceil (x) + cos (y) + cosh (x) + exp (y))",T(1.0),T(1.0),T(0.0)), + test_xy("0 * (floor(x) + log (y) + log10(x) + round(y))",T(1.0),T(1.0),T(0.0)), + test_xy("0 * (sin (x) + sinh (y) + sqrt (x) + tan (y))",T(1.0),T(1.0),T(0.0)), + test_xy("0 * (sec (x) + csc (y) + tanh (x) + cot (y))",T(1.0),T(1.0),T(0.0)), + test_xy("0 * (erf (x) + erfc (y) + sgn (y) )",T(1.0),T(1.0),T(0.0)), + test_xy("0 * (deg2grad(x) + grad2deg(y) + rad2deg(x) + deg2rad(y))",T(1.0),T(1.0),T(0.0)), }; static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xy); diff --git a/readme.txt b/readme.txt index c2bccc3..4e6000c 100644 --- a/readme.txt +++ b/readme.txt @@ -8,6 +8,7 @@ kinds of functional, logic processing semantics and is very easily extendible. + [CAPABILITIES] The ExprTk evaluator supports the following fundamental mathematical operations, functions and processes: @@ -34,6 +35,7 @@ operations, functions and processes: (7) Assigment: := + [EXAMPLE EXPRESSIONS] The following is a short sample of the types of mathematical expressions that can be parsed and evaluated using the ExprTk library. @@ -60,6 +62,7 @@ expressions that can be parsed and evaluated using the ExprTk library. (20) (x like '*123*') or ('a123b' ilike y) + [COPYRIGHT NOTICE] Free use of the Mathematical Expression Toolkit Library is permitted under the guidelines and in accordance with the most current version @@ -68,6 +71,7 @@ of the Common Public License. http://www.opensource.org/licenses/cpl1.0.php + [DOWNLOADS & UPDATES] All updates and the most recent version of the C++ Mathematical Expression Library can be found at: @@ -75,17 +79,20 @@ Expression Library can be found at: (2) svn checkout http://exprtk.googlecode.com/svn/ exprtk + [INSTALLATION] (1) exprtk.hpp should be placed in a project or system include path (e.g: /usr/include/). + [COMPILATION] (1) For a complete build: make clean all (2) For a PGO build: make clean pgo (3) To strip executables: make strip_bin + [COMPILER COMPATIBILITY] (*) GNU Compiler Collection (4.3+) (*) Intel® C++ Compiler (9.x+) @@ -94,6 +101,7 @@ Expression Library can be found at: (*) Comeau C++ Compiler (4.3+) + [SPECIAL FUNCTIONS] The purpose of special functions in ExprTk is to provide compiler generated equivalents of common mathematical expressions which can be @@ -144,6 +152,7 @@ correctly optimize such expressions for a given architecture. sf58(x,y,z,w) | x * y^9 + z * w^9 + [MACROS] ExprTk utilizes certain macros to modify the underlying behaviour of the parser and the evaluation engine. The following macros are used to @@ -194,6 +203,11 @@ both modes [3] and [4]. The mode when this macro is defined, is 'lean and mean' coupled with all string capabilities disabled [1]. +Note: Foregoing a few extra clock cycles during compilation in +exchange for a dramatic increase in performance during run-time is +always a worthy undertaking. + + [FILES] (00) Makefile