/

21 tháng 6, 2013

Thư viện biểu thức toán học C++

Mô tả

Thư viện mở rộng Biểu thức toán học (ExprTk) đơn giản khi sử dụng, dễ dàng hợp nhất và vô cùng hiệu quả trong việc phân tích biểu thức, cũng như động cơ tính toán. Động cơ phân tích hỗ trợ nhiều cấu trúc của hàm, xử lý ngữ nghĩa logic và rất dễ dàng được mở rộng thêm.
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 very easily extendible.

Khả năng

Thư viện ExprTk có những khả năng sau:
  • Các toán tử toán học thông thường (+, -, *, /, %, ^)
  • Hàm (min, max, avg, sum, abs, ceil, floor, round, roundn, exp, log, log10, logn, root, sqrt, clamp, inrange)
  • Lượng giác (sin, cos, tan, acos, asin, atan, atan2, cosh, cot, csc, sec, sinh, tanh, d2r, r2d, d2g, g2d, hyp)
  • Đẳng thức, phép so sánh và phép gán (=, ==, <>, !=, <, <=, >, >=, :=)
  • Phép logic (and, mand, mor, nand, nor, not, or, xor, xnor)
  • Cấu trúc điều khiển (if-then-else, switch case, while loop, repeat until loop)
  • Tối ưu hóa biểu thức (phép gấp hằng số, ghép nối toán tử và hàm đặc biệt cho chuỗi số học)
  • Phép xử lý chuỗi đơn giản (equalities, inequalities, boolean logic and ranges)
  • Xử lý chuỗi đa điểm và hỗ trợ tiểu biểu thức (sub expression)
  • Vi phân và tích phân số học
  • Hỗ trợ đa biến và biến riêng
  • Biến người dùng, hỗ trợ hằng và hàm
  • Hàm hợp nhiều chiều
  • Hỗ trợ kiểu số thực(float, double, long double)
  • Thực thi header đơn, không yêu cầu xây dựng. Không mở rộng độc lập.
  • Hoàn toàn di động (Biên dịch và thi hành trên tất cả các cấu trúc: x86 x86-64, ARMv7/8, POWER6/7 và AVR32)

Bản quyền sử dụng thư viện biểu thức toán học C++

Sử dụng thư viện biểu thức toán học C++ được đồng ý dưới những hướng dẫn và trong thỏa thuận với phiên bản mới nhất của "Bản quyền sử dụng công cộng."

Tương thích

Thư viện biểu thức toán học C++ tượng thích với các trình biên dịch sau:
  • GNU Compiler Collection (4.1+)
  • 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+)
  • IBM XL C/C++ (10.x+)
Tải về

The C++ Mathematical Expression Library Download - Copyright Arash Partow Ví dụ và Mã nguồn thư viện biểu thức toán học C++


Ví dụ biểu thức toán học

The C++ Mathematical Expression Library Example - Copyright Arash Partow
  • sqrt(1 - (x^2))
  • clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1)
  • sin(2 * x)
  • if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z)
  • inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0)
  • ({1 / 1} * [1 / 2] + (1 / 3)) - {1 / 4} ^ [1 / 5] + (1 / 6) -({1 / 7} + [1 / 8]*(1 / 9))
  • a * exp(2 * t) + c
  • z := x + sin(2 * pi / y)
  • u <- 2 * (pi * z) / (w := x + cos(y / pi))
  • 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
  • (sin(x/pi)cos(2y) + 1)==(sin(x / pi) * cos(2 * y) + 1)
  • fib_i := fib_i + (x := y + 0 * (fib_i := x + (y := fib_i)))
  • while(x <= 100) { x := x + 1 }
  • x <= 'abc123' and (y in 'AString') or ('1x2y3z' != z)
  • (x like '*123*') or ('a123b' ilike y)

Ví dụ 1


The following is an example where a given single variable function is evaluated between a specified range[-5,+5]. The graph below shows the clamped (red) and non-clamped (blue) versions of the specified function. simple_example_01.cpp
template<typename T>
void trig_function()
{
std::string expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)";
T x;
exprtk::symbol_table<T> symbol_table;
symbol_table.add_variable("x",x);
symbol_table.add_constants();

exprtk::expression<T> expression;
expression.register_symbol_table(symbol_table);

