C++ Mathematical Expression Toolkit (ExprTk) release
Loading...
Searching...
No Matches
exprtk_benchmark.cpp
Go to the documentation of this file.
1/*
2 **************************************************************
3 * C++ Mathematical Expression Toolkit Library *
4 * *
5 * ExprTk vs Native Benchmarks *
6 * Author: Arash Partow (1999-2024) *
7 * URL: https://www.partow.net/programming/exprtk/index.html *
8 * *
9 * Copyright notice: *
10 * Free use of the Mathematical Expression Toolkit Library is *
11 * permitted under the guidelines and in accordance with the *
12 * most current version of the MIT License. *
13 * https://www.opensource.org/licenses/MIT *
14 * SPDX-License-Identifier: MIT *
15 * *
16 **************************************************************
17*/
18
19
20#include <cstdio>
21#include <cmath>
22#include <fstream>
23#include <string>
24#include <deque>
25
26#include "exprtk.hpp"
27
28
29const std::string global_expression_list[] =
30 {
31 "(y + x)",
32 "2 * (y + x)",
33 "(2 * y + 2 * x)",
34 "((1.23 * x^2) / y) - 123.123",
35 "(y + x / y) * (x - y / x)",
36 "x / ((x + y) + (x - y)) / y",
37 "1 - ((x * y) + (y / x)) - 3",
38 "(5.5 + x) + (2 * x - 2 / 3 * y) * (x / 3 + y / 4) + (y + 7.7)",
39 "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^15 - 5.5x^23 + 6.6y^55",
40 "sin(2 * x) + cos(pi / y)",
41 "1 - sin(2 * x) + cos(pi / y)",
42 "sqrt(111.111 - sin(2 * x) + cos(pi / y) / 333.333)",
43 "(x^2 / sin(2 * pi / y)) - x / 2",
44 "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y",
45 "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)",
46 "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))",
47 "if((y + (x * 2.2)) <= (x + y + 1.1), x - y, x * y) + 2 * pi / x"
48 };
49
50const std::size_t global_expression_list_size = sizeof(global_expression_list) / sizeof(std::string);
51
52static const double global_lower_bound_x = -100.0;
53static const double global_lower_bound_y = -100.0;
54static const double global_upper_bound_x = +100.0;
55static const double global_upper_bound_y = +100.0;
56static const double global_delta = 0.0111;
57
58
59template <typename T,
60 typename Allocator,
61 template <typename,typename> class Sequence>
63 Sequence<exprtk::expression<T>,Allocator>& expr_seq)
64{
66
67 for (std::size_t i = 0; i < global_expression_list_size; ++i)
68 {
70 expression.register_symbol_table(symbol_table);
71
72 if (!parser.compile(global_expression_list[i],expression))
73 {
74 printf("[load_expression] - Parser Error: %s\tExpression: %s\n",
75 parser.error().c_str(),
76 global_expression_list[i].c_str());
77
78 return false;
79 }
80
81 expr_seq.push_back(expression);
82 }
83
84 return true;
85}
86
87template <typename T>
88void run_exprtk_benchmark(T& x, T& y,
89 exprtk::expression<T>& expression,
90 const std::string& expr_string)
91{
92 T total = T(0);
93 unsigned int count = 0;
94
95 exprtk::timer timer;
96 timer.start();
97
99 {
101 {
102 total += expression.value();
103 ++count;
104 }
105 }
106
107 timer.stop();
108
109 if (T(0) != total)
110 printf("[exprtk] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n",
111 timer.time(),
112 count / timer.time(),
113 expr_string.c_str());
114 else
115 printf("run_exprtk_benchmark() - Error running benchmark for expression: %s\n",expr_string.c_str());
116}
117
118template <typename T> struct native;
119
120template <typename T, typename NativeFunction>
121void run_native_benchmark(T& x, T& y, NativeFunction f, const std::string& expr_string)
122{
123 T total = T(0);
124 unsigned int count = 0;
125
126 exprtk::timer timer;
127 timer.start();
128
130 {
132 {
133 total += f(x,y);
134 ++count;
135 }
136 }
137
138 timer.stop();
139
140 if (T(0) != total)
141 printf("[native] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n",
142 timer.time(),
143 count / timer.time(),
144 expr_string.c_str());
145 else
146 printf("run_native_benchmark() - Error running benchmark for expression: %s\n",expr_string.c_str());
147}
148
149template <typename T>
151{
152 static const std::size_t rounds = 100000;
155
156 expression.register_symbol_table(symbol_table);
157
158 for (std::size_t i = 0; i < global_expression_list_size; ++i)
159 {
160 exprtk::timer timer;
161 timer.start();
162
163 for (std::size_t r = 0; r < rounds; ++r)
164 {
165 if (!parser.compile(global_expression_list[i],expression))
166 {
167 printf("[run_parse_benchmark] - Parser Error: %s\tExpression: %s\n",
168 parser.error().c_str(),
169 global_expression_list[i].c_str());
170
171 return false;
172 }
173 }
174
175 timer.stop();
176
177 printf("[parse] Total Time:%12.8f Rate:%14.3fparse/sec Expression: %s\n",
178 timer.time(),
179 rounds / timer.time(),
180 global_expression_list[i].c_str());
181 }
182
183 return true;
184}
185
186const double pi = 3.141592653589793238462643383279502;
187
188template <typename T>
189struct native
190{
192 typedef typename functor_t::Type Type;
193
194 static inline T avg(Type x, Type y)
195 {
196 return (x + y) / T(2);
197 }
198
199 static inline T clamp(const Type l, const Type v, const Type u)
200 {
201 return ((v < l) ? l : ((v > u) ? u : v));
202 }
203
204 static inline T func00(Type x, Type y)
205 {
206 return (y + x);
207 }
208
209 static inline T func01(Type x, Type y)
210 {
211 return T(2) * (y + x);
212 }
213
214 static inline T func02(Type x, Type y)
215 {
216 return (T(2) * y + T(2) * x);
217 }
218
219 static inline T func03(Type x, Type y)
220 {
221 return ((T(1.23) * (x * x)) / y) - T(123.123);
222 }
223
224 static inline T func04(Type x, Type y)
225 {
226 return (y + x / y) * (x - y / x);
227 }
228
229 static inline T func05(Type x, Type y)
230 {
231 return x / ((x + y) + (x - y)) / y;
232 }
233
234 static inline T func06(Type x, Type y)
235 {
236 return T(1) - ((x * y) + (y / x)) - T(3);
237 }
238
239 static inline T func07(Type x, Type y)
240 {
241 return (T(5.5) + x) + (T(2) * x - T(2) / T(3) * y) * (x / T(3) + y / T(4)) + (y + T(7.7));
242 }
243
244 static inline T func08(Type x, Type y)
245 {
246 using namespace std;
247 return (T(1.1)*pow(x,T(1))+T(2.2)*pow(y,T(2))-T(3.3)*pow(x,T(3))+T(4.4)*pow(y,T(15))-T(5.5)*pow(x,T(23))+T(6.6)*pow(y,T(55)));
248 }
249
250 static inline T func09(Type x, Type y)
251 {
252 return std::sin(T(2) * x) + std::cos(pi / y);
253 }
254
255 static inline T func10(Type x, Type y)
256 {
257 return T(1) - std::sin(T(2) * x) + std::cos(pi / y);
258 }
259
260 static inline T func11(Type x, Type y)
261 {
262 return std::sqrt(T(111.111) - std::sin(T(2) * x) + std::cos(pi / y) / T(333.333));
263 }
264
265 static inline T func12(Type x, Type y)
266 {
267 return ((x * x) / std::sin(T(2) * pi / y)) - x / T(2);
268 }
269
270 static inline T func13(Type x, Type y)
271 {
272 return (x + (std::cos(y - std::sin(T(2) / x * pi)) - std::sin(x - std::cos(T(2) * y / pi))) - y);
273 }
274
275 static inline T func14(Type x, Type y)
276 {
277 return clamp(T(-1), std::sin(T(2) * pi * x) + std::cos(y / T(2) * pi), + T(1));
278 }
279
280 static inline T func15(Type x, Type y)
281 {
282 return std::max(T(3.33), std::min(sqrt(T(1) - std::sin(T(2) * x) + std::cos(pi / y) / T(3)), T(1.11)));
283 }
284
285 static inline T func16(Type x, Type y)
286 {
287 return (((y + (x * T(2.2))) <= (x + y + T(1.1))) ? x - y : x * y) + T(2) * pi / x;
288 }
289};
290
291double pgo_primer();
292void perform_file_based_benchmark(const std::string& file_name, const std::size_t& rounds = 100000);
293
294int main(int argc, char* argv[])
295{
296 if (argc >= 2)
297 {
298 const std::string file_name = argv[1];
299
300 if (argc == 2)
302 else
303 perform_file_based_benchmark(file_name,atoi(argv[2]));
304
305 return 0;
306 }
307
308 pgo_primer();
309
310 double x = 0;
311 double y = 0;
312
313 exprtk::symbol_table<double> symbol_table;
314 symbol_table.add_constants();
315 symbol_table.add_variable("x",x);
316 symbol_table.add_variable("y",y);
317
318 std::deque<exprtk::expression<double> > compiled_expr_list;
319
320 if (!load_expression(symbol_table,compiled_expr_list))
321 {
322 return 1;
323 }
324
325 {
326 printf("--- EXPRTK ---\n");
327 for (std::size_t i = 0; i < compiled_expr_list.size(); ++i)
328 {
329 run_exprtk_benchmark(x,y,compiled_expr_list[i],global_expression_list[i]);
330 }
331 }
332
333 {
334 printf("--- NATIVE ---\n");
352 }
353
354 {
355 printf("--- PARSE ----\n");
356 run_parse_benchmark(symbol_table);
357 }
358
359 return 0;
360}
361
363{
364 static const double lower_bound_x = -50.0;
365 static const double lower_bound_y = -50.0;
366 static const double upper_bound_x = +50.0;
367 static const double upper_bound_y = +50.0;
368 static const double delta = 0.07;
369
370 double total = 0.0;
371
372 for (double x = lower_bound_x; x <= upper_bound_x; x += delta)
373 {
374 for (double y = lower_bound_y; y <= upper_bound_y; y += delta)
375 {
376 total += native<double>::func00(x,y);
377 total += native<double>::func01(x,y);
378 total += native<double>::func02(x,y);
379 total += native<double>::func03(x,y);
380 total += native<double>::func04(x,y);
381 total += native<double>::func05(x,y);
382 total += native<double>::func06(x,y);
383 total += native<double>::func07(x,y);
384 total += native<double>::func08(x,y);
385 total += native<double>::func09(x,y);
386 total += native<double>::func10(x,y);
387 total += native<double>::func11(x,y);
388 total += native<double>::func12(x,y);
389 total += native<double>::func13(x,y);
390 total += native<double>::func14(x,y);
391 total += native<double>::func15(x,y);
392 total += native<double>::func16(x,y);
393 }
394 }
395
396 return total;
397}
398
399inline std::size_t load_expression_file(const std::string& file_name, std::deque<std::string>& expression_list)
400{
401 std::ifstream stream(file_name.c_str());
402
403 if (!stream) return 0;
404
405 std::string buffer;
406 buffer.reserve(1024);
407 std::size_t line_count = 0;
408
409 while (std::getline(stream,buffer))
410 {
411 if (buffer.empty())
412 continue;
413 else if ('#' == buffer[0])
414 continue;
415
416 ++line_count;
417 expression_list.push_back(buffer);
418 }
419
420 return line_count;
421}
422
423void perform_file_based_benchmark(const std::string& file_name, const std::size_t& rounds)
424{
425 std::deque<std::string> expr_str_list;
426
427 if (0 == load_expression_file(file_name,expr_str_list))
428 {
429 printf("Failed to load any expressions from: %s\n", file_name.c_str());
430 return;
431 }
432
433 typedef exprtk::symbol_table<double> symbol_table_t;
434 typedef exprtk::expression<double> expression_t;
435 typedef exprtk::parser<double> parser_t;
436
437 std::deque<expression_t> expression_list;
438
439 symbol_table_t symbol_table;
440
441 double a = 1.1;
442 double b = 2.2;
443 double c = 3.3;
444 double x = 2.123456;
445 double y = 3.123456;
446 double z = 4.123456;
447 double w = 5.123456;
448
450
451 symbol_table.add_variable("a", a);
452 symbol_table.add_variable("b", b);
453 symbol_table.add_variable("c", c);
454
455 symbol_table.add_variable("x", x);
456 symbol_table.add_variable("y", y);
457 symbol_table.add_variable("z", z);
458 symbol_table.add_variable("w", w);
459
472
473 symbol_table.add_function("poly01", poly01);
474 symbol_table.add_function("poly02", poly02);
475 symbol_table.add_function("poly03", poly03);
476 symbol_table.add_function("poly04", poly04);
477 symbol_table.add_function("poly05", poly05);
478 symbol_table.add_function("poly06", poly06);
479 symbol_table.add_function("poly07", poly07);
480 symbol_table.add_function("poly08", poly08);
481 symbol_table.add_function("poly09", poly09);
482 symbol_table.add_function("poly10", poly10);
483 symbol_table.add_function("poly11", poly11);
484 symbol_table.add_function("poly12", poly12);
485
486 symbol_table.add_package(vector_package);
487
488
490 symbol_table.add_variable("e", e, true);
491
492 symbol_table.add_constants();
493
494 {
495 parser_t parser;
496
497 for (std::size_t i = 0; i < expr_str_list.size(); ++i)
498 {
499 expression_t expression;
500 expression.register_symbol_table(symbol_table);
501
502 if (!parser.compile(expr_str_list[i],expression))
503 {
504 printf("[perform_file_based_benchmark] - Parser Error: %s\tExpression: %s\n",
505 parser.error().c_str(),
506 expr_str_list[i].c_str());
507
508 return;
509 }
510
511 expression_list.push_back(expression);
512 }
513 }
514
515 exprtk::timer total_timer;
516 exprtk::timer timer;
517
518 double single_eval_total_time = 0.0;
519
520 total_timer.start();
521
522 for (std::size_t i = 0; i < expression_list.size(); ++i)
523 {
524 expression_t& expression = expression_list[i];
525
526 a = 1.1;
527 b = 2.2;
528 c = 3.3;
529 x = 2.123456;
530 y = 3.123456;
531 z = 4.123456;
532 w = 5.123456;
533
534 timer.start();
535 double sum = 0.0;
536
537 for (std::size_t r = 0; r < rounds; ++r)
538 {
539 sum += expression.value();
540 std::swap(a,b);
541 std::swap(x,y);
542 }
543
544 timer.stop();
545
546 printf("Expression %3d of %3d %9.3f ns\t%10d ns\t(%30.10f) '%s'\n",
547 static_cast<int>(i + 1),
548 static_cast<int>(expression_list.size()),
549 (timer.time() * 1000000000.0) / (1.0 * rounds),
550 static_cast<int>(timer.time() * 1000000000.0),
551 sum,
552 expr_str_list[i].c_str());
553
554 fflush(stdout);
555
556 single_eval_total_time += (timer.time() * 1000000000.0) / (1.0 * rounds);
557 }
558
559 total_timer.stop();
560
561 printf("[*] Number Of Evals: %15.0f\n",
562 rounds * (expression_list.size() * 1.0));
563
564 printf("[*] Total Time: %9.3fsec\n",
565 total_timer.time());
566
567 printf("[*] Total Single Eval Time: %9.3fms\n",
568 single_eval_total_time / 1000000.0);
569}
bool register_symbol_table(symbol_table< T > &st)
Definition exprtk.hpp:21726
bool compile(const std::string &expression_string, expression< T > &expr)
Definition exprtk.hpp:24443
std::string error() const
Definition exprtk.hpp:24722
bool add_variable(const std::string &variable_name, T &t, const bool is_constant=false)
Definition exprtk.hpp:20770
double time() const
Definition exprtk.hpp:43502
const std::string global_expression_list[]
double pgo_primer()
void perform_file_based_benchmark(const std::string &file_name, const std::size_t &rounds=100000)
static const double global_upper_bound_y
static const double global_lower_bound_x
bool run_parse_benchmark(exprtk::symbol_table< T > &symbol_table)
const double pi
std::size_t load_expression_file(const std::string &file_name, std::deque< std::string > &expression_list)
void run_exprtk_benchmark(T &x, T &y, exprtk::expression< T > &expression, const std::string &expr_string)
void run_native_benchmark(T &x, T &y, NativeFunction f, const std::string &expr_string)
static const double global_delta
bool load_expression(exprtk::symbol_table< T > &symbol_table, Sequence< exprtk::expression< T >, Allocator > &expr_seq)
static const double global_lower_bound_y
const std::size_t global_expression_list_size
static const double global_upper_bound_x
static const std::size_t rounds
static const double upper_bound_y
static const double upper_bound_x
static const double delta
static const double lower_bound_x
static const double lower_bound_y
const real::type pi
static const std::string expression_list[]
static T func06(Type x, Type y)
static T func09(Type x, Type y)
static T func16(Type x, Type y)
static T func11(Type x, Type y)
static T func10(Type x, Type y)
static T func08(Type x, Type y)
static T func12(Type x, Type y)
static T func04(Type x, Type y)
static T clamp(const Type l, const Type v, const Type u)
static T func02(Type x, Type y)
exprtk::details::functor_t< T > functor_t
static T func15(Type x, Type y)
static T func00(Type x, Type y)
static T func03(Type x, Type y)
static T func13(Type x, Type y)
static T func07(Type x, Type y)
static T avg(Type x, Type y)
functor_t::Type Type
static T func05(Type x, Type y)
static T func14(Type x, Type y)
static T func01(Type x, Type y)