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

This commit is contained in:
Arash Partow 2012-03-14 07:12:58 +11:00
parent a420147e7a
commit 64a4f623a3
4 changed files with 2951 additions and 436 deletions

View File

@ -23,15 +23,23 @@ OPTIONS = $(BASE_OPTIONS) $(OPTIMIZATION_OPT) -o
LINKER_OPT = -L/usr/lib -lstdc++ LINKER_OPT = -L/usr/lib -lstdc++
BUILD_LIST+=exprtk_test BUILD_LIST+=exprtk_test
BUILD_LIST+=exprtk_benchmark
all: $(BUILD_LIST) all: $(BUILD_LIST)
exprtk_test: exprtk_test.cpp exprtk.hpp exprtk_test: exprtk_test.cpp exprtk.hpp
$(COMPILER) $(OPTIONS) exprtk_test exprtk_test.cpp $(LINKER_OPT) $(COMPILER) $(OPTIONS) exprtk_test exprtk_test.cpp $(LINKER_OPT)
exprtk_benchmark: exprtk_benchmark.cpp exprtk.hpp
$(COMPILER) $(OPTIONS) exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT)
pgo: exprtk_test.cpp exprtk.hpp pgo: exprtk_test.cpp exprtk_benchmark.cpp exprtk.hpp
$(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_test exprtk_test.cpp $(LINKER_OPT) $(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_test exprtk_test.cpp $(LINKER_OPT)
$(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT)
./exprtk_test
./exprtk_benchmark
$(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-use -o exprtk_test exprtk_test.cpp $(LINKER_OPT)
$(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-use -o exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT)
strip_bin: strip_bin:
strip -s exprtk_test strip -s exprtk_test

3138
exprtk.hpp

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,8 @@ typedef std::pair<std::string,double> test_t;
static const test_t test_list[] = static const test_t test_list[] =
{ {
// Note: The each of following tests should
// all compile down to a single literal node.
test_t("0",0.0), test_t("0",0.0),
test_t("1",1.0), test_t("1",1.0),
test_t("2",2.0), test_t("2",2.0),
@ -37,6 +39,11 @@ static const test_t test_list[] =
test_t("7",7.0), test_t("7",7.0),
test_t("8",8.0), test_t("8",8.0),
test_t("9",9.0), test_t("9",9.0),
test_t("12.12",12.12),
test_t("123.123",123.123),
test_t("1234.1234",1234.1234),
test_t("12345.12345",12345.12345),
test_t("123456.123456",123456.123456),
test_t("0.0",0.0), test_t("0.0",0.0),
test_t("1.0",1.0), test_t("1.0",1.0),
test_t("2.0",2.0), test_t("2.0",2.0),
@ -666,7 +673,7 @@ static const test_t test_list[] =
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_t); static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_t);
template<typename T> template <typename T>
inline bool not_equal(const T& t1, inline bool not_equal(const T& t1,
const T& t2, const T& t2,
const T& epsilon = 0.0000000001/*std::numeric_limits<T>::epsilon()*/) const T& epsilon = 0.0000000001/*std::numeric_limits<T>::epsilon()*/)
@ -676,7 +683,7 @@ inline bool not_equal(const T& t1,
return std::abs(t1 - t2) > (std::max(T(1.0),std::max(std::abs(t1),std::abs(t2))) * epsilon); return std::abs(t1 - t2) > (std::max(T(1.0),std::max(std::abs(t1),std::abs(t2))) * epsilon);
} }
template<typename T> template <typename T>
inline bool test_expression(const std::string& expression_string, const T& expected_result) inline bool test_expression(const std::string& expression_string, const T& expected_result)
{ {
exprtk::expression<T> expression; exprtk::expression<T> expression;
@ -707,10 +714,10 @@ inline bool test_expression(const std::string& expression_string, const T& expec
return true; return true;
} }
template<typename T> template <typename T>
inline bool run_test0() inline bool run_test0()
{ {
const std::size_t rounds = 10000; const std::size_t rounds = 100;
for (std::size_t r = 0; r < rounds; ++r) for (std::size_t r = 0; r < rounds; ++r)
{ {
for (std::size_t i = 0; i < test_list_size; ++i) for (std::size_t i = 0; i < test_list_size; ++i)
@ -722,8 +729,112 @@ inline bool run_test0()
return true; return true;
} }
template<typename T> template<typename T>
struct test_xy
{
test_xy(std::string e, const T& v0, const T& v1, const T& r)
: expr(e),
x(v0),
y(v1),
result(r)
{}
std::string expr;
T x;
T y;
T result;
};
template <typename T>
inline bool run_test1() inline bool run_test1()
{
static const test_xy<T> test_list[] =
{
test_xy<T>("x + y" ,T(2.2),T(3.3),T(5.5 )),
test_xy<T>("x - y" ,T(3.3),T(2.2),T(1.1 )),
test_xy<T>("x * y" ,T(3.3),T(2.2),T(7.26 )),
test_xy<T>("x / y" ,T(3.3),T(2.2),T(1.5 )),
test_xy<T>("(x + y) * (x + y)" ,T(2.2),T(3.3),T(30.25)),
test_xy<T>("(x + y) / (x + y)" ,T(2.2),T(3.3),T(1.0 )),
test_xy<T>("x + y > x and x + y > y" ,T(2.2),T(3.3),T(1.0)),
test_xy<T>("1 + (x + y)" ,T(2.2),T(3.3),T(6.5 )),
test_xy<T>("(x + y) - 1" ,T(2.2),T(3.3),T(4.5 )),
test_xy<T>("1 + (x + y) * 2" ,T(2.2),T(3.3),T(12.0 )),
test_xy<T>("2 * (x + y) - 1" ,T(2.2),T(3.3),T(10.0 )),
test_xy<T>("y + (x + 1)" ,T(2.2),T(3.3),T(6.5 )),
test_xy<T>("(x + 1) + y" ,T(2.2),T(3.3),T(6.5 )),
test_xy<T>("2 * x" ,T(2.2),T(0.0),T(4.4)),
test_xy<T>("x * 2" ,T(2.2),T(0.0),T(4.4)),
test_xy<T>("1.1 + x",T(2.2),T(0.0),T(3.3)),
test_xy<T>("x + 1.1",T(2.2),T(0.0),T(3.3)),
test_xy<T>("x * 1 == x" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("1 * x == x" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("y * 1 == y" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("1 * y == y" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("x * 0 == 0" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("0 * x == 0" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("y * 0 == 0" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("0 * y == 0" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("x + 1 == 1 + x",T(2.0),T(3.0),T(1.0)),
test_xy<T>("y + 1 == 1 + y",T(2.0),T(3.0),T(1.0)),
test_xy<T>("x + y == y + x",T(2.0),T(3.0),T(1.0)),
test_xy<T>("x * y == y * x",T(2.0),T(3.0),T(1.0)),
test_xy<T>("x < y" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("y > x" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("x <= y" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("y >= x" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("x + y > y" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("x + y > x" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("x * y > y" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("x * y > x" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("(x + y) > y" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("(x + y) > x" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("(x * y) > y" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("(x * y) > x" ,T(2.0),T(3.0),T(1.0))
};
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xy<T>);
const std::size_t rounds = 10000;
for (std::size_t r = 0; r < rounds; ++r)
{
for (std::size_t i = 0; i < test_list_size; ++i)
{
test_xy<T>& test = const_cast<test_xy<T>&>(test_list[i]);
exprtk::symbol_table<T> symbol_table;
symbol_table.add_variable("x",test.x);
symbol_table.add_variable("y",test.y);
exprtk::expression<T> expression;
expression.register_symbol_table(symbol_table);
{
exprtk::parser<T> parser;
if (!parser.compile(test.expr,expression))
{
std::cout << "test_expression() - Error: " << parser.error() << "\tExpression: " << test.expr << std::endl;
return false;
}
}
T result = expression.value();
if (not_equal<T>(result,test.result))
{
printf("Computation Error: Expression: [%s]\tExpected: %19.15f\tResult: %19.15f\n",
test.expr.c_str(),
test.result,
result);
return false;
}
}
}
return true;
}
template <typename T>
inline bool run_test2()
{ {
std::string expression_string = "a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+u+v+w+x+y+z+" std::string expression_string = "a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+u+v+w+x+y+z+"
"A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z+" "A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z+"
@ -761,41 +872,46 @@ inline bool run_test1()
static const std::size_t variable_list_size = sizeof(variable_list) / sizeof(std::string); static const std::size_t variable_list_size = sizeof(variable_list) / sizeof(std::string);
exprtk::expression<T> expression; static const std::size_t rounds = 10000;
exprtk::symbol_table<T> symbol_table;
std::vector<T> v; for (std::size_t r = 0; r < rounds; ++r)
v.resize(variable_list_size);
for (std::size_t i = 0; i < variable_list_size; ++i)
{ {
v[i] = i; exprtk::expression<T> expression;
symbol_table.add_variable(variable_list[i],v[i]); exprtk::symbol_table<T> symbol_table;
std::vector<T> v;
v.resize(variable_list_size);
for (std::size_t i = 0; i < variable_list_size; ++i)
{
v[i] = i;
symbol_table.add_variable(variable_list[i],v[i]);
}
symbol_table.add_constants();
expression.register_symbol_table(symbol_table);
exprtk::parser<T> parser;
if (!parser.compile(expression_string,expression))
{
std::cout << "run_test1() - Error: " << parser.error() << "\tExpression: " << expression_string << std::endl;
return false;
}
expression.value();
} }
symbol_table.add_constants();
expression.register_symbol_table(symbol_table);
exprtk::parser<T> parser;
if (!parser.compile(expression_string,expression))
{
std::cout << "run_test1() - Error: " << parser.error() << "\tExpression: " << expression_string << std::endl;
return false;
}
expression.value();
return true; return true;
} }
template<typename T> template <typename T>
inline T clamp(const T& l, const T& v, const T& u) inline T clamp(const T& l, const T& v, const T& u)
{ {
return (v < l) ? l : ((v > u) ? u : v); return (v < l) ? l : ((v > u) ? u : v);
} }
template<typename T> template <typename T>
inline bool run_test2() inline bool run_test3()
{ {
std::string expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(y / 2 * pi),+1.0)"; std::string expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(y / 2 * pi),+1.0)";
@ -822,6 +938,7 @@ inline bool run_test2()
} }
const T pi = T(3.14159265358979323846); const T pi = T(3.14159265358979323846);
const T increment = T(0.0001);
while ((x <= T(+1000.0)) && (y <= T(+1000.0))) while ((x <= T(+1000.0)) && (y <= T(+1000.0)))
{ {
@ -837,14 +954,14 @@ inline bool run_test2()
y); y);
return false; return false;
} }
x += 0.001; x += increment;
y += 0.001; y += increment;
} }
return true; return true;
} }
template<typename T> template <typename T>
inline bool run_test3() inline bool run_test4()
{ {
typedef exprtk::expression<T> expression_t; typedef exprtk::expression<T> expression_t;
std::string expression_string = "clamp(-1.0,sin(2 * pi * x_var123) + cos(y_var123 / 2 * pi),+1.0)"; std::string expression_string = "clamp(-1.0,sin(2 * pi * x_var123) + cos(y_var123 / 2 * pi),+1.0)";
@ -875,6 +992,7 @@ inline bool run_test3()
} }
const T pi = T(3.14159265358979323846); const T pi = T(3.14159265358979323846);
const T increment = T(0.0001);
while ((x <= T(+1000.0)) && (y <= T(+1000.0))) while ((x <= T(+1000.0)) && (y <= T(+1000.0)))
{ {
@ -896,14 +1014,14 @@ inline bool run_test3()
return false; return false;
} }
} }
x += 0.001; x += increment;
y += 0.001; y += increment;
} }
return true; return true;
} }
template<typename T> template <typename T>
inline bool run_test4() inline bool run_test5()
{ {
typedef exprtk::expression<T> expression_t; typedef exprtk::expression<T> expression_t;
std::string expression_string = "sqrt(1 - (x^2))"; std::string expression_string = "sqrt(1 - (x^2))";
@ -944,11 +1062,11 @@ inline bool run_test4()
return true; return true;
} }
template<typename T> template <typename T>
inline bool run_test5() inline bool run_test6()
{ {
typedef exprtk::expression<T> expression_t; typedef exprtk::expression<T> expression_t;
std::string expression_string = "sin(2*x)"; std::string expression_string = "sin(2x+1/3)";
T x = T(0.0); T x = T(0.0);
@ -970,7 +1088,7 @@ inline bool run_test5()
{ {
T result1 = exprtk::derivative(expression,x); T result1 = exprtk::derivative(expression,x);
T result2 = exprtk::derivative(expression,"x"); T result2 = exprtk::derivative(expression,"x");
T real_result = T(2.0) * std::cos(T(2.0) * x); T real_result = T(2.0) * std::cos(T(2.0) * x + T(1.0/3.0));
if (not_equal<T>(result1,result2,0.000000001)) if (not_equal<T>(result1,result2,0.000000001))
{ {
@ -989,8 +1107,8 @@ inline bool run_test5()
return true; return true;
} }
template<typename T> template <typename T>
inline bool run_test6() inline bool run_test7()
{ {
static const std::string expr_str[] = static const std::string expr_str[] =
@ -1021,6 +1139,13 @@ inline bool run_test6()
"avg(x,y,z,w)", "avg(x,y,z,w)",
"avg(x,y,z,w,u)", "avg(x,y,z,w,u)",
"(u := u <- min(x:=1,y:=2,z:=3)) == 1", "(u := u <- min(x:=1,y:=2,z:=3)) == 1",
"(2x+3y+4z+5w)==(2*x+3*y+4*z+5*w)",
"(3(x+y)/2+1)==(3*(x+y)/2+1)",
"((x+y)3+1/4)==((x+y)*3+1/4)",
"((x+y)z+1/2)==((x+y)*z+1/2)",
"(3min(x,y))==(3*min(x,y))",
"(sin(x)y)==(sin(x)*y)",
"(sin(x)cos(y)+1)==(sin(x)*cos(y)+1)",
"equal($f00(x,y,z),((x+y)/z))", "equal($f00(x,y,z),((x+y)/z))",
"equal($f01(x,y,z),((x+y)*z))", "equal($f01(x,y,z),((x+y)*z))",
"equal($f02(x,y,z),((x-y)/z))", "equal($f02(x,y,z),((x-y)/z))",
@ -1103,7 +1228,7 @@ inline bool run_test6()
return true; return true;
} }
template<typename T> template <typename T>
struct myfunc : public exprtk::ifunction<T> struct myfunc : public exprtk::ifunction<T>
{ {
myfunc() : exprtk::ifunction<T>(2) {} myfunc() : exprtk::ifunction<T>(2) {}
@ -1114,8 +1239,8 @@ struct myfunc : public exprtk::ifunction<T>
} }
}; };
template<typename T> template <typename T>
inline bool run_test7() inline bool run_test8()
{ {
static const std::size_t rounds = 100000; static const std::size_t rounds = 100000;
for (std::size_t i = 0; i < rounds; ++i) for (std::size_t i = 0; i < rounds; ++i)
@ -1164,16 +1289,16 @@ inline bool run_test7()
const T pi = T(3.14159265358979323846); const T pi = T(3.14159265358979323846);
T result = expression.value(); T result = expression.value();
T expected = mf(sin(x*pi),y/2) + T expected = mf(sin(x*pi),y/2.0) +
mf(sin(x*pi),y/2) + mf(sin(x*pi),y/2.0) +
mf(sin(x*pi),y/2) + mf(sin(x*pi),y/2.0) +
mf(sin(x*pi),y/2) + mf(sin(x*pi),y/2.0) +
mf(sin(x*pi),y/2) + mf(sin(x*pi),y/2.0) +
mf(sin(x*pi),y/2) + mf(sin(x*pi),y/2.0) +
mf(sin(x*pi),y/2) + mf(sin(x*pi),y/2.0) +
mf(sin(x*pi),y/2) + mf(sin(x*pi),y/2.0) +
mf(sin(x*pi),y/2) + mf(sin(x*pi),y/2.0) +
mf(sin(x*pi),y/2); mf(sin(x*pi),y/2.0);
if (not_equal<T>(result,expected,0.0000001)) if (not_equal<T>(result,expected,0.0000001))
{ {
@ -1196,7 +1321,8 @@ int main()
run_test4<double>() && run_test4<double>() &&
run_test5<double>() && run_test5<double>() &&
run_test6<double>() && run_test6<double>() &&
run_test7<double>() run_test7<double>() &&
run_test8<double>()
) )
? 0 : 1; ? 0 : 1;
} }

View File

@ -46,3 +46,4 @@ Expression Library can be found at:
(01) readme.txt (01) readme.txt
(02) exprtk.hpp (02) exprtk.hpp
(03) exprtk_test.cpp (03) exprtk_test.cpp
(04) exprtk_benchmark.cpp