exprtk::parser<T> parser;
parser.compile(expression_string,expression);

for (x = T(-5.0); x <= T(+5.0); x += 0.001)
{
T y = expression.value();
printf("%19.15f\t%19.15f\n",x,y);
}
}
The C++ Mathematical Expression Library Graph - Copyright Arash Partow

Ví dụ 2

Ví dụ dưới đây sinh ra sóng vuông dựa trên chuỗi Fourier - 14 hòa âm. Hằng số xấp xỉ Sigma không được áp dụng từ đây
The following example generates a square wave form based on Fourier series accumulations - 14 harmonics. Sigma-approximation is not applied hence Gibbs phenomenon based ringing is observed on the edges of the square, as is demonstrated in the graph below. simple_example_02.cpp
template<typename T>
void square_wave()
{
std::string expr_string = "a*(4/pi)*"
"((1 /1)*sin( 2*pi*f*t)+(1 /3)*sin( 6*pi*f*t)+"
" (1 /5)*sin(10*pi*f*t)+(1 /7)*sin(14*pi*f*t)+"
" (1 /9)*sin(18*pi*f*t)+(1/11)*sin(22*pi*f*t)+"
" (1/13)*sin(26*pi*f*t)+(1/15)*sin(30*pi*f*t)+"
" (1/17)*sin(34*pi*f*t)+(1/19)*sin(38*pi*f*t)+"
" (1/21)*sin(42*pi*f*t)+(1/23)*sin(46*pi*f*t)+"
" (1/25)*sin(50*pi*f*t)+(1/27)*sin(54*pi*f*t))";
static const T pi = T(3.14159265358979323846);
T f = pi/10.0;
T t = T(0.0);
T a = T(10.0);

exprtk::symbol_table<T> symbol_table;
symbol_table.add_variable("f",f);
symbol_table.add_variable("t",t);
symbol_table.add_variable("a",a);
symbol_table.add_constants();

exprtk::expression<T> expression;
expression.register_symbol_table(symbol_table);

exprtk::parser<T> parser;
parser.compile(expr_string,expression);

const T delta = (4.0*pi)/1000.0;
for (t = -2.0*pi; t <= +2.0*pi; t+=delta)
{
T result = expression.value();
printf("%19.15f\t%19.15f\n",t,result);
}
}
The C++ Mathematical Expression Library Sqaure Wave Graph - Copyright Arash Partow

Ví dụ 3

The following example evaluates a 5th degree polynomial within the domain [0,1] with a step size of 1/100th. An interesting side note in the expression is how the multiplication of the coefficients to the variable 'x' are implied rather than explicity defined using the multiplication operator '*' simple_example_03.cpp
template<typename T>
void polynomial()
{
std::string expression_string = "25x^5 - 35x^4 - 15x^3 + 40x^2 - 15x + 1";
T r0 = T(0.0);
T r1 = T(1.0);
T x = T(0.0);

exprtk::symbol_table<T> symbol_table;
symbol_table.add_variable("x",x);

exprtk::expression<T> expression;
expression.register_symbol_table(symbol_table);

exprtk::parser<T> parser;
parser.compile(expression_string,expression);

const T delta = T(1/100.0);
for (x = r0; x <= r1; x += delta)
{
printf("%19.15f\t%19.15f\n",x,expression.value());
}
}
The C++ Mathematical Expression Library Polynomial Graph - Copyright Arash Partow

Ví dụ 4

The following example generates the first 40 Fibonacci numbers using a simple iterative method. The example demonstrates the use of multiple assignment and sequence points, switch statements, while-loops and recursive composited multi-variate functions. simple_example_04.cpp
template <typename T>
void fibonacci()
{
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
typedef exprtk::function_compositor<T> compositor_t;

compositor_t compositor;

//define: fibonacci_impl(x,y,z,w)
compositor
.add("fibonacci_impl",
"switch "
"{ "
" case x == 0 : 0; "
" case x == 1 : 1; "
" default : "
" while ((x := (x - 1)) > 0)"
" { "
" w := z; "
" z := z + y; "
" y := w; "
" z "
" }; "
"} ",
"x","y","z","w");

//define: fibonacci(x)
compositor
.add("fibonacci",
"fibonacci_impl(x,0,1,0)",
"x");

T x = T(0);

symbol_table_t& symbol_table = compositor.symbol_table();
symbol_table.add_constants();
symbol_table.add_variable("x",x);

std::string expression_str = "fibonacci(x)";

expression_t expression;
expression.register_symbol_table(symbol_table);

parser_t parser;

parser.compile(expression_str,expression);

for (std::size_t i = 0; i < 40; ++i)
{
x = i;
T result = expression.value();
printf("fibonacci(%3d) = %10.0f\n",i,result);
}
}

