C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html

This commit is contained in:
Arash Partow 2013-03-27 01:20:20 +11:00
parent 9d798d71e5
commit 7103525a7f
3 changed files with 259 additions and 60 deletions

View File

@ -1504,7 +1504,7 @@ namespace exprtk
s_end_ = str.data() + str.size();
eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_);
token_list_.clear();
while (s_end_ != s_itr_)
while (!is_end(s_itr_))
{
scan_token();
if (token_list_.back().is_error())
@ -1564,9 +1564,14 @@ namespace exprtk
private:
inline bool is_end(const char* itr)
{
return (s_end_ == itr);
}
inline void skip_whitespace()
{
while ((s_end_ != s_itr_) && details::is_whitespace(*s_itr_))
while (!is_end(s_itr_) && details::is_whitespace(*s_itr_))
{
++s_itr_;
}
@ -1575,15 +1580,48 @@ namespace exprtk
inline void skip_comments()
{
#ifndef exprtk_disable_comments
if ((s_end_ == s_itr_) || (s_end_ == (s_itr_ + 1)))
//The following comment styles are supported:
// 1. // .... \n
// 2. # .... \n
// 3. /* .... */
struct test
{
static inline bool comment_start(const char c0, const char c1, int& mode, int& incr)
{
mode = 0;
if ('#' == c0) { mode = 1; incr = 1; }
else if ('/' == c0)
{
if ('/' == c1) { mode = 1; incr = 2; }
else if ('*' == c1) { mode = 2; incr = 2; }
}
return (mode != 0);
}
static inline bool comment_end(const char c0, const char c1, const int mode)
{
return ((1 == mode) && ('\n' == c0)) ||
((2 == mode) && ( '*' == c0) && ('/' == c1));
}
};
int mode = 0;
int increment = 0;
if (is_end(s_itr_) || is_end((s_itr_ + 1)))
return;
else if (('/' != *s_itr_) || ('/' != *(s_itr_ + 1)))
else if (!test::comment_start(*s_itr_,*(s_itr_ + 1),mode,increment))
return;
while ((s_end_ != s_itr_) && ('\n' != *s_itr_))
s_itr_ += increment;
while (!is_end(s_itr_) && !test::comment_end(*s_itr_,*(s_itr_ + 1),mode))
{
++s_itr_;
}
if (is_end(s_itr_))
{
s_itr_ += mode;
skip_whitespace();
skip_comments();
}
#endif
}
@ -1591,7 +1629,7 @@ namespace exprtk
{
skip_whitespace();
skip_comments();
if (s_end_ == s_itr_)
if (is_end(s_itr_))
{
return;
}
@ -1635,7 +1673,7 @@ namespace exprtk
{
token_t t;
if ((s_itr_ + 1) != s_end_)
if (!is_end(s_itr_ + 1))
{
token_t::token_type ttype = token_t::e_none;
char c0 = s_itr_[0];
@ -1675,7 +1713,7 @@ namespace exprtk
{
const char* begin = s_itr_;
while (
(s_end_ != s_itr_) &&
(!is_end(s_itr_)) &&
(details::is_letter_or_digit(*s_itr_) || ((*s_itr_) == '_'))
)
{
@ -1705,7 +1743,7 @@ namespace exprtk
bool post_e_sign_found = false;
token_t t;
while (s_end_ != s_itr_)
while (!is_end(s_itr_))
{
if ('.' == (*s_itr_))
{
@ -1723,7 +1761,7 @@ namespace exprtk
{
const char& c = *(s_itr_ + 1);
if (s_end_ == (s_itr_ + 1))
if (is_end(s_itr_ + 1))
{
t.set_error(token::e_err_number,begin,s_itr_,base_itr_);
token_list_.push_back(t);
@ -1778,7 +1816,6 @@ namespace exprtk
{
t.set_error(token::e_err_sfunc,begin,s_itr_,base_itr_);
token_list_.push_back(t);
return;
}
@ -1791,7 +1828,6 @@ namespace exprtk
{
t.set_error(token::e_err_sfunc,begin,s_itr_,base_itr_);
token_list_.push_back(t);
return;
}
@ -1812,14 +1848,13 @@ namespace exprtk
{
t.set_error(token::e_err_string,begin,s_itr_,base_itr_);
token_list_.push_back(t);
return;
}
++s_itr_;
bool escaped = false;
while (s_end_ != s_itr_)
while (!is_end(s_itr_))
{
if ('\\' == *s_itr_)
{
@ -1834,16 +1869,16 @@ namespace exprtk
}
else if (escaped)
escaped = false;
++s_itr_;
}
if (s_end_ == s_itr_)
if (is_end(s_itr_))
{
t.set_error(token::e_err_string,begin,s_itr_,base_itr_);
token_list_.push_back(t);
return;
}
t.set_string(begin,s_itr_,base_itr_);
token_list_.push_back(t);
++s_itr_;
@ -10775,7 +10810,7 @@ namespace exprtk
if (!expr_gen.sf3_optimizable(id,sf3opr))
return false;
else
result = synthesize_sf3ext_expression::process<T0,T1,T2>(expr_gen,sf3opr,t0,t1,t2);
result = synthesize_sf3ext_expression::template process<T0,T1,T2>(expr_gen,sf3opr,t0,t1,t2);
return true;
}
@ -10846,7 +10881,7 @@ namespace exprtk
if (!expr_gen.sf4_optimizable(id,sf4opr))
return false;
else
result = synthesize_sf4ext_expression::process<T0,T1,T2,T3>(expr_gen,sf4opr,t0,t1,t2,t3);
result = synthesize_sf4ext_expression::template process<T0,T1,T2,T3>(expr_gen,sf4opr,t0,t1,t2,t3);
return true;
}
@ -13874,7 +13909,7 @@ namespace exprtk
template <typename T>
inline T derivative(expression<T>& e,
T& x,
const T& h = T(0.00001))
const T& h = T(0.00000001))
{
T x_init = x;
x = x_init + T(2.0) * h;
@ -13889,10 +13924,47 @@ namespace exprtk
return (-y0 + T(8.0) * (y1 - y2) + y3) / (T(12.0) * h);
}
template <typename T>
inline T second_derivative(expression<T>& e,
T& x,
const T& h = T(0.00001))
{
T y = e.value();
T x_init = x;
x = x_init + T(2.0) * h;
T y0 = e.value();
x = x_init + h;
T y1 = e.value();
x = x_init - h;
T y2 = e.value();
x = x_init - T(2.0) * h;
T y3 = e.value();
x = x_init;
return (-y0 + T(16.0) * (y1 + y2) - T(30.0) * y - y3) / (T(12.0) * h * h);
}
template <typename T>
inline T third_derivative(expression<T>& e,
T& x,
const T& h = T(0.0001))
{
T x_init = x;
x = x_init + T(2.0) * h;
T y0 = e.value();
x = x_init + h;
T y1 = e.value();
x = x_init - h;
T y2 = e.value();
x = x_init - T(2.0) * h;
T y3 = e.value();
x = x_init;
return (y0 + T(2.0) * (y2 - y1) - y3) / (T(2.0) * h * h * h);
}
template <typename T>
inline T derivative(expression<T>& e,
const std::string& variable_name,
const T& h = T(0.00001))
const T& h = T(0.00000001))
{
symbol_table<T>& sym_table = e.get_symbol_table();
if (!sym_table.valid())
@ -13904,7 +13976,48 @@ namespace exprtk
T x_original = x;
T result = derivative(e,x,h);
x = x_original;
return result;
}
else
return std::numeric_limits<T>::quiet_NaN();
}
template <typename T>
inline T second_derivative(expression<T>& e,
const std::string& variable_name,
const T& h = T(0.00001))
{
symbol_table<T>& sym_table = e.get_symbol_table();
if (!sym_table.valid())
return std::numeric_limits<T>::quiet_NaN();
details::variable_node<T>* var = sym_table.get_variable(variable_name);
if (var)
{
T& x = var->ref();
T x_original = x;
T result = second_derivative(e,x,h);
x = x_original;
return result;
}
else
return std::numeric_limits<T>::quiet_NaN();
}
template <typename T>
inline T third_derivative(expression<T>& e,
const std::string& variable_name,
const T& h = T(0.0001))
{
symbol_table<T>& sym_table = e.get_symbol_table();
if (!sym_table.valid())
return std::numeric_limits<T>::quiet_NaN();
details::variable_node<T>* var = sym_table.get_variable(variable_name);
if (var)
{
T& x = var->ref();
T x_original = x;
T result = third_derivative(e,x,h);
x = x_original;
return result;
}
else
@ -14016,6 +14129,32 @@ namespace exprtk
template <typename Type, std::size_t NumberOfCoefficients>
struct poly_impl { };
template <typename Type>
struct poly_impl <Type,12>
{
static inline T evaluate(const Type x,
const Type c12, const Type c11, const Type c10, const Type c9, const Type c8,
const Type c7, const Type c6, const Type c5, const Type c4, const Type c3,
const Type c2, const Type c1, const Type c0)
{
// p(x) = c_12x^12 + c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0
return ((((((((((((c12 * x + c11) * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0);
}
};
template <typename Type>
struct poly_impl <Type,11>
{
static inline T evaluate(const Type x,
const Type c11, const Type c10, const Type c9, const Type c8, const Type c7,
const Type c6, const Type c5, const Type c4, const Type c3, const Type c2,
const Type c1, const Type c0)
{
// p(x) = c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0
return ((((((((((( c11 * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0);
}
};
template <typename Type>
struct poly_impl <Type,10>
{
@ -14183,6 +14322,16 @@ namespace exprtk
return ((10 == N) ? poly_impl<T,10>::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
}
inline virtual T operator()(const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0)
{
return ((11 == N) ? poly_impl<T,11>::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
}
inline virtual T operator()(const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0)
{
return ((12 == N) ? poly_impl<T,12>::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
}
inline virtual T operator()()
{
return std::numeric_limits<T>::quiet_NaN();

View File

@ -1498,26 +1498,70 @@ inline bool run_test07()
for (x = T(-200.0); x < T(200); x += T(0.0001))
{
T result1 = exprtk::derivative(expression,x);
T result2 = exprtk::derivative(expression,"x");
T real_result = T(2.0) * std::cos(T(2.0) * x + T(1.0/3.0));
if (not_equal(result1,result2,T(0.000000001)))
{
printf("run_test07() - Derivative Error: result1 != result2\n");
T deriv1_real_result = T(2.0) * std::cos(T(2.0) * x + T(1.0/3.0));
T deriv1_result1 = exprtk::derivative(expression,x);
T deriv1_result2 = exprtk::derivative(expression,"x");
if (not_equal(deriv1_result1,deriv1_result2,T(0.00001)))
{
printf("run_test07() - 1st Derivative Error: result1 != result2\n");
return false;
}
if (not_equal(result1,real_result,T(0.000000001)))
if (not_equal(deriv1_result1,deriv1_real_result,T(0.00001)))
{
printf("run_test07() - Derivative Error: x: %19.15f\tExpected: %19.15f\tResult: %19.15f\n",
printf("run_test07() - 1st Derivative Error: x: %19.15f\tExpected: %19.15f\tResult: %19.15f\n",
x,
real_result,
result1);
deriv1_real_result,
deriv1_result1);
return false;
}
}
{
T deriv2_real_result = T(-4.0) * std::sin(T(2.0) * x + T(1.0/3.0));
T deriv2_result1 = exprtk::second_derivative(expression,x);
T deriv2_result2 = exprtk::second_derivative(expression,"x");
if (not_equal(deriv2_result1,deriv2_result2,T(0.0000001)))
{
printf("run_test07() - 2nd Derivative Error: result1 != result2\n");
return false;
}
if (not_equal(deriv2_result1,deriv2_real_result,T(0.01)))
{
printf("run_test07() - 2nd Derivative Error: x: %19.15f\tExpected: %19.15f\tResult: %19.15f\n",
x,
deriv2_real_result,
deriv2_result1);
return false;
}
}
{
T deriv3_real_result = T(-8.0) * std::cos(T(2.0) * x + T(1.0/3.0));
T deriv3_result1 = exprtk::third_derivative(expression,x);
T deriv3_result2 = exprtk::third_derivative(expression,"x");
if (not_equal(deriv3_result1,deriv3_result2,T(0.0000001)))
{
printf("run_test07() - 3rd Derivative Error: result1 != result2\n");
return false;
}
if (not_equal(deriv3_result1,deriv3_real_result,T(0.01)))
{
printf("run_test07() - 3rd Derivative Error: x: %19.15f\tExpected: %19.15f\tResult: %19.15f\n",
x,
deriv3_real_result,
deriv3_result1);
return false;
}
}
}
return true;
}
@ -2332,15 +2376,18 @@ inline bool run_test12()
typedef exprtk::expression<T> expression_t;
static const std::string expression_string[] =
{
"equal(poly1(x,2.2,1.1),(2.2x^1+1.1))",
"equal(poly2(x,3.3,2.2,1.1),(3.3x^2+2.2x^1+1.1))",
"equal(poly3(x,4.4,3.3,2.2,1.1),(4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly4(x,5.5,4.4,3.3,2.2,1.1),(5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly5(x,6.6,5.5,4.4,3.3,2.2,1.1),(6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly6(x,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly7(x,8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(8.8x^7+7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly8(x,9.9,8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(9.9x^8+8.8x^7+7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly9(x,1.1,9.9,8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(1.1x^9+9.9x^8+8.8x^7+7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))"
"equal(poly01(x,2.2,1.1),(2.2x^1+1.1))",
"equal(poly02(x,3.3,2.2,1.1),(3.3x^2+2.2x^1+1.1))",
"equal(poly03(x,4.4,3.3,2.2,1.1),(4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly04(x,5.5,4.4,3.3,2.2,1.1),(5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly05(x,6.6,5.5,4.4,3.3,2.2,1.1),(6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly06(x,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly07(x,8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(8.8x^7+7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly08(x,9.9,8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(9.9x^8+8.8x^7+7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))",
"equal(poly09(x,1.1,9.9,8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(1.1x^9+9.9x^8+8.8x^7+7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))"
"equal(poly10(x,2.2,1.1,9.9,8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(2.2x^10+1.1x^9+9.9x^8+8.8x^7+7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))"
"equal(poly11(x,3.3,2.2,1.1,9.9,8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(3.3x^11+2.2x^10+1.1x^9+9.9x^8+8.8x^7+7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))"
"equal(poly12(x,4.4,3.3,2.2,1.1,9.9,8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1),(4.4x^12+3.3x^11+2.2x^10+1.1x^9+9.9x^8+8.8x^7+7.7x^6+6.6x^5+5.5x^4+4.4x^3+3.3x^2+2.2x^1+1.1))"
};
static const std::size_t expression_string_size = sizeof(expression_string) / sizeof(std::string);
@ -2356,20 +2403,24 @@ inline bool run_test12()
exprtk::polynomial<T, 8> poly08;
exprtk::polynomial<T, 9> poly09;
exprtk::polynomial<T,10> poly10;
exprtk::polynomial<T,11> poly11;
exprtk::polynomial<T,12> poly12;
exprtk::symbol_table<T> symbol_table;
symbol_table.add_variable("x",x);
symbol_table.add_function( "poly1", poly01);
symbol_table.add_function( "poly2", poly02);
symbol_table.add_function( "poly3", poly03);
symbol_table.add_function( "poly4", poly04);
symbol_table.add_function( "poly5", poly05);
symbol_table.add_function( "poly6", poly06);
symbol_table.add_function( "poly7", poly07);
symbol_table.add_function( "poly8", poly08);
symbol_table.add_function( "poly9", poly09);
symbol_table.add_function("poly01", poly01);
symbol_table.add_function("poly02", poly02);
symbol_table.add_function("poly03", poly03);
symbol_table.add_function("poly04", poly04);
symbol_table.add_function("poly05", poly05);
symbol_table.add_function("poly06", poly06);
symbol_table.add_function("poly07", poly07);
symbol_table.add_function("poly08", poly08);
symbol_table.add_function("poly09", poly09);
symbol_table.add_function("poly10", poly10);
symbol_table.add_function("poly11", poly11);
symbol_table.add_function("poly12", poly12);
expression_t expression;
expression.register_symbol_table(symbol_table);

View File

@ -406,7 +406,7 @@ correctly optimize such expressions for a given architecture.
(10) User defined functions can have up to 20 parameters.
(11) The inbuilt polynomial functions can be at most of degree 10.
(11) The inbuilt polynomial functions can be at most of degree 12.
(12) Where appropriate constant folding optimisations will be
applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)')
@ -415,11 +415,10 @@ correctly optimize such expressions for a given architecture.
To turn them off, the following needs to be defined at
compile time: exprtk_disable_string_capabilities
(14) Expressions may contain trailing comments that must be prefixed
with '//' and are terminated by the next occurrence of new-line
or line-break. To disallow comments, the following needs to be
defined at compile time: exprtk_disable_comments
(eg: '2+(3-(x/y)) // This is an expression')
(14) Expressions may contain any of the following comment styles:
1. // .... \n
2. # .... \n
3. /* .... */