C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html
This commit is contained in:
parent
334953ee4d
commit
71029f7f97
64
exprtk.hpp
64
exprtk.hpp
|
@ -8344,6 +8344,23 @@ namespace exprtk
|
|||
{
|
||||
public:
|
||||
|
||||
typedef range_pack<T> range_pack_t;
|
||||
|
||||
struct range_type
|
||||
{
|
||||
range_type()
|
||||
: range(0),
|
||||
data (0),
|
||||
size (0),
|
||||
type_size(0)
|
||||
{}
|
||||
|
||||
range_pack_t* range;
|
||||
void* data;
|
||||
std::size_t size;
|
||||
std::size_t type_size;
|
||||
};
|
||||
|
||||
typedef type_store<T> type_store_t;
|
||||
typedef expression_node<T>* expression_ptr;
|
||||
typedef variable_node<T> variable_node_t;
|
||||
|
@ -8353,13 +8370,11 @@ namespace exprtk
|
|||
typedef vector_elem_node_t* vector_elem_node_ptr_t;
|
||||
typedef vector_node_t* vector_node_ptr_t;
|
||||
typedef range_interface<T> range_interface_t;
|
||||
typedef range_pack<T> range_pack_t;
|
||||
typedef std::pair<expression_ptr,bool> branch_t;
|
||||
typedef std::pair<void*,std::size_t> void_t;
|
||||
typedef std::pair<range_pack_t*,void_t> range_t;
|
||||
typedef std::vector<T> tmp_vs_t;
|
||||
typedef std::vector<type_store_t> typestore_list_t;
|
||||
typedef std::vector<range_t> range_list_t;
|
||||
typedef std::vector<range_type> range_list_t;
|
||||
|
||||
generic_function_node(GenericFunction* func,
|
||||
const std::vector<expression_ptr>& arg_list)
|
||||
|
@ -8383,8 +8398,7 @@ namespace exprtk
|
|||
{
|
||||
expr_as_vec1_store_.resize(arg_list_.size(),T(0));
|
||||
|
||||
range_list_.resize(arg_list_.size(),
|
||||
range_t((range_pack_t*)0,void_t((void*)0,0)));
|
||||
range_list_.resize(arg_list_.size(),range_type());
|
||||
|
||||
for (std::size_t i = 0; i < arg_list_.size(); ++i)
|
||||
{
|
||||
|
@ -8414,8 +8428,9 @@ namespace exprtk
|
|||
ts.data = reinterpret_cast<void*>(const_cast<char*>(sbn->base()));
|
||||
ts.type = type_store_t::e_string;
|
||||
|
||||
range_list_[i].second.first = ts.data;
|
||||
range_list_[i].second.second = sizeof(char);
|
||||
range_list_[i].data = ts.data;
|
||||
range_list_[i].size = ts.size;
|
||||
range_list_[i].type_size = sizeof(char);
|
||||
|
||||
if (
|
||||
is_string_range_node (arg_list_[i]) ||
|
||||
|
@ -8433,10 +8448,10 @@ namespace exprtk
|
|||
{
|
||||
ts.size = rp.n1_c.second - rp.n0_c.second + 1;
|
||||
ts.data = static_cast<char*>(ts.data) + rp.n0_c.second;
|
||||
range_list_[i].first = reinterpret_cast<range_pack_t*>(0);
|
||||
range_list_[i].range = reinterpret_cast<range_pack_t*>(0);
|
||||
}
|
||||
else
|
||||
range_list_[i].first = &(ri->range_ref());
|
||||
range_list_[i].range = &(ri->range_ref());
|
||||
}
|
||||
}
|
||||
else if (is_variable_node(arg_list_[i]))
|
||||
|
@ -8484,11 +8499,13 @@ namespace exprtk
|
|||
{
|
||||
if (function_)
|
||||
{
|
||||
populate_value_list();
|
||||
return (*function_)(fwd_typestore_list_);
|
||||
if (populate_value_list())
|
||||
{
|
||||
return (*function_)(fwd_typestore_list_);
|
||||
}
|
||||
}
|
||||
else
|
||||
return std::numeric_limits<T>::quiet_NaN();
|
||||
|
||||
return std::numeric_limits<T>::quiet_NaN();
|
||||
}
|
||||
|
||||
inline typename expression_node<T>::node_type type() const
|
||||
|
@ -8498,22 +8515,31 @@ namespace exprtk
|
|||
|
||||
private:
|
||||
|
||||
inline void populate_value_list() const
|
||||
inline bool populate_value_list() const
|
||||
{
|
||||
for (std::size_t i = 0; i < branch_.size(); ++i)
|
||||
{
|
||||
expr_as_vec1_store_[i] = branch_[i].first->value();
|
||||
|
||||
if (range_list_[i].first)
|
||||
if (range_list_[i].range)
|
||||
{
|
||||
range_pack_t& rp = (*range_list_[i].first);
|
||||
range_pack_t& rp = (*range_list_[i].range);
|
||||
std::size_t r0 = 0;
|
||||
std::size_t r1 = 0;
|
||||
|
||||
typestore_list_[i].size = (rp.cache.second - rp.cache.first) + 1;
|
||||
typestore_list_[i].data = static_cast<char*>(range_list_[i].second.first) + (rp.cache.first * range_list_[i].second.second);
|
||||
if (rp(r0,r1,range_list_[i].size))
|
||||
{
|
||||
typestore_list_[i].size = (rp.cache.second - rp.cache.first) + 1;
|
||||
typestore_list_[i].data = static_cast<char*>(range_list_[i].data) + (rp.cache.first * range_list_[i].type_size);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fwd_typestore_list_ = typestore_list_;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GenericFunction* function_;
|
||||
|
@ -12018,6 +12044,7 @@ namespace exprtk
|
|||
|
||||
inline virtual T operator()(const std::vector<T>&)
|
||||
{
|
||||
exprtk_debug(("ivararg_function::operator() - Operator has not been overriden.\n"));
|
||||
return std::numeric_limits<T>::quiet_NaN();
|
||||
}
|
||||
|
||||
|
@ -12044,6 +12071,7 @@ namespace exprtk
|
|||
|
||||
inline virtual T operator()(parameter_list_t&)
|
||||
{
|
||||
exprtk_debug(("igeneric_function::operator() - Operator has not been overriden.\n"));
|
||||
return std::numeric_limits<T>::quiet_NaN();
|
||||
}
|
||||
|
||||
|
|
194
readme.txt
194
readme.txt
|
@ -2,10 +2,10 @@ C++ Mathematical Expression Toolkit Library
|
|||
|
||||
[00 - INTRODUCTION]
|
||||
The C++ Mathematical Expression Toolkit Library (ExprTk) is a simple
|
||||
to use, easy to integrate and extremely efficient mathematical
|
||||
expression parsing and evaluation engine. The parsing engine supports
|
||||
numerous forms of functional and logic processing semantics and is
|
||||
easily extendible.
|
||||
to use, easy to integrate and extremely efficient run-time
|
||||
mathematical expression parsing and evaluation engine. The parsing
|
||||
engine supports numerous forms of functional and logic processing
|
||||
semantics and is easily extendible.
|
||||
|
||||
|
||||
|
||||
|
@ -15,14 +15,14 @@ arithmetic operations, functions and processes:
|
|||
|
||||
(00) Basic operators: +, -, *, /, %, ^
|
||||
|
||||
(01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp,
|
||||
expm1, floor, frac, log, log10, log1p, log2,
|
||||
logn, max, min, mul, ncdf, nequal, root, round,
|
||||
roundn, sgn, sqrt, sum, swap, trunc
|
||||
(01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp,
|
||||
expm1, floor, frac, log, log10, log1p, log2,
|
||||
logn, max, min, mul, ncdf, nequal, root,
|
||||
round, roundn, sgn, sqrt, sum, swap, trunc
|
||||
|
||||
(02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2,
|
||||
cos, cosh, cot, csc, sec, sin, sinc, sinh,
|
||||
tan, tanh, hypot, rad2deg, deg2grad, deg2rad,
|
||||
(02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2,
|
||||
cos, cosh, cot, csc, sec, sin, sinc, sinh,
|
||||
tan, tanh, hypot, rad2deg, deg2grad, deg2rad,
|
||||
grad2deg
|
||||
|
||||
(03) Equalities &
|
||||
|
@ -899,7 +899,7 @@ zero. The following are examples of vector definitions:
|
|||
(c) Initialise all values to given expression
|
||||
var x[3] := [123 + 3y + sin(w/z)];
|
||||
|
||||
(d) Initialise the first two values, other elements to zero
|
||||
(d) Initialise the first two values, all other elements to zero
|
||||
var x[3] := { 1 + x[2], sin(y[0] / x[]) + 3 };
|
||||
|
||||
(e) Initialise the first three (all) values
|
||||
|
@ -1019,7 +1019,8 @@ ExprTk provides a means whereby custom functions can be defined and
|
|||
utilized within expressions. The concept requires the user to
|
||||
provide a reference to the function coupled with an associated name
|
||||
that will be invoked within expressions. Function can take in numerous
|
||||
inputs but will always return one value.
|
||||
inputs but will always return a single value of the underlying numeric
|
||||
type.
|
||||
|
||||
During expression compilation when required the reference to the
|
||||
function will be obtained from the associated symbol_table and be
|
||||
|
@ -1089,7 +1090,9 @@ parameters and their views are as follows:
|
|||
(2) vector - vector_view
|
||||
(3) string - string_view
|
||||
|
||||
The following example defines a generic function called 'too':
|
||||
The above denoted type views provide non-const reference-like access
|
||||
to each parameter. The following example defines a generic function
|
||||
called 'too':
|
||||
|
||||
template <typename T>
|
||||
struct too : public exprtk::igeneric_function<T>
|
||||
|
@ -1104,25 +1107,134 @@ The following example defines a generic function called 'too':
|
|||
{
|
||||
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:
|
||||
In the above example, the input 'parameters' to the function operator,
|
||||
parameter_list_t, 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
|
||||
(1) e_scalar - literals, variables, vector elements, expressions
|
||||
eg: 123.456, x, 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:]
|
||||
(3) e_string - strings, string literals and range variants of both
|
||||
eg: 'AString', s0, 'AString'[x:y], s1[1 + x:]
|
||||
|
||||
|
||||
Each of the parameters can be accessed using its designated view. A
|
||||
typical loop for processing the parameters is as follows:
|
||||
|
||||
inline T operator()(parameter_list_t& parameters)
|
||||
{
|
||||
typedef typename exprtk::igeneric_function<T>::generic_type
|
||||
generic_type;
|
||||
|
||||
typedef typename generic_type::scalar_view scalar_t;
|
||||
typedef typename generic_type::vector_view vector_t;
|
||||
typedef typename generic_type::string_view string_t;
|
||||
|
||||
for (std::size_t i = 0; i < parameters.size(); ++i)
|
||||
{
|
||||
generic_type& gt = parameters[i];
|
||||
|
||||
if (generic_type::e_scalar == gt.type)
|
||||
{
|
||||
scalar_t x(gt);
|
||||
...
|
||||
}
|
||||
else if (generic_type::e_vector == gt.type)
|
||||
{
|
||||
vector_t vector(gt);
|
||||
...
|
||||
}
|
||||
else if (generic_type::e_string == gt.type)
|
||||
{
|
||||
string_t string(gt);
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
return T(0);
|
||||
}
|
||||
|
||||
|
||||
Most often than not a custom generic function will require a specific
|
||||
sequence of parameters, rather than some arbitrary sequence of types.
|
||||
In those situations, ExprTk can perform compile-time type checking to
|
||||
validate that function invocations are carried out using the correct
|
||||
sequence of parameters. Furthermore performing the checks at compile
|
||||
-time rather than at run-time (aka every time the function is invoked)
|
||||
will result expression evaluation performance gains.
|
||||
|
||||
Compile-time type checking can be requested by passing a string
|
||||
representing the desired parameter sequence to the constructor of the
|
||||
igeneric_function. The following example demonstrates how this can be
|
||||
done:
|
||||
|
||||
template <typename T>
|
||||
struct too : public exprtk::igeneric_function<T>
|
||||
{
|
||||
typedef typename exprtk::igeneric_function<T>::parameter_list_t
|
||||
parameter_list_t;
|
||||
|
||||
too()
|
||||
: exprtk::igeneric_function<T>("SVTT")
|
||||
{}
|
||||
|
||||
inline T operator()(parameter_list_t& parameters)
|
||||
{
|
||||
...
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
In the example above the custom generic function 'too' expects
|
||||
exactly four parameters in the following sequence:
|
||||
|
||||
(a) String
|
||||
(b) Vector
|
||||
(c) Scalar
|
||||
(d) Scalar
|
||||
|
||||
|
||||
One further refinement to the type checking facility is possibility of
|
||||
a variable number of trailing common types which can be accomplished
|
||||
by using a wildcard '*' at the end of the sequence definition.
|
||||
|
||||
template <typename T>
|
||||
struct too : public exprtk::igeneric_function<T>
|
||||
{
|
||||
typedef typename exprtk::igeneric_function<T>::parameter_list_t
|
||||
parameter_list_t;
|
||||
|
||||
too()
|
||||
: exprtk::igeneric_function<T>("SVTTV*")
|
||||
{}
|
||||
|
||||
inline T operator()(parameter_list_t& parameters)
|
||||
{
|
||||
...
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
In the example above the generic function 'too' expects at least five
|
||||
parameters in the following sequence:
|
||||
|
||||
(a) String
|
||||
(b) Vector
|
||||
(c) Scalar
|
||||
(d) Scalar
|
||||
(e) One or more vectors
|
||||
|
||||
|
||||
(4) function_compositor
|
||||
|
@ -1173,10 +1285,14 @@ The following demonstrates how all the pieces are put together:
|
|||
|
||||
foo<double> f;
|
||||
boo<double> b;
|
||||
too<double> t;
|
||||
|
||||
symbol_table_t symbol_table;
|
||||
compositor_t compositor(symbol_table);
|
||||
|
||||
symbol_table.add_function("foo",f);
|
||||
symbol_table.add_function("boo",b);
|
||||
symbol_table.add_function("too",t);
|
||||
|
||||
compositor
|
||||
.add(function_t()
|
||||
|
@ -1189,7 +1305,11 @@ The following demonstrates how all the pieces are put together:
|
|||
expression.register_symbol_table(symbol_table);
|
||||
|
||||
std::string expression_str =
|
||||
"foo(1,2,3) + boo(1) / boo(1/2,2/3,3/4,4/5) + koo(3,4)";
|
||||
" if (foo(1,2,3) + boo(1) > boo(1/2,2/3,3/4,4/5)) "
|
||||
" koo(3,4); "
|
||||
" else "
|
||||
" too(2 * v1 + v2 / 3, 'abcdef'[2:4], 3.3); "
|
||||
" ";
|
||||
|
||||
parser_t parser;
|
||||
parser.compile(expression_str,expression);
|
||||
|
@ -1357,14 +1477,14 @@ into account when using Exprtk:
|
|||
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
|
||||
and functions.
|
||||
(05) Supported user defined types are numeric and string
|
||||
variables, numeric vectors and functions.
|
||||
|
||||
(06) All reserved and key words, variable, vector and function names
|
||||
are case-insensitive.
|
||||
(06) All reserved words and keywords, 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
|
||||
(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
|
||||
|
@ -1376,8 +1496,8 @@ into account when using Exprtk:
|
|||
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 and 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
|
||||
|
@ -1398,8 +1518,8 @@ into account when using Exprtk:
|
|||
|
||||
(15) The inbuilt polynomial functions can be at most of degree 12.
|
||||
|
||||
(16) Where appropriate constant folding optimisations may be
|
||||
applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)')
|
||||
(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
|
||||
|
@ -1422,25 +1542,27 @@ into account when using Exprtk:
|
|||
of the ifunction allowing it to be constant folded where
|
||||
appropriate.
|
||||
|
||||
(22) The entity relationship between symbol_table and an expression
|
||||
is one-to-many. Hence the intended use case where possible is
|
||||
to have a single symbol table manage the variable and function
|
||||
(22) The entity relationship between symbol_table and an expression
|
||||
is one-to-many. Hence the intended use case where possible is
|
||||
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
|
||||
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
|
||||
representations:
|
||||
|
||||
(a) 12345 (e) -123.456
|
||||
(b) +123.456e+12 (f) 123.456E-12
|
||||
(c) +012.045e+07 (g) .1234
|
||||
(d) 123.456f (h) -321.654E+3L
|
||||
|
||||
(25) Expressions may contain any of the following comment styles:
|
||||
|
||||
1. // .... \n
|
||||
2. # .... \n
|
||||
3. /* .... */
|
||||
|
|
Loading…
Reference in New Issue