From 953f3aeaad0a2d64d852466395dfcef4aee15b3d Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Fri, 3 Jan 2014 21:42:54 +1100 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- Makefile | 2 +- exprtk.hpp | 132 +++++++++++++++++++++-------------- exprtk_simple_example_09.cpp | 2 +- exprtk_test.cpp | 20 ++++-- readme.txt | 37 ++++++++-- 5 files changed, 126 insertions(+), 67 deletions(-) diff --git a/Makefile b/Makefile index 92c1410..4a7abb2 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ COMPILER = -c++ #COMPILER = -clang OPTIMIZATION_OPT = -O1 -BASE_OPTIONS = -ansi -pedantic-errors -Wall -Wextra -Werror -Wno-long-long +BASE_OPTIONS = -pedantic-errors -Wall -Wextra -Werror -Wno-long-long OPTIONS = $(BASE_OPTIONS) $(OPTIMIZATION_OPT) -o LINKER_OPT = -L/usr/lib -lstdc++ -lm diff --git a/exprtk.hpp b/exprtk.hpp index 694cf64..4cbf75a 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -281,15 +281,15 @@ namespace exprtk static const std::string reserved_symbols[] = { - "abs", "acos", "and", "asin", "atan", "atan2", "avg", "case", "ceil", - "clamp", "cos", "cosh", "cot", "csc", "default", "deg2grad", "deg2rad", - "equal", "erf", "erfc", "exp", "expm1", "false", "floor", "for", "frac", - "grad2deg", "hypot", "if", "ilike", "in", "inrange", "like", "log", "log10", - "log2", "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", "nand", - "nor", "not", "not_equal", "null", "or", "pow", "rad2deg", "repeat", "root", - "round", "roundn", "sec", "sgn", "shl", "shr", "sin", "sinh", "sqrt", "sum", - "switch", "tan", "tanh", "true", "trunc", "until", "while", "xnor", "xor", - "&", "|" + "abs", "acos", "acosh", "and", "asin", "asinh", "atan", "atanh", "atan2", + "avg", "case", "ceil", "clamp", "cos", "cosh", "cot", "csc", "default", + "deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", "expm1", "false", + "floor", "for", "frac", "grad2deg", "hypot", "if", "ilike", "in", "inrange", + "like", "log", "log10", "log2", "logn", "log1p", "mand", "max", "min", "mod", + "mor", "mul", "nand", "nor", "not", "not_equal", "null", "or", "pow", "rad2deg", + "repeat", "root", "round", "roundn", "sec", "sgn", "shl", "shr", "sin", "sinh", + "sqrt", "sum", "switch", "tan", "tanh", "true", "trunc", "until", "while", + "xnor", "xor", "&", "|" }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); @@ -817,8 +817,11 @@ namespace exprtk 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 acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } + template inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } template inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } + template inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - log(T(1) - v)) / T(2); } 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); } @@ -860,8 +863,11 @@ namespace exprtk template inline T frac_impl(const T , int_type_tag) { return T(0); } template inline T trunc_impl(const T v, int_type_tag) { return v; } template inline T acos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T acosh_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 asinh_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 atanh_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(); } @@ -1063,8 +1069,11 @@ namespace exprtk exprtk_define_unary_function(abs ) exprtk_define_unary_function(acos ) + exprtk_define_unary_function(acosh) exprtk_define_unary_function(asin ) + exprtk_define_unary_function(asinh) exprtk_define_unary_function(atan ) + exprtk_define_unary_function(atanh) exprtk_define_unary_function(ceil ) exprtk_define_unary_function(cos ) exprtk_define_unary_function(cosh ) @@ -2909,7 +2918,6 @@ namespace exprtk lexer::token_joiner* error_token_joiner; lexer::token_inserter* error_token_inserter; }; - } } @@ -2926,17 +2934,18 @@ namespace exprtk e_or , e_nor , e_xor , e_xnor , e_mand , e_mor , e_scand , e_scor , e_shr , e_shl , e_abs , e_acos , - e_asin , e_atan , e_ceil , e_cos , - e_cosh , e_exp , e_expm1 , e_floor , - e_log , e_log10 , e_log2 , e_log1p , - e_logn , e_neg , e_pos , e_round , - e_roundn , e_root , e_sqrt , e_sin , - e_sinh , e_sec , e_csc , e_tan , - e_tanh , e_cot , e_clamp , e_inrange , - e_sgn , e_r2d , e_d2r , e_d2g , - e_g2d , e_hypot , e_notl , e_erf , - e_erfc , e_frac , e_trunc , e_assign , - e_in , e_like , e_ilike , e_multi , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_logn , + e_neg , e_pos , e_round , e_roundn , + e_root , e_sqrt , e_sin , e_sinh , + e_sec , e_csc , e_tan , e_tanh , + e_cot , e_clamp , e_inrange , e_sgn , + e_r2d , e_d2r , e_d2g , e_g2d , + e_hypot , e_notl , e_erf , e_erfc , + e_frac , e_trunc , e_assign , e_in , + e_like , e_ilike , e_multi , // Do not add new functions/operators after this point. e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, @@ -3000,8 +3009,11 @@ namespace exprtk { case e_abs : return numeric::abs (arg); case e_acos : return numeric::acos (arg); + case e_acosh : return numeric::acosh(arg); case e_asin : return numeric::asin (arg); + case e_asinh : return numeric::asinh(arg); case e_atan : return numeric::atan (arg); + case e_atanh : return numeric::atanh(arg); case e_ceil : return numeric::ceil (arg); case e_cos : return numeric::cos (arg); case e_cosh : return numeric::cosh (arg); @@ -3167,21 +3179,21 @@ namespace exprtk e_or , e_nor , e_xor , e_xnor , e_in , e_like , e_ilike , e_inranges , e_ipow , e_ipowinv , e_abs , e_acos , - e_asin , e_atan , e_ceil , e_cos , - e_cosh , e_exp , e_expm1 , e_floor , - e_log , e_log10 , e_log2 , e_log1p , - 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 , e_frac , - e_trunc , e_uvouv , e_vov , e_cov , - e_voc , e_vob , e_bov , e_cob , - e_boc , e_vovov , e_vovoc , e_vocov , - e_covov , e_covoc , e_vovovov , e_vovovoc , - e_vovocov , e_vocovov , e_covovov , e_covocov , - e_vocovoc , e_covovoc , e_vococov , e_sf3ext , - e_sf4ext + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , 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 , e_frac , e_trunc , + e_uvouv , e_vov , e_cov , e_voc , + e_vob , e_bov , e_cob , e_boc , + e_vovov , e_vovoc , e_vocov , e_covov , + e_covoc , e_vovovov , e_vovovoc , e_vovocov , + e_vocovov , e_covovov , e_covocov , e_vocovoc , + e_covovoc , e_vococov , e_sf3ext , e_sf4ext }; typedef T value_type; @@ -5172,8 +5184,11 @@ namespace exprtk exprtk_define_unary_op(abs ) exprtk_define_unary_op(acos ) + exprtk_define_unary_op(acosh) exprtk_define_unary_op(asin ) + exprtk_define_unary_op(asinh) exprtk_define_unary_op(atan ) + exprtk_define_unary_op(atanh) exprtk_define_unary_op(ceil ) exprtk_define_unary_op(cos ) exprtk_define_unary_op(cosh ) @@ -8308,8 +8323,11 @@ namespace exprtk register_op( "abs",e_abs , 1) register_op( "acos",e_acos , 1) + register_op( "acosh",e_acosh , 1) register_op( "asin",e_asin , 1) + register_op( "asinh",e_asinh , 1) register_op( "atan",e_atan , 1) + register_op( "atanh",e_atanh , 1) register_op( "ceil",e_ceil , 1) register_op( "cos",e_cos , 1) register_op( "cosh",e_cosh , 1) @@ -12203,23 +12221,24 @@ namespace exprtk 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_expm1 == operation) || (details::e_floor == operation) || - (details::e_log == operation) || (details::e_log10 == operation) || - (details::e_log2 == operation) || (details::e_log1p == 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) || (details::e_frac == operation) || - (details::e_trunc == operation); + (details::e_acosh == operation) || (details::e_asin == operation) || + (details::e_asinh == operation) || (details::e_atan == operation) || + (details::e_atanh == operation) || (details::e_ceil == operation) || + (details::e_cos == operation) || (details::e_cosh == operation) || + (details::e_exp == operation) || (details::e_expm1 == operation) || + (details::e_floor == operation) || (details::e_log == operation) || + (details::e_log10 == operation) || (details::e_log2 == operation) || + (details::e_log1p == 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) || + (details::e_frac == operation) || (details::e_trunc == operation); } inline bool sf3_optimizable(const std::string sf3id, trinary_functor_t& tfunc) @@ -12743,8 +12762,11 @@ namespace exprtk #define unary_opr_switch_statements \ case_stmt(details:: e_abs,details:: abs_op) \ case_stmt(details:: e_acos,details:: acos_op) \ + case_stmt(details::e_acosh,details::acosh_op) \ case_stmt(details:: e_asin,details:: asin_op) \ + case_stmt(details::e_asinh,details::asinh_op) \ case_stmt(details:: e_atan,details:: atan_op) \ + case_stmt(details::e_atanh,details::atanh_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) \ @@ -16816,8 +16838,10 @@ namespace exprtk register_unary_op(details:: e_abs,details:: abs_op) register_unary_op(details:: e_acos,details:: acos_op) + register_unary_op(details::e_acosh,details::acosh_op) register_unary_op(details:: e_asin,details:: asin_op) - register_unary_op(details:: e_atan,details:: atan_op) + register_unary_op(details::e_asinh,details::asinh_op) + register_unary_op(details::e_atanh,details::atanh_op) register_unary_op(details:: e_ceil,details:: ceil_op) register_unary_op(details:: e_cos,details:: cos_op) register_unary_op(details:: e_cosh,details:: cosh_op) diff --git a/exprtk_simple_example_09.cpp b/exprtk_simple_example_09.cpp index b19eb37..e8bb39f 100644 --- a/exprtk_simple_example_09.cpp +++ b/exprtk_simple_example_09.cpp @@ -133,4 +133,4 @@ int main() { primes(); return 0; -} \ No newline at end of file +} diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 4365a01..306f108 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -709,6 +709,12 @@ static const test_t test_list[] = test_t("cos(deg2rad(60))",0.5), test_t("sin(deg2rad(30)) + cos(deg2rad(60))",1.0), test_t("equal(sin(deg2rad(30))/cos(deg2rad(30)),tan(deg2rad(30)))",1.0), + test_t("equal(sinh(pi),11.5487393572577483779773343153884) ",1.0), + test_t("equal(asinh(11.5487393572577483779773343153884),pi)",1.0), + test_t("equal(cosh(pi),11.5919532755215206277517520525601) ",1.0), + test_t("equal(acosh(11.5919532755215206277517520525601),pi)",1.0), + test_t("equal(tanh(pi),0.99627207622074994426469058001253) ",1.0), + test_t("equal(atanh(0.99627207622074994426469058001253),pi)",1.0), test_t("exp(1.0)",2.71828182845904523536028747135266249775724), test_t("exp(0.0)",1.0), test_t("log(2.7182818284590451)",1.0), @@ -1296,7 +1302,7 @@ inline bool run_test01() 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) + frac (y))",T(1.0),T(1.0),T(0.0)), - test_xy("0 * (log1p(x) + expm1(y) )",T(1.0),T(1.0),T(0.0)), + test_xy("0 * (log1p(x) + expm1(y) + acosh(x) + asinh(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)), test_xy("switch { case (x <= y) : (y - x); default: 1.12345; }",T(1.0),T(2.0),T(1.0)), test_xy("switch { case (x > y) : 0; case (x <= y) : (y - x); default: 1.12345; }",T(1.0),T(2.0),T(1.0)), @@ -3990,12 +3996,12 @@ inline bool run_test19() compositor .add("fibonacci2", - "switch " - "{ " - " case x == 0 : 0; " - " case x == 1 : 1; " - " default : fibonacci2(x - 1) + fibonacci2(x - 2);" - "} ", + "switch " + "{ " + " case x == 0 : 0; " + " case x == 1 : 1; " + " default : fibonacci2(x - 1) + fibonacci2(x - 2);" + "} ", "x"); compositor diff --git a/readme.txt b/readme.txt index 2a51d19..2cb291c 100644 --- a/readme.txt +++ b/readme.txt @@ -20,9 +20,9 @@ operations, functions and processes: logn, max, min, mul, nequal, root, round, roundn, sgn, sqrt, sum, trunc -(2) Trigonometry: acos, asin, atan, atan2, cos, cosh, cot, csc, - deg2grad, deg2rad, grad2deg, hypot, rad2deg, - sec, sin, sinh, tan, tanh +(2) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2, + cos, cosh, cot, csc, deg2grad, deg2rad, grad2deg, + hypot, rad2deg, sec, sin, sinh, tan, tanh (3) Equalities & Inequalities: =, ==, <>, !=, <, <=, >, >= @@ -272,13 +272,19 @@ include path (e.g: /usr/include/). +----------+---------------------------------------------------------+ | acos | Arc cosine of x expressed in radians. Interval [-1,+1] | +----------+---------------------------------------------------------+ +| acosh | Inverse hyperbolic cosine of x expressed in radians. | ++----------+---------------------------------------------------------+ | asin | Arc sine of x expressed in radians. Interval [-1,+1] | +----------+---------------------------------------------------------+ +| asinh | Inverse hyperbolic sine of x expressed in radians. | ++----------+---------------------------------------------------------+ | atan | Arc tangent of x expressed in radians. Interval [-1,+1] | +----------+---------------------------------------------------------+ | atan2 | Arc tangent of (x/y) expressed in radians. [-pi,+pi] | | | eg: atan2(x,y) | +----------+---------------------------------------------------------+ +| atanh | Inverse hyperbolic tangent of x expressed in radians. | ++----------+---------------------------------------------------------+ | cos | Cosine of x. | +----------+---------------------------------------------------------+ | cosh | Hyperbolic cosine of x. | @@ -408,7 +414,30 @@ A structure that holds an AST for a specified expression and is used to evaluate said expression. If a compiled Expression uses variables or user defined functions, it will then also have an associated Symbol Table, which will contain references to said variables, functions et -al. +al. An example AST structure for the denoted expression is as follows: + +Expression: z := (x + y^-2.345) * sin(pi / min(w - 7.3,v)) + + [Root] + | + [Assignment] + ________/ \_____ + / \ + Variable(z) [Multiply] + ____________/ \___________ + / \ + / [Unary-Func(sin)] + [Addition] | + ____/ \____ [Division] + / \ ___/ \___ + Variable(x) [Power] / \ + ______/ \______ Constant(pi) [Binary-Func(min)] + / \ ___/ \___ + Variable(y) [Negate] / \ + | [Subtract] Variable(v) + Constant(2.345) ____/ \___ + / \ + Variable(w) Constant(7.3) (3) Parser A structure which takes as input a string representation of an