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

This commit is contained in:
Arash Partow 2013-01-31 00:28:22 +11:00
parent 0d8601550f
commit 2a0be4d5a3
5 changed files with 5047 additions and 2268 deletions

View File

@ -43,8 +43,8 @@ strip_bin:
strip -s exprtk_benchmark
valgrind_check:
valgrind --leak-check=full --show-reachable=yes --track-origins=yes ./exprtk_test
valgrind --leak-check=full --show-reachable=yes --track-origins=yes ./exprtk_benchmark
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_test
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_benchmark
clean:
rm -f core.* *~ *.o *.bak *stackdump gmon.out *.gcda *.gcno *.gcnor *.gch

5928
exprtk.hpp

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,8 @@
**************************************************************
* C++ Mathematical Expression Toolkit Library *
* *
* Benchmarks *
* Author: Arash Partow (1999-2012) *
* ExprTk vs Native Benchmarks *
* Author: Arash Partow (1999-2013) *
* URL: http://www.partow.net/programming/exprtk/index.html *
* *
* Copyright notice: *
@ -18,6 +18,7 @@
#include <cstdio>
#include <cmath>
#include <iostream>
#include <string>
#include <deque>
@ -40,8 +41,17 @@ const std::string expression_list[] = {
"max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))",
"if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x"
};
const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
static const double lower_bound_x = -100.0;
static const double lower_bound_y = -100.0;
static const double upper_bound_x = +100.0;
static const double upper_bound_y = +100.0;
static const double delta = 0.0173;
template <typename T,
typename Allocator,
template <typename,typename> class Sequence>
@ -54,102 +64,95 @@ bool load_expression(exprtk::symbol_table<T>& symbol_table,
{
exprtk::expression<double> expression;
expression.register_symbol_table(symbol_table);
if (!parser.compile(expression_list[i],expression,opt_level))
{
std::cout << "[load_expression] - Parser Error: " << parser.error() << "\tExpression: " << expression_list[i] << std::endl;
printf("[load_expression] - Parser Error: %s\tExpression: %s\n",
parser.error().c_str(),
expression_list[i].c_str());
return false;
}
expr_seq.push_back(expression);
}
return true;
}
template <typename T>
void run_benchmark(T& x, T& y,
void run_exprtk_benchmark(T& x, T& y,
exprtk::expression<T>& expression,
const std::string& expr_string)
{
static const double lower_bound = -85.0;
static const double upper_bound = +85.0;
double delta = 0.01;
double total = 0.0;
unsigned int count = 0;
exprtk::timer timer;
timer.start();
for (x = lower_bound; x <= upper_bound; x += delta)
for (x = lower_bound_x; x <= upper_bound_x; x += delta)
{
for (y = lower_bound; y <= upper_bound; y += delta)
for (y = lower_bound_y; y <= upper_bound_y; y += delta)
{
total += expression.value();
++count;
}
}
timer.stop();
if (T(0.0) != total)
printf("[exprtk] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n",
timer.time(),
count / timer.time(),
expr_string.c_str());
else
std::cerr << "Error - expression: " << expr_string << "\n";
printf("run_exprtk_benchmark() - Error running benchmark for expression: %s\n",expr_string.c_str());
}
const double pi = 3.14159265358979323846;
template <typename T>
inline T avg(const T v1, const T v2)
{
return (v1 + v2) / T(2.0);
}
template <typename T>
inline T clamp(const T l, const T v, const T u)
{
return ((v < l) ? l : ((v > u) ? u : v));
}
template <typename T> inline T func00(const T x, const T y) { return (y + x); }
template <typename T> inline T func01(const T x, const T y) { return T(2.0) * (y + x); }
template <typename T> inline T func02(const T x, const T y) { return (T(2.0) * y + T(2.0) * x); }
template <typename T> inline T func03(const T x, const T y) { return (y + x / y) * (x - y / x); }
template <typename T> inline T func04(const T x, const T y) { return x / ((x + y) * (x - y)) / y; }
template <typename T> inline T func05(const T x, const T y) { return T(1.0) - ((x * y) + (y / x)) - T(3.0); }
template <typename T> inline T func06(const T x, const T y) { return (1.1*pow(x,T(1.0))+2.2*pow(y,T(2.0))-3.3*pow(x,T(3.0))+4.4*pow(y,T(15.0))-5.5*pow(x,T(23.0))+6.6*pow(y,T(55.0))); }
template <typename T> inline T func07(const T x, const T y) { return std::sin(T(2.0) * x) + std::cos(pi / y); }
template <typename T> inline T func08(const T x, const T y) { return T(1.0) - std::sin(2.0 * x) + std::cos(pi / y); }
template <typename T> inline T func09(const T x, const T y) { return std::sqrt(T(111.111) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(333.333)); }
template <typename T> inline T func10(const T x, const T y) { return (std::pow(x,T(2.0)) / std::sin(T(2.0) * pi / y)) -x / T(2.0); }
template <typename T> inline T func11(const T x, const T y) { return (x + (std::cos(y - std::sin(2 / x * pi)) - std::sin(x - std::cos(2 * y / pi))) - y); }
template <typename T> inline T func12(const T x, const T y) { return clamp(T(-1.0), std::sin(T(2.0) * pi * x) + std::cos(y / T(2.0) * pi), + T(1.0)); }
template <typename T> inline T func13(const T x, const T y) { return std::max(T(3.33), std::min(sqrt(T(1.0) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(3.0)), T(1.11))); }
template <typename T> inline T func14(const T x, const T y) { return ((avg(x,y) <= x + y) ? x - y : x * y) + T(2.0) * pi / x; }
template <typename T> inline T func00(const T x, const T y);
template <typename T> inline T func01(const T x, const T y);
template <typename T> inline T func02(const T x, const T y);
template <typename T> inline T func03(const T x, const T y);
template <typename T> inline T func04(const T x, const T y);
template <typename T> inline T func05(const T x, const T y);
template <typename T> inline T func06(const T x, const T y);
template <typename T> inline T func07(const T x, const T y);
template <typename T> inline T func08(const T x, const T y);
template <typename T> inline T func09(const T x, const T y);
template <typename T> inline T func10(const T x, const T y);
template <typename T> inline T func11(const T x, const T y);
template <typename T> inline T func12(const T x, const T y);
template <typename T> inline T func13(const T x, const T y);
template <typename T> inline T func14(const T x, const T y);
template <typename T, typename NativeFunction>
void run_native_benchmark(T& x, T& y, NativeFunction f, const std::string& expr_string)
{
static const double lower_bound = -85.0;
static const double upper_bound = +85.0;
double delta = 0.01;
double total = 0.0;
unsigned int count = 0;
exprtk::timer timer;
timer.start();
for (x = lower_bound; x <= upper_bound; x += delta)
for (x = lower_bound_x; x <= upper_bound_x; x += delta)
{
for (y = lower_bound; y <= upper_bound; y += delta)
for (y = lower_bound_y; y <= upper_bound_y; y += delta)
{
total += f(x,y);
++count;
}
}
timer.stop();
if (T(0.0) != total)
printf("[native] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n",
timer.time(),
count / timer.time(),
expr_string.c_str());
else
std::cerr << "Error - expression: " << expr_string << "\n";
printf("run_native_benchmark() - Error running benchmark for expression: %s\n",expr_string.c_str());
}
template <typename T>
@ -158,20 +161,28 @@ bool run_parse_benchmark(exprtk::symbol_table<T>& symbol_table)
static const std::size_t rounds = 1000000;
exprtk::parser<double> parser;
exprtk::expression<double> expression;
expression.register_symbol_table(symbol_table);
for (std::size_t i = 0; i < expression_list_size; ++i)
{
exprtk::timer timer;
timer.start();
for (std::size_t r = 0; r < rounds; ++r)
{
if (!parser.compile(expression_list[i],expression))
{
std::cout << "[run_parse_benchmark] - Parser Error: " << parser.error() << "\tExpression: " << expression_list[i] << std::endl;
printf("[run_parse_benchmark] - Parser Error: %s\tExpression: %s\n",
parser.error().c_str(),
expression_list[i].c_str());
return false;
}
}
timer.stop();
printf("[parse] Total Time:%12.8f Rate:%14.3fparse/sec Expression: %s\n",
timer.time(),
rounds / timer.time(),
@ -180,8 +191,12 @@ bool run_parse_benchmark(exprtk::symbol_table<T>& symbol_table)
return true;
}
void pgo_primer();
int main()
{
pgo_primer();
double x = 0;
double y = 0;
@ -204,16 +219,16 @@ int main()
}
{
std::cout << "--- EXPRTK [Opt All]---" << std::endl;
std::cout << "--- EXPRTK [All Optimisations] ---" << std::endl;
for (std::size_t i = 0; i < optimized_expr_list.size(); ++i)
{
run_benchmark(x,y,optimized_expr_list[i],expression_list[i]);
run_exprtk_benchmark(x,y,optimized_expr_list[i],expression_list[i]);
}
std::cout << "--- EXPRTK [No Opt]---" << std::endl;
std::cout << "--- EXPRTK [No Optimisations] ---" << std::endl;
for (std::size_t i = 0; i < expr_list.size(); ++i)
{
run_benchmark(x,y,expr_list[i],expression_list[i]);
run_exprtk_benchmark(x,y,expr_list[i],expression_list[i]);
}
}
@ -243,3 +258,142 @@ int main()
return 0;
}
void pgo_primer()
{
exprtk::pgo_primer<double>();
static const double lower_bound_x = -50.0;
static const double lower_bound_y = -50.0;
static const double upper_bound_x = +50.0;
static const double upper_bound_y = +50.0;
static const double delta = 0.03;
double total = 0.0;
for (double x = lower_bound_x; x <= upper_bound_x; x += delta)
{
for (double y = lower_bound_y; y <= upper_bound_y; y += delta)
{
total += func00<double>(x,y);
total += func01<double>(x,y);
total += func02<double>(x,y);
total += func03<double>(x,y);
total += func04<double>(x,y);
total += func05<double>(x,y);
total += func06<double>(x,y);
total += func07<double>(x,y);
total += func08<double>(x,y);
total += func09<double>(x,y);
total += func10<double>(x,y);
total += func11<double>(x,y);
total += func12<double>(x,y);
total += func13<double>(x,y);
total += func14<double>(x,y);
}
}
}
const double pi = 3.14159265358979323846;
template <typename T>
inline T avg(const T v1, const T v2)
{
return (v1 + v2) / T(2.0);
}
template <typename T>
inline T clamp(const T l, const T v, const T u)
{
return ((v < l) ? l : ((v > u) ? u : v));
}
template <typename T>
inline T func00(const T x, const T y)
{
return (y + x);
}
template <typename T>
inline T func01(const T x, const T y)
{
return T(2.0) * (y + x);
}
template <typename T>
inline T func02(const T x, const T y)
{
return (T(2.0) * y + T(2.0) * x);
}
template <typename T>
inline T func03(const T x, const T y)
{
return (y + x / y) * (x - y / x);
}
template <typename T>
inline T func04(const T x, const T y)
{
return x / ((x + y) * (x - y)) / y;
}
template <typename T>
inline T func05(const T x, const T y)
{
return T(1.0) - ((x * y) + (y / x)) - T(3.0);
}
template <typename T>
inline T func06(const T x, const T y)
{
return (1.1*pow(x,T(1.0))+2.2*pow(y,T(2.0))-3.3*pow(x,T(3.0))+4.4*pow(y,T(15.0))-5.5*pow(x,T(23.0))+6.6*pow(y,T(55.0)));
}
template <typename T>
inline T func07(const T x, const T y)
{
return std::sin(T(2.0) * x) + std::cos(pi / y);
}
template <typename T>
inline T func08(const T x, const T y)
{
return T(1.0) - std::sin(2.0 * x) + std::cos(pi / y);
}
template <typename T>
inline T func09(const T x, const T y)
{
return std::sqrt(T(111.111) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(333.333));
}
template <typename T>
inline T func10(const T x, const T y)
{
return (std::pow(x,T(2.0)) / std::sin(T(2.0) * pi / y)) -x / T(2.0);
}
template <typename T>
inline T func11(const T x, const T y)
{
return (x + (std::cos(y - std::sin(2 / x * pi)) - std::sin(x - std::cos(2 * y / pi))) - y);
}
template <typename T>
inline T func12(const T x, const T y)
{
return clamp(T(-1.0), std::sin(T(2.0) * pi * x) + std::cos(y / T(2.0) * pi), + T(1.0));
}
template <typename T>
inline T func13(const T x, const T y)
{
return std::max(T(3.33), std::min(sqrt(T(1.0) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(3.0)), T(1.11)));
}
template <typename T>
inline T func14(const T x, const T y)
{
return ((avg(x,y) <= x + y) ? x - y : x * y) + T(2.0) * pi / x;
}

File diff suppressed because it is too large Load Diff

View File

@ -17,14 +17,14 @@ operations, functions and processes:
(2) Functions: min, max, avg, sum, abs, ceil, floor, round,
roundn, exp, log, log10, logn, root, sqrt,
clamp, inrange, sgn, erf, erfc
clamp, inrange, sgn, erf, erfc, frac, trunc
(3) Trigonometry: sin, cos, tan, acos, asin, atan, atan2, cosh,
cot, csc, sec, sinh, tanh, rad2deg, deg2rad,
deg2grad, grad2deg, hyp
(4) Equalities &
Inequalities: =, ==, <>, !=, <, <=, >, >=,
Inequalities: =, ==, <>, !=, <, <=, >, >=
(5) Boolean logic: and, or, xor, not, nand, nor, shr, shl, true,
false
@ -32,7 +32,11 @@ operations, functions and processes:
(6) Conditional &
Loop statement: if-then-else, while
(7) Assigment: :=
(7) Assignment: :=
(8) Calculus: numerical integration and differentiation
Note: The trigonometry functions assume radians as input.
@ -97,6 +101,7 @@ Expression Library can be found at:
(*) GNU Compiler Collection (4.3+)
(*) Intel® C++ Compiler (9.x+)
(*) Clang/LLVM (1.1+)
(*) PGI C++ (10.x+)
(*) Microsoft Visual Studio C++ Compiler (8.1+)
(*) Comeau C++ Compiler (4.3+)
@ -115,9 +120,9 @@ an expression and by also leveraging the compiler's ability to
correctly optimize such expressions for a given architecture.
3-Parameter 4-Parameter
+------------+-------------+ +--------------+------------------+
+-------------+-------------+ +--------------+------------------+
| Prototype | Operation | | Prototype | Operation |
+------------+-------------+ +--------------+------------------+
+-------------+-------------+ +--------------+------------------+
sf00(x,y,z) | (x + y) / z sf35(x,y,z,w) | x + ((y + z) / w)
sf01(x,y,z) | (x + y) * z sf36(x,y,z,w) | x + ((y + z) * w)
sf02(x,y,z) | (x - y) / z sf37(x,y,z,w) | x + ((y - z) / w)
@ -145,24 +150,27 @@ correctly optimize such expressions for a given architecture.
sf24(x,y,z) | x * y^8 + z sf59(x,y,z,w) | ((x / y) / z) - w
sf25(x,y,z) | x * y^9 + z sf60(x,y,z,w) | (x * y) + (z * w)
sf26(x,y,z) | x * log(y)+z sf61(x,y,z,w) | (x * y) - (z * w)
sf27(x,y,z) | x * log(y)-z sf62(x,y,z,w) | (x / y) + (z / w)
sf28(x,y,z) | x * log10(y)+z sf63(x,y,z,w) | (x / y) - (z / w)
sf29(x,y,z) | x * log10(y)-z sf64(x,y,z,w) | x * y^2 + z * w^2
sf30(x,y,z) | x * sin(y)+z sf65(x,y,z,w) | x * y^3 + z * w^3
sf31(x,y,z) | x * sin(y)-z sf66(x,y,z,w) | x * y^4 + z * w^4
sf32(x,y,z) | x * cos(y)+z sf67(x,y,z,w) | x * y^5 + z * w^5
sf33(x,y,z) | x * cos(y)-z sf68(x,y,z,w) | x * y^6 + z * w^6
sf34(x,y,z) | x ? y : z sf69(x,y,z,w) | x * y^7 + z * w^7
sf70(x,y,z,w) | x * y^8 + z * w^8
sf71(x,y,z,w) | x * y^9 + z * w^9
sf72(x,y,z,w) | (x and y) ? z : w
sf73(x,y,z,w) | (x or y) ? z : w
sf74(x,y,z,w) | (x < y) ? z : w
sf75(x,y,z,w) | (x <= y) ? z : w
sf76(x,y,z,w) | (x > y) ? z : w
sf77(x,y,z,w) | (x >= y) ? z : w
sf78(x,y,z,w) | (x == y) ? z : w
sf79(x,y,z,w) | x*sin(y) + z*cos(w)
sf27(x,y,z) | x * log(y)-z sf62(x,y,z,w) | (x * y) + (z / w)
sf28(x,y,z) | x * log10(y)+z sf63(x,y,z,w) | (x * y) - (z / w)
sf29(x,y,z) | x * log10(y)-z sf64(x,y,z,w) | (x / y) + (z / w)
sf30(x,y,z) | x * sin(y)+z sf65(x,y,z,w) | (x / y) - (z / w)
sf31(x,y,z) | x * sin(y)-z sf66(x,y,z,w) | (x / y) - (z * w)
sf32(x,y,z) | x * cos(y)+z sf67(x,y,z,w) | x * y^2 + z * w^2
sf33(x,y,z) | x * cos(y)-z sf68(x,y,z,w) | x * y^3 + z * w^3
sf34(x,y,z) | x ? y : z sf69(x,y,z,w) | x * y^4 + z * w^4
sf70(x,y,z,w) | x * y^5 + z * w^5
sf71(x,y,z,w) | x * y^6 + z * w^6
sf72(x,y,z,w) | x * y^7 + z * w^7
sf73(x,y,z,w) | x * y^8 + z * w^8
sf74(x,y,z,w) | x * y^9 + z * w^9
sf75(x,y,z,w) | (x and y) ? z : w
sf76(x,y,z,w) | (x or y) ? z : w
sf77(x,y,z,w) | (x < y) ? z : w
sf78(x,y,z,w) | (x <= y) ? z : w
sf79(x,y,z,w) | (x > y) ? z : w
sf80(x,y,z,w) | (x >= y) ? z : w
sf81(x,y,z,w) | (x == y) ? z : w
sf82(x,y,z,w) | x*sin(y) + z*cos(w)
@ -179,6 +187,7 @@ and the ability to evaluate strings within expressions.
(4) exprtk_disable_extended_operator_optimizations
(5) exprtk_lean_and_mean
(6) exprtk_lean_and_mean_numeric_only
(7) exprtk_enable_all_optimizations
(1) "exprtk_disable_string_capabilities"
If defined, the macro will disable all string processing capabilities.
@ -218,12 +227,83 @@ both modes [3] and [4].
The mode when this macro is defined, is 'lean and mean' coupled with
all string capabilities disabled [1].
(7) "exprtk_enable_all_optimizations"
When defined all optimization mechanisms are turned on, including all
string processing related optimizations. In short nothing is disabled.
This mode will cause older C++ compilers and or compilers running on
slower machines with limited RAM to nearly come to a grinding halt as
per (3). This mode will however produce the most efficient and high
performance expression evaluation results. It is advised to have this
mode turned on for final builds and not to be used during the
development cycle.
Note: Foregoing a few extra clock cycles during compilation in
exchange for a dramatic increase in performance during run-time is
always a worthy undertaking.
[SIMPLE EXAMPLE]
--- snip ---
#include <cstdio>
#include <string>
#include "exprtk.hpp"
int main()
{
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
typedef exprtk::parser_error::type error_t;
std::string expression_str = "z := 2 [sin(x/pi)^3 + cos(pi/y)^4]";
double x = 1.1;
double y = 2.2;
double z = 3.3;
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);
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
if (!parser.compile(expression_str,expression))
{
printf("Error: %s\tExpression: %s\n",
parser.error().c_str(),
expression_str.c_str());
for (std::size_t i = 0; i < parser.error_count(); ++i)
{
error_t error = parser.get_error(i);
printf("Err: %02d Pos: %02d Type: [%s] Msg: %s Expr: %s\n",
static_cast<int>(i),
static_cast<int>(error.token.position),
exprtk::parser_error::to_str(error.mode).c_str(),
error.diagnostic.c_str(),
expression_str.c_str());
}
return 1;
}
double result = expression.value();
printf("Result: %10.5f\n",result);
return 0;
}
--- snip ---
[FILES]
(00) Makefile
(01) readme.txt