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.
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ề
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
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);
}
}
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ừ đâyThe 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);
}
}
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.cpptemplate<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());
}
}
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.cpptemplate <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.cpptemplate<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.cpptemplate<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.cpptemplate <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.cpptemplate <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.cpptemplate <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.cpptemplate <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
Một số vấn đề nhỏ có thể gặp phải khi biên dịch:
My guess is thatmax
has been made a macro. This happens at some point insidewindows.h
.DefineNOMINMAX
prior to including to stopwindows.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 yourNOMINMAX
isn't being defined properly. (Add it as a project setting.)You can also prevent macro expansion by:(std::numeric_limits<T>::max)()
.
No comments:
Post a Comment