Ví dụ 5

The following example demonstrates how one can easily register a custom user defined function to be used within expression evaluations. In this example the custom function myfunc takes 2 parameters and returns a result. At the moment an upper limit of 20 parameters is in place. simple_example_05.cpp
template<typename T>
struct myfunc : public exprtk::ifunction<T>
{
myfunc()
: exprtk::ifunction<T>(2)
{}

inline T operator()(const T& v1, const T& v2)
{
return T(1) + (v1 * v2) / T(3);
}
};

template<typename T>
void custom_function()
{
typedef exprtk::expression<T> expression_t;
std::string expression_string = "myfunc(sin(x*pi),y/2)";
T x = T(1.0);
T y = T(2.0);
myfunc<T> mf;

exprtk::symbol_table<T> symbol_table;
symbol_table.add_variable("x",x);
symbol_table.add_variable("y",y);
symbol_table.add_function("myfunc",mf);
symbol_table.add_constants();

expression_t expression;
expression.register_symbol_table(symbol_table);

exprtk::parser<T> parser;
parser.compile(expression_string,expression);

T result = expression.value();
}

Ví dụ 6

The following example demonstrates how one can evaluate an expression over multiple vectors. The example evaluates the value of an expression at the ith element of vectors x and y and assigns the value to the ith value of vector z. simple_example_06.cpp
template<typename T>
void vector_function()
{
typedef exprtk::expression<T> expression_t;
std::string expression_string = "z := (3sin(x) + 2log(y))";

const std::size_t vec_size = 5;

T x[vec_size] = { T(1.1), T(2.2), T(3.3), T(4.4), T(5.5) };
T y[vec_size] = { T(1.1), T(2.2), T(3.3), T(4.4), T(5.5) };
T z[vec_size] = { T(0.0), T(0.0), T(0.0), T(0.0), T(0.0) };

T x_ = x[0];
T y_ = y[0];
T z_ = z[0];

exprtk::symbol_table<T> symbol_table;
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);

exprtk::parser<T> parser;
parser.compile(expression_string,expression);

for (std::size_t i = 0; i < vec_size; ++i)
{
x_ = x[i]; y_ = y[i]; z_ = z[i];
expression.value();
x[i] = x_; y[i] = y_; z[i] = z_;
}
}

Ví dụ 7

The following example demonstrates how one can create and later on reference variables via the symbol_table. In the example a simple boolean expression is evaluated so as to determine its truth-table. simple_example_07.cpp
template <typename T>
void logic()
{
typedef exprtk::expression<T> expression_t;
std::string expression_string = "not(A and B) or C";

exprtk::symbol_table<T> symbol_table;
symbol_table.create_variable("A");
symbol_table.create_variable("B");
symbol_table.create_variable("C");

expression_t expression;
expression.register_symbol_table(symbol_table);

exprtk::parser<T> parser;
parser.compile(expression_string,expression);

printf(" # | A | B | C | %s\n"
"---+---+---+---+-%s\n",
expression_string.c_str(),
std::string(expression_string.size(),'-').c_str());

for (int i = 0; i < 8; ++i)
{
symbol_table.get_variable("A")->ref() = T(i & 0x01 ? 1 : 0);
symbol_table.get_variable("B")->ref() = T(i & 0x02 ? 1 : 0);
symbol_table.get_variable("C")->ref() = T(i & 0x04 ? 1 : 0);

int result = static_cast<int>(expression.value());

printf(" %d | %d | %d | %d | %d \n",
i,
static_cast<int>(symbol_table.get_variable("A")->value()),
static_cast<int>(symbol_table.get_variable("B")->value()),
static_cast<int>(symbol_table.get_variable("C")->value()),
result);
}
}

