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

This commit is contained in:
Arash Partow 2014-11-30 20:48:19 +11:00
parent ce23204895
commit 334953ee4d
3 changed files with 1877 additions and 591 deletions

1750
exprtk.hpp

File diff suppressed because it is too large Load Diff

View File

@ -4419,87 +4419,534 @@ struct va_func : public exprtk::ivararg_function<T>
}
};
template <typename T>
struct gen_func : public exprtk::igeneric_function<T>
{
typedef typename exprtk::igeneric_function<T>::generic_type generic_type;
typedef typename exprtk::igeneric_function<T>::parameter_list_t parameter_list_t;
typedef typename generic_type::scalar_view scalar_t;
typedef typename generic_type::vector_view vector_t;
typedef typename generic_type::string_view string_t;
gen_func()
: scalar_count(0),
vector_count(0),
string_count(0)
{}
inline T operator()(parameter_list_t& params)
{
for (std::size_t i = 0; i < params.size(); ++i)
{
generic_type& gt = params[i];
switch (gt.type)
{
case generic_type::e_scalar : scalar_count++;
break;
case generic_type::e_vector : vector_count++;
break;
case generic_type::e_string : {
if (
("CdEf" != exprtk::to_str(string_t(gt))) &&
("abc123" != exprtk::to_str(string_t(gt)))
)
{
return std::numeric_limits<T>::quiet_NaN();
}
else
string_count++;
}
break;
default : return std::numeric_limits<T>::quiet_NaN();
}
}
return T(0);
}
std::size_t scalar_count;
std::size_t vector_count;
std::size_t string_count;
};
template <typename T>
struct gen_func2 : public exprtk::igeneric_function<T>
{
typedef typename exprtk::igeneric_function<T>::parameter_list_t parameter_list_t;
gen_func2()
{}
inline T operator()(parameter_list_t&)
{
return T(0);
}
};
template <typename T>
struct inc_func : public exprtk::igeneric_function<T>
{
typedef typename exprtk::igeneric_function<T>::generic_type generic_type;
typedef typename exprtk::igeneric_function<T>::parameter_list_t parameter_list_t;
typedef typename generic_type::scalar_view scalar_t;
typedef typename generic_type::vector_view vector_t;
typedef typename generic_type::string_view string_t;
inc_func()
{}
inline T operator()(parameter_list_t& params)
{
for (std::size_t i = 0; i < params.size(); ++i)
{
generic_type& gt = params[i];
switch (gt.type)
{
case generic_type::e_scalar : {
scalar_t scalar(gt);
scalar() += T(1);
}
break;
case generic_type::e_vector : {
vector_t vector(gt);
for (std::size_t x = 0; x < vector.size(); ++x)
{
vector[x] += T(1);
}
}
break;
case generic_type::e_string : {
string_t string(gt);
for (std::size_t x = 0; x < string.size(); ++x)
{
string[x] += static_cast<typename string_t::value_t>(1);
}
}
break;
default : return std::numeric_limits<T>::quiet_NaN();
}
}
return T(0);
}
};
template <typename T>
inline bool run_test18()
{
typedef exprtk::expression<T> expression_t;
T x = T(1.1);
T y = T(2.2);
T z = T(3.3);
T w = T(4.4);
T u = T(5.5);
T v = T(6.6);
T t = T(7.7);
va_func<T> vaf;
exprtk::symbol_table<T> symbol_table;
symbol_table.add_constants();
symbol_table.add_variable("x",x);
symbol_table.add_variable("y",y);
symbol_table.add_variable("z",z);
symbol_table.add_variable("w",w);
symbol_table.add_variable("u",u);
symbol_table.add_variable("v",v);
symbol_table.add_variable("t",t);
symbol_table.add_vararg_function("va_func",vaf);
static const std::string expr_str_list[] =
{
"equal(va_func,(0))",
"equal(va_func(),(0))",
"equal(va_func(1,2,3,4,5,6,7,8,9),(1+2+3+4+5+6+7+8+9))",
"equal(va_func(1,x,3,y,5,z,7,w,9),(1+x+3+y+5+z+7+w+9))",
"equal(va_func(x,2,y,4,z,6,w,8,u),(x+2+y+4+z+6+w+8+u))",
"equal(va_func(x,y,z,w,u,v,t,1,2,3),(x+y+z+w+u+v+t+1+2+3))",
"equal(va_func(x,y,z,w,u,v,t),(x+y+z+w+u+v+t))",
"equal(va_func(x+t,y+v,z+u,w+w,u+z,v+y,t+x),2*(x+y+z+w+u+v+t))",
"equal(1+va_func(1,x,3,y,5,z,7,w,9),(1+x+3+y+5+z+7+w+9)+1)",
"equal(va_func(va_func(x,y,z,w,u,v,t),va_func(x,y,z,w,u,v,t)),2*(x+y+z+w+u+v+t))",
"equal(va_func(va_func(x),va_func(y),va_func(z)),va_func(x,y,z))",
"equal(va_func(va_func(va_func(va_func(va_func(va_func(va_func(va_func(x)))))))),x)",
"equal(va_func(va_func(va_func(va_func(va_func(va_func(va_func(va_func(123.456)))))))),123.456)",
"equal(va_func(va_func(va_func(va_func(va_func(va_func(va_func(va_func(x+1)))))))),x+1)",
"equal(va_func(va_func(va_func(va_func(va_func(va_func(va_func(va_func(x+y)))))))),x+y)"
};
static const std::size_t expr_str_list_size = sizeof(expr_str_list) / sizeof(std::string);
std::deque<expression_t> expression_list;
for (std::size_t i = 0; i < expr_str_list_size; ++i)
{
expression_t expression;
expression.register_symbol_table(symbol_table);
typedef exprtk::expression<T> expression_t;
exprtk::parser<T> parser;
T x = T(1.1);
T y = T(2.2);
T z = T(3.3);
T w = T(4.4);
T u = T(5.5);
T v = T(6.6);
T t = T(7.7);
if (!parser.compile(expr_str_list[i],expression))
va_func<T> vaf;
exprtk::symbol_table<T> symbol_table;
symbol_table.add_constants();
symbol_table.add_variable("x",x);
symbol_table.add_variable("y",y);
symbol_table.add_variable("z",z);
symbol_table.add_variable("w",w);
symbol_table.add_variable("u",u);
symbol_table.add_variable("v",v);
symbol_table.add_variable("t",t);
symbol_table.add_function("va_func",vaf);
static const std::string expr_str_list[] =
{
"equal(va_func,(0))",
"equal(va_func(),(0))",
"equal(va_func(1,2,3,4,5,6,7,8,9),(1+2+3+4+5+6+7+8+9))",
"equal(va_func(1,x,3,y,5,z,7,w,9),(1+x+3+y+5+z+7+w+9))",
"equal(va_func(x,2,y,4,z,6,w,8,u),(x+2+y+4+z+6+w+8+u))",
"equal(va_func(x,y,z,w,u,v,t,1,2,3),(x+y+z+w+u+v+t+1+2+3))",
"equal(va_func(x,y,z,w,u,v,t),(x+y+z+w+u+v+t))",
"equal(va_func(x+t,y+v,z+u,w+w,u+z,v+y,t+x),2*(x+y+z+w+u+v+t))",
"equal(1+va_func(1,x,3,y,5,z,7,w,9),(1+x+3+y+5+z+7+w+9)+1)",
"equal(va_func(va_func(x,y,z,w,u,v,t),va_func(x,y,z,w,u,v,t)),2*(x+y+z+w+u+v+t))",
"equal(va_func(va_func(x),va_func(y),va_func(z)),va_func(x,y,z))",
"equal(va_func(va_func(va_func(va_func(va_func(va_func(va_func(va_func(x)))))))),x)",
"equal(va_func(va_func(va_func(va_func(va_func(va_func(va_func(va_func(123.456)))))))),123.456)",
"equal(va_func(va_func(va_func(va_func(va_func(va_func(va_func(va_func(x+1)))))))),x+1)",
"equal(va_func(va_func(va_func(va_func(va_func(va_func(va_func(va_func(x+y)))))))),x+y)"
};
static const std::size_t expr_str_list_size = sizeof(expr_str_list) / sizeof(std::string);
std::deque<expression_t> expression_list;
for (std::size_t i = 0; i < expr_str_list_size; ++i)
{
printf("run_test18() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
expression_t expression;
expression.register_symbol_table(symbol_table);
exprtk::parser<T> parser;
if (!parser.compile(expr_str_list[i],expression))
{
printf("run_test18() - VarArg Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
return false;
}
else
expression_list.push_back(expression);
}
bool failure = false;
for (std::size_t i = 0; i < expression_list.size(); ++i)
{
if (T(1) != expression_list[i].value())
{
printf("run_test18() - Error in evaluation! (1) Expression: %s\n",
expr_str_list[i].c_str());
failure = true;
}
}
if (failure)
return false;
}
else
expression_list.push_back(expression);
}
bool failure = false;
for (std::size_t i = 0; i < expression_list.size(); ++i)
{
if (T(1) != expression_list[i].value())
{
printf("run_test18() - Error in evaluation! (1) Expression: %s\n",
expr_str_list[i].c_str());
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
failure = true;
T x = T(33);
T y = T(77);
T v0[] = { T(1), T(1), T(1), T(1) };
T v1[] = { T(1), T(2), T(3), T(4) };
std::vector<T> v2;
v2.push_back(T(5));
v2.push_back(T(6));
v2.push_back(T(7));
v2.push_back(T(8));
std::string s0 = "AbCdEfGhIj";
gen_func<T> f;
symbol_table_t symbol_table;
symbol_table.add_constants();
symbol_table.add_variable ("x" , x);
symbol_table.add_variable ("y" , y);
symbol_table.add_vector ("v0" ,v0);
symbol_table.add_vector ("v1" ,v1);
symbol_table.add_vector ("v2" ,v2);
symbol_table.add_stringvar("s0", s0);
symbol_table.add_function ("gen_func", f);
std::string expression_list[] =
{
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x, 2x + y);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func('abc123', s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3, 'abc123');"
};
static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
bool failure = false;
for (std::size_t i = 0; i < expression_list_size; ++i)
{
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
if (!parser.compile(expression_list[i],expression))
{
printf("run_test18() - GenFunc Error: %s Expression: %s\n",
parser.error().c_str(),
expression_list[i].c_str());
failure = true;
continue;
}
f.scalar_count = 0;
f.vector_count = 0;
f.string_count = 0;
expression.value();
if (
(4 != f.scalar_count) ||
(3 != f.vector_count) ||
(2 != f.string_count)
)
{
printf("run_test18() - Error in evaluation! (2) Expression: %s "
"sc_count = %d "
"vr_count = %d "
"st_count = %d\n",
expression_list[i].c_str(),
static_cast<int>(f.scalar_count),
static_cast<int>(f.vector_count),
static_cast<int>(f.string_count));
failure = true;
}
}
if (failure)
return false;
}
return !failure;
{
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
T x = T(33);
T y = T(77);
T v0[] = { T(1), T(1), T(1), T(1) };
T v1[] = { T(1), T(2), T(3), T(4) };
T v2[] = { T(5), T(6), T(7), T(8) };
std::string s0 = "AbCdEfGhIj";
gen_func2<T> f;
symbol_table_t symbol_table;
symbol_table.add_constants();
symbol_table.add_variable ("x" , x);
symbol_table.add_variable ("y" , y);
symbol_table.add_vector ("v0" ,v0);
symbol_table.add_vector ("v1" ,v1);
symbol_table.add_vector ("v2" ,v2);
symbol_table.add_stringvar("s0", s0);
symbol_table.add_function ("foo", f);
std::string expression_list[] =
{
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x, 2x + y);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo('abc123', s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3, 'abc123');"
};
static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
std::string parameter_type_list[] =
{
"VVTTTTVSS",
"VTTTTVSSV",
"TTTTVSSVV",
"TTTVSSVVT",
"TTVSSVVT*",
"TVSSVVT*" ,
"VSSVVT*" ,
"SSVVTTTTV",
"SVVTTTTVS",
};
bool failure = false;
for (std::size_t i = 0; i < expression_list_size; ++i)
{
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
f.parameter_sequence = parameter_type_list[i];
if (!parser.compile(expression_list[i],expression))
{
printf("run_test18() - GenFunc2 Error: %s Expression: %s Parameter Sequence: %s\n",
parser.error().c_str(),
expression_list[i].c_str(),
parameter_type_list[i].c_str());
failure = true;
continue;
}
expression.value();
}
if (failure)
return false;
}
{
bool failure = false;
std::string expression_list[] =
{
"foo(v0,v1,v2,x,y,s0);",
"foo(v1,v2,x,y,s0,v0);",
"foo(v2,x,y,s0,v0,v1);",
"foo(x,y,s0,v0,v1,v2);",
"foo(y,s0,v0,v1,v2,x);",
"foo(s0,v0,v1,v2,x,y);"
};
static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
std::string parameter_type_list[] =
{
"VVVTTS",
"VVTTSV",
"VTTSVV",
"TTSVVV",
"TSVVVT",
"SVVVTT"
};
for (std::size_t i = 0; i < expression_list_size; ++i)
{
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
T x = T(33);
T y = T(77);
T v0[] = { T(1), T(1), T(1), T(1) };
T v1[] = { T(1), T(2), T(3), T(4) };
T v2[] = { T(5), T(6), T(7), T(8) };
std::string s0 = "AbCdEfGhIj";
T x_inc = T(34);
T y_inc = T(78);
T v0_inc[] = { T(2), T(2), T(2), T(2) };
T v1_inc[] = { T(2), T(3), T(4), T(5) };
T v2_inc[] = { T(6), T(7), T(8), T(9) };
std::size_t sizeof_vec = sizeof(v0) / sizeof(T);
std::string s0_inc = "BcDeFgHiJk";
inc_func<T> f;
symbol_table_t symbol_table;
symbol_table.add_constants();
symbol_table.add_variable ("x" , x);
symbol_table.add_variable ("y" , y);
symbol_table.add_vector ("v0" ,v0);
symbol_table.add_vector ("v1" ,v1);
symbol_table.add_vector ("v2" ,v2);
symbol_table.add_stringvar("s0", s0);
symbol_table.add_function ("foo", f);
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
f.parameter_sequence = parameter_type_list[i];
if (!parser.compile(expression_list[i],expression))
{
printf("run_test18() - IncFunc Error: %s Expression: %s Parameter Sequence: %s\n",
parser.error().c_str(),
expression_list[i].c_str(),
parameter_type_list[i].c_str());
failure = true;
continue;
}
expression.value();
if (x != x_inc)
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: x\n",
expression_list[i].c_str());
failure = true;
}
if (y != y_inc)
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: y\n",
expression_list[i].c_str());
failure = true;
}
if (s0 != s0_inc)
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: y\n",
expression_list[i].c_str());
failure = true;
}
if (!std::equal(v0,v0 + sizeof_vec,v0_inc))
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: v0\n",
expression_list[i].c_str());
failure = true;
}
if (!std::equal(v1,v1 + sizeof_vec,v1_inc))
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: v1\n",
expression_list[i].c_str());
failure = true;
}
if (!std::equal(v2,v2 + sizeof_vec,v2_inc))
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: v2\n",
expression_list[i].c_str());
failure = true;
}
}
if (failure)
return false;
}
return true;
}
template <typename T>

