From a60b7646c1041dc65e30bf9a46559866bbe2a640 Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Sat, 21 Apr 2012 09:15:01 +1000 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- exprtk.hpp | 34 ++++++++++++++++++++++++++++-- exprtk_test.cpp | 56 +++++++++++++++++++++++++++++++------------------ 2 files changed, 68 insertions(+), 22 deletions(-) diff --git a/exprtk.hpp b/exprtk.hpp index c853e54..fbe7622 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -142,7 +142,7 @@ namespace exprtk "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", "shl", "shr", "sin", "sinh", "sqrt", "sum", "tan", "tanh", + "sec", "sgn", "shl", "shr", "sin", "sinh", "sqrt", "sum", "tan", "tanh", "while", "xor" }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); @@ -447,6 +447,22 @@ namespace exprtk return v0 << v1; } + template + inline T sgn_impl(const T& v, real_type_tag) + { + if (v > T(0.0)) return T(+1.0); + else if (v < T(0.0)) return T(-1.0); + else return T( 0.0); + } + + template + inline T sgn_impl(const T& v, int_type_tag) + { + if (v > T(0)) return T(+1); + else if (v < T(0)) return T(-1); + else return T( 0); + } + template inline T xor_impl(const T& v0, const T& v1, real_type_tag) { @@ -546,6 +562,13 @@ 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) { @@ -1344,6 +1367,7 @@ namespace exprtk e_cot , e_clamp , e_inrange, + e_sgn , e_r2d , e_d2r , e_d2g , @@ -1437,6 +1461,7 @@ namespace exprtk 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); default : return std::numeric_limits::quiet_NaN(); } } @@ -1454,6 +1479,7 @@ namespace exprtk case e_pos : return +arg; case e_sqrt : return std::sqrt (arg); case e_not : return !arg; + case e_sgn : return numeric::sgn(arg); default : return std::numeric_limits::quiet_NaN(); } } @@ -3403,6 +3429,7 @@ namespace exprtk operation_t( "deg2rad" , e_d2r , 1), 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( "atan2", e_atan2 , 2), operation_t( "min", e_min , 2), @@ -5418,7 +5445,10 @@ namespace exprtk return error_node(); else { - if (!all_nodes_valid(b)) + //has the function call been completely optimized? + if (details::is_constant_node(result)) + return result; + else if (!all_nodes_valid(b)) return error_node(); else if (N != f->param_count) return error_node(); diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 2182878..4bf379e 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -600,6 +600,9 @@ static const test_t test_list[] = test_t("clamp(-1,-1.5,+1.0) + clamp(-1,+1.5,+1.0)",0.0), test_t("inrange(-2,1,+2) == ((-2 <= 1) and (1 <= +2))",1.0), test_t("inrange(-2,1,+2) == if(({-2 <= 1} and [1 <= +2]),1.0,0.0)",1.0), + test_t("sgn( 0)", 0.0), + test_t("sgn(+3)",+1.0), + test_t("sgn(-3)",-1.0), test_t("equal($f00(1.1,2.2,3.3),((1.1+2.2)/3.3))",1.0), test_t("equal($f01(1.1,2.2,3.3),((1.1+2.2)*3.3))",1.0), test_t("equal($f02(1.1,2.2,3.3),((1.1-2.2)/3.3))",1.0), @@ -1365,16 +1368,26 @@ inline bool run_test09() for (std::size_t i = 0; i < rounds; ++i) { typedef exprtk::expression expression_t; - std::string expression_string = "myfunc0(sin(x*pi),y/2)+" - "myfunc1(sin(x*pi),y/2)+" - "myfunc2(sin(x*pi),y/2)+" - "myfunc3(sin(x*pi),y/2)+" - "myfunc4(sin(x*pi),y/2)+" - "myfunc5(sin(x*pi),y/2)+" - "myfunc6(sin(x*pi),y/2)+" - "myfunc7(sin(x*pi),y/2)+" - "myfunc8(sin(x*pi),y/2)+" - "myfunc9(sin(x*pi),y/2)"; + std::string expression_string = "myfunc0(sin(x*pi),y/2)+myfunc1(sin(x*pi),y/2)+" + "myfunc2(sin(x*pi),y/2)+myfunc3(sin(x*pi),y/2)+" + "myfunc4(sin(x*pi),y/2)+myfunc5(sin(x*pi),y/2)+" + "myfunc6(sin(x*pi),y/2)+myfunc7(sin(x*pi),y/2)+" + "myfunc8(sin(x*pi),y/2)+myfunc9(sin(x*pi),y/2)+" + "myfunc0(sin(1*pi),y/2)+myfunc1(sin(1*pi),y/2)+" + "myfunc2(sin(1*pi),y/2)+myfunc3(sin(1*pi),y/2)+" + "myfunc4(sin(1*pi),y/2)+myfunc5(sin(1*pi),y/2)+" + "myfunc6(sin(1*pi),y/2)+myfunc7(sin(1*pi),y/2)+" + "myfunc8(sin(1*pi),y/2)+myfunc9(sin(1*pi),y/2)+" + "myfunc0(sin(x*pi),2/2)+myfunc1(sin(x*pi),2/2)+" + "myfunc2(sin(x*pi),2/2)+myfunc3(sin(x*pi),2/2)+" + "myfunc4(sin(x*pi),2/2)+myfunc5(sin(x*pi),2/2)+" + "myfunc6(sin(x*pi),2/2)+myfunc7(sin(x*pi),2/2)+" + "myfunc8(sin(x*pi),2/2)+myfunc9(sin(x*pi),2/2)+" + "myfunc0(sin(1*pi),2/2)+myfunc1(sin(1*pi),2/2)+" + "myfunc2(sin(1*pi),2/2)+myfunc3(sin(1*pi),2/2)+" + "myfunc4(sin(1*pi),2/2)+myfunc5(sin(1*pi),2/2)+" + "myfunc6(sin(1*pi),2/2)+myfunc7(sin(1*pi),2/2)+" + "myfunc8(sin(1*pi),2/2)+myfunc9(sin(1*pi),2/2)"; T x = T(1.0); T y = T(2.0); @@ -1408,16 +1421,19 @@ inline bool run_test09() const T pi = T(3.14159265358979323846); T result = expression.value(); - T expected = mf(sin(x*pi),y/2.0) + - mf(sin(x*pi),y/2.0) + - mf(sin(x*pi),y/2.0) + - mf(sin(x*pi),y/2.0) + - mf(sin(x*pi),y/2.0) + - mf(sin(x*pi),y/2.0) + - mf(sin(x*pi),y/2.0) + - mf(sin(x*pi),y/2.0) + - mf(sin(x*pi),y/2.0) + - mf(sin(x*pi),y/2.0); + T expected = T(4.0) * + ( + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + + mf(sin(x*pi),y/2.0) + ); if (not_equal(result,expected,0.0000001)) {