Expected output:
# | A | B | C | not(A and B) or C
---+---+---+---+------------------
0 | 0 | 0 | 0 | 1
1 | 1 | 0 | 0 | 1
2 | 0 | 1 | 0 | 1
3 | 1 | 1 | 0 | 0
4 | 0 | 0 | 1 | 1
5 | 1 | 0 | 1 | 1
6 | 0 | 1 | 1 | 1
7 | 1 | 1 | 1 | 1

Ví dụ 8

The following example demonstrates the function composition capabilities within ExprTk. In the example there are two simple functions defined, an f(x) and a multivariate g(x,y). The function g(x,y) is composed of calls to f(x), the culmination of which is a final expression composed from both functions. Furthermore the example demonstrates how one can extract all errors that were encountered during a failed compilation process. simple_example_08.cpp
template <typename T>
void composite()
{
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
typedef exprtk::parser_error::type error_t;
typedef exprtk::function_compositor<T> compositor_t;

compositor_t compositor;

T x = T(1);
T y = T(2);

symbol_table_t& symbol_table = compositor.symbol_table();
symbol_table.add_constants();
symbol_table.add_variable("x",x);
symbol_table.add_variable("y",y);

compositor.add("f","sin(x/pi)","x"); // f(x) = sin(x/pi)
compositor.add("g","3*(f(x)+f(y))","x","y"); // g(x,y) = 3(f(x)+f(y))

std::string expression_string = "g(1 + f(x),f(y) / 2)";

expression_t expression;
expression.register_symbol_table(symbol_table);

parser_t parser;

if (!parser.compile(expression_string,expression))
{
printf("Error: %s\tExpression: %s\n",
parser.error().c_str(),
expression_string.c_str());

for (std::size_t i = 0; i < parser.error_count(); ++i)
{
error_t error = parser.get_error(i);
printf("Error: %02d Position: %02d Type: [%14s] Msg: %s\tExpression: %s\n",
i,
error.token.position,
exprtk::parser_error::to_str(error.mode).c_str(),
error.diagnostic.c_str(),
expression_string.c_str());
}
return;
}

T result = expression.value();

printf("%s = %e\n",
expression_string.c_str(),
result);
}

Ví dụ 9

The following example demonstrates the computation of prime numbers via a mixture of recursive composited functions, switch-statement and while-loop functionalities. simple_example_09.cpp
template <typename T>
void primes()
{
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
typedef exprtk::function_compositor<T> compositor_t;

T x = T(0);

exprtk::symbol_table<T> symbol_table;

symbol_table.add_constants();
symbol_table.add_variable("x",x);

compositor_t compositor(symbol_table);

//Method 1 - Recursive if-statement based
compositor
.add("is_prime_impl1",
"if(y == 1,true, "
" if(0 == (x % y),false, "
" is_prime_impl1(x,y-1)))",
"x","y");

compositor
.add("is_prime1",
"if(frac(x) != 0, false, "
" if(x <= 0, false, "
" is_prime_impl1(x,min(x - 1,trunc(sqrt(x)) + 1))))",
"x");

//Method 2 - Recursive switch statement based
compositor
.add("is_prime_impl2",
"switch "
"{ "
" case y == 1 : true; "
" case (x % y) == 0 : false; "
" default : is_prime_impl2(x,y - 1);"
"} ",
"x","y");

compositor
.add("is_prime2",
"switch "
"{ "
" case x <= 0 : false; "
" case frac(x) != 0 : false; "
" default : "
" is_prime_impl2(x,min(x - 1,trunc(sqrt(x)) + 1));"
"} ",
"x");

//Method 3 - Iterative switch statement and while-loop based
compositor
.add("is_prime_impl3",
"while (y > 0) "
"{ "
" switch "
" { "
" case y == 1 : ~(y := 0, true);"
" case (x % y) == 0 : ~(y := 0,false);"
" default : y := y - 1; "
" } "
"} ",
"x","y");

compositor
.add("is_prime3",
"switch "
"{ "
" case x <= 0 : false; "
" case frac(x) != 0 : false; "
" default : "
" is_prime_impl3(x,min(x - 1,trunc(sqrt(x)) + 1));"
"} ",
"x");

std::string expression_str1 = "is_prime1(x)";
std::string expression_str2 = "is_prime2(x)";
std::string expression_str3 = "is_prime3(x)";

expression_t expression1;
expression_t expression2;
expression_t expression3;
expression1.register_symbol_table(symbol_table);
expression2.register_symbol_table(symbol_table);
expression3.register_symbol_table(symbol_table);

exprtk::parser<T> parser;

parser.compile(expression_str1,expression1);
parser.compile(expression_str2,expression2);
parser.compile(expression_str3,expression3);

for (std::size_t i = 0; i < 100; ++i)
{
x = i;
T result1 = expression1.value();
T result2 = expression2.value();
T result3 = expression3.value();
printf("%03d Result1: %c Result2: %c Result3: %c\n",
i,
(result1 == T(1)) ? 'T' : 'F',
(result2 == T(1)) ? 'T' : 'F',
(result3 == T(1)) ? 'T' : 'F');
}
}