View File

@ -618,7 +618,7 @@ current values assigned to the variables will be used.
y = -9.0;
expression.value(); // 3.7 * -9 + 3
// 'x * -9 + 3' for x in range of [0,100] in steps of 0.0001
// 'x * -9 + 3' for x in range of [0,100) in steps of 0.0001
for (var x = 0; x < 100; x += 0.0001)
{
expression.value(); // x * -9 + 3
@ -703,7 +703,7 @@ incorrectly disjoint in the string representation of the specified
expression. For example the consecutive tokens of ">" "=" will become
">=" representing the "greater than or equal to" operator. If not
properly resolved the original form will cause a compilation error.
The following is a listing of the scenarios that the joiner can
The following is a listing of the scenarios that the joiner can
handle:
(a) '>' '=' ---> '>=' (gte)
@ -1029,7 +1029,8 @@ There are two types of function interface:
(1) ifunction
(2) ivararg_function
(3) function_compositor
(3) igeneric_function
(4) function_compositor
(1) ifunction
@ -1075,7 +1076,56 @@ example defines a vararg function called 'boo':
};
(3) function_compositor
(3) igeneric_function
This interface supports a variable number of arguments and types as
input into the function. The function operator interface uses a
std::vector specialized upon the type_store type to facilitate
parameter passing.
The fundamental types that can be passed into the function as
parameters and their views are as follows:
(1) scalar - scalar_view
(2) vector - vector_view
(3) string - string_view
The following example defines a generic function called 'too':
template <typename T>
struct too : public exprtk::igeneric_function<T>
{
typedef typename exprtk::igeneric_function<T>::parameter_list_t
parameter_list_t;
too()
{}
inline T operator()(parameter_list_t& parameters)
{
for (std::size_t i = 0; i < parameters.size(); ++i)
{
}
return T(0);
}
};
In the above example, the parameter_list_t type is a type of
std::vector of type_store. Each type_store instance has a member
called 'type' which holds the enumeration pertaining the underlying
type of the type_store. There are three type enumerations:
(1) e_scalar - variables, vector elements, general expressions
eg: x, y, z, vec[3x + 1], 2x + 3
(2) e_vector - vectors, vector expressions
eg: vec1, 2 * vec1 + vec2 / 3
(3) e_string - string, string literal and range variants of both
eg: 'AString', s0, 'AString'[x:y], s1[1+x:]
(4) function_compositor
The function compositor interface allows a user to define a function
using ExprTk syntax. The functions are limited to returning a single
scalar value and consuming up to six parameters as input.
@ -1126,7 +1176,7 @@ The following demonstrates how all the pieces are put together:
symbol_table_t symbol_table;
symbol_table.add_function("foo",f);
symbol_table.add_vararg_function("boo",b);
symbol_table.add_function("boo",b);
compositor
.add(function_t()
@ -1293,48 +1343,48 @@ via the 'unknown symbol resolver' mechanism.
The following is a list of facts and suggestions one may want to take
into account when using Exprtk:
(00) Precision and performance of expression evaluations are the
(00) Precision and performance of expression evaluations are the
dominant principles of the ExprTk library.
(01) ExprTk uses a rudimentary imperative programming model with
(01) ExprTk uses a rudimentary imperative programming model with
syntax based on languages such as Pascal and C.
(02) Supported types are float, double, long double and MPFR/GMP.
(03) Standard mathematical operator precedence is applied (BEDMAS).
(04) Results of expressions that are deemed as being 'valid' are to
(04) Results of expressions that are deemed as being 'valid' are to
exist within the set of Real numbers. All other results will be
of the value: Not-A-Number (NaN).
(05) Supported user defined types are numeric and string variables
(05) Supported user defined types are numeric and string variables
and functions.
(06) All reserved and key words, variable, vector and function names
are case-insensitive.
(07) Variable, vector and function names must begin with a letter
(A-Z or a-z), then can be comprised of any combination of
(07) Variable, vector and function names must begin with a letter
(A-Z or a-z), then can be comprised of any combination of
letters, digits and underscores. (eg: x, var1 or power_func99)
(08) Expression lengths and sub-expression lists are limited only by
storage capacity.
(09) The life-time of objects registered with or created from a
specific symbol-table must span at least the life-time of the
compiled expressions which utilize objects, such as variables,
of that symbol-table, otherwise the result will be undefined
(09) The life-time of objects registered with or created from a
specific symbol-table must span at least the life-time of the
compiled expressions which utilize objects, such as variables,
of that symbol-table, otherwise the result will be undefined
behavior.
(10) Equal/Nequal are normalized equality routines, which use
epsilons of 0.0000000001 and 0.000001 for double and float
(10) Equal/Nequal are normalized equality routines, which use
epsilons of 0.0000000001 and 0.000001 for double and float
types respectively.
(11) All trigonometric functions assume radian input unless
stated otherwise.
(11) All trigonometric functions assume radian input unless stated
otherwise.
(12) Expressions may contain white-space characters such as
space, tabs, new-lines, control-feed et al.
(12) Expressions may contain white-space characters such as space,
tabs, new-lines, control-feed et al.
('\n', '\r', '\t', '\b', '\v', '\f')
(13) Strings may be comprised of any combination of letters, digits
@ -1342,22 +1392,22 @@ into account when using Exprtk:
and must be enclosed with single-quotes.
eg: 'Frankly my dear, 1 do n0t give a damn!'
(14) User defined normal functions can have up to 20 parameters,
where as user defined vararg-functions can have an unlimited
(14) User defined normal functions can have up to 20 parameters,
where as user defined vararg-functions can have an unlimited
number of parameters.
(15) The inbuilt polynomial functions can be at most of degree 12.
(16) Where appropriate constant folding optimisations may be
(16) Where appropriate constant folding optimisations may be
applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)')
(17) If the strength reduction compilation option has been enabled,
then where applicable strength reduction optimisations may be
applied.
(18) String processing capabilities are available by default.
To turn them off, the following needs to be defined at
compile time: exprtk_disable_string_capabilities
(18) String processing capabilities are available by default. To
turn them off, the following needs to be defined at compile
time: exprtk_disable_string_capabilities
(19) Composited functions can call themselves or any other functions
that have been defined prior to their own definition.
@ -1365,11 +1415,11 @@ into account when using Exprtk:
(20) Recursive calls made from within composited functions will have
a stack size bound by the stack of the executing architecture.
(21) User defined functions by default are assumed to have side
(21) User defined functions by default are assumed to have side
effects. As such an "all constant parameter" invocation of such
functions wont result in constant folding. If the function has
no side effects then that can be noted during the constructor
of the ifunction allowing it to be constant folded where
functions wont result in constant folding. If the function has
no side effects then that can be noted during the constructor
of the ifunction allowing it to be constant folded where
appropriate.
(22) The entity relationship between symbol_table and an expression
@ -1377,10 +1427,10 @@ into account when using Exprtk:
to have a single symbol table manage the variable and function
requirements of multiple expressions.
(23) The common use-case for an expression is to have it compiled
only ONCE and then subsequently have it evaluated multiple
times. An extremely inefficient and suboptimal approach would
be to recompile an expression from its string form every time
(23) The common use-case for an expression is to have it compiled
only ONCE and then subsequently have it evaluated multiple
times. An extremely inefficient and suboptimal approach would
be to recompile an expression from its string form every time
it requires evaluating.
(24) The following are examples of compliant floating point value
@ -1395,10 +1445,11 @@ into account when using Exprtk:
2. # .... \n
3. /* .... */
(26) The 'null' value type is a special non-zero type that
incorporates specific semantics when undergoing operations
with the standard numeric type. The following is a list of
type and boolean results associated with the use of 'null':
(26) The 'null' value type is a special non-zero type that
incorporates specific semantics when undergoing operations with
the standard numeric type. The following is a list of type and
boolean results associated with the use of 'null':
1. null +,-,*,/,% x --> x
2. x +,-,*,/,% null --> x
3. null +,-,*,/,% null --> null
@ -1409,10 +1460,10 @@ into account when using Exprtk:
8. null != null --> false
9. null != x --> false
(27) The following is a list of reserved words and symbols used by
ExprTk. Attempting to add a variable or custom function to a
symbol table using any of the reserved words will result in
a failure.
(27) The following is a list of reserved words and symbols used by
ExprTk. Attempting to add a variable or custom function to a
symbol table using any of the reserved words will result in a
failure.
abs, acos, acosh, and, asin, asinh, atan, atan2, atanh, avg,
break, case, ceil, clamp, continue, cosh, cos, cot, csc,
@ -1426,8 +1477,8 @@ into account when using Exprtk:
while, xnor, xor, xor
(28) Every valid ExprTk statement is a "value returning" expression.
Unlike some languages that limit the types of expressions that
can be performed in certain situations, in ExprTk any valid
Unlike some languages that limit the types of expressions that
can be performed in certain situations, in ExprTk any valid
expression can be used in any "value consuming" context. Eg:
var y := 3;