Ví dụ 10

The following example is an implementation of the Newton–Raphson method for computing the approximate of the square root of a real number. The example below demonstrates the use of multiple sub-expressions, sequence points, switch statements and the repeat until loop. simple_example_10.cpp
template <typename T>
void newton_sqrt()
{
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
typedef exprtk::function_compositor<T> compositor_t;

T x = T(0);

exprtk::symbol_table<T> symbol_table;
symbol_table.add_constants();
symbol_table.add_variable("x",x);

compositor_t compositor(symbol_table);

compositor
.add("newton_sqrt_impl",
"switch "
"{ "
" case x < 0 : -inf; "
" case x == 0 : 0; "
" case x == 1 : 1; "
" default: "
" ~{ "
" z := 100; "
" y := x / 2; "
" repeat "
" if (equal(y * y,x), z := 0, 0);"
" y := (1 / 2) * (y + (x / y)); "
" until ((z := (z - 1)) <= 0) "
" }; "
"} ",
"x","y","z");

compositor
.add("newton_sqrt",
"newton_sqrt_impl(x,0,0)","x");

std::string expression_str = "newton_sqrt(x)";

expression_t expression;
expression.register_symbol_table(symbol_table);

exprtk::parser<T> parser;
parser.compile(expression_str,expression);

for (std::size_t i = 0; i < 100; ++i)
{
x = i;
T result = expression.value();
printf("sqrt(%03d) - Result: %12.10f\tReal: %12.10f\n",
static_cast<unsigned int>(i),
result,
std::sqrt(x));
}
}

Chuẩn đánh giá

The chart below depicts the rate of expression evaluations per second for an assortment of expressions as denoted. Each expression is specialised upon the 'double' floating point type and comprised of two variables that are varied before each expression evaluation. The expressions are evaluated in two modes: ExprTk compiled and native optimised. The benchmark itself was compiled using GCC 4.8 with O3, PGO and native architecture target compiler settings, and executed upon a 64-Bit Intel Quad Core Extreme i7-920XM 2.0GHz, 16GB RAM, Ubuntu 10.10 kernel 2.6.35 system.
  • (y + x)
  • 2 * (y + x)
  • ((1.23 * x^2) / y) - 123.123
  • (y + x / y) * (x - y / x)
  • x / ((x + y) + (x - y)) / y
  • 1 - ((x * y) + (y / x)) - 3
  • 1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^15 - 5.5x^23 + 6.6y^55
  • sin(2 * x) + cos(pi / y)
  • 1 - sin(2 * x) + cos(pi / y)
  • sqrt(111.111 - sin(2 * x) + cos(pi / y) / 333.333)
  • (x^2 / sin(2 * pi / y)) -x / 2
  • x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y
  • clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)
  • 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
The C++ Mathematical Expression Library Benchmark Result - Copyright Arash Partow
Một số vấn đề nhỏ có thể gặp phải khi biên dịch:
My guess is that max has been made a macro. This happens at some point inside windows.h.
Define NOMINMAX prior to including to stop windows.h from doing that.
EDIT:
I'm still confident this is your problem. (Not including <limits> would result in a different error). Place #undef max and #undef min just before the function and try again. If that fixes it, I was correct, and your NOMINMAX isn't being defined properly. (Add it as a project setting.)
You can also prevent macro expansion by: (std::numeric_limits<T>::max)().


Không có nhận xét nào:

Đăng nhận xét