Line data Source code
1 : /*
2 : * Copyright (c) 2002-2006 Michael Niedermayer <michaelni@gmx.at>
3 : * Copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
4 : *
5 : * This file is part of Libav.
6 : *
7 : * Libav is free software; you can redistribute it and/or
8 : * modify it under the terms of the GNU Lesser General Public
9 : * License as published by the Free Software Foundation; either
10 : * version 2.1 of the License, or (at your option) any later version.
11 : *
12 : * Libav is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * Lesser General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU Lesser General Public
18 : * License along with Libav; if not, write to the Free Software
19 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 : */
21 :
22 : /**
23 : * @file
24 : * simple arithmetic expression evaluator.
25 : *
26 : * see http://joe.hotchkiss.com/programming/eval/eval.html
27 : */
28 :
29 : #include "attributes.h"
30 : #include "avutil.h"
31 : #include "common.h"
32 : #include "eval.h"
33 : #include "log.h"
34 : #include "mathematics.h"
35 : #include "avstring.h"
36 : #include "timer.h"
37 :
38 : typedef struct Parser {
39 : const AVClass *class;
40 : int stack_index;
41 : char *s;
42 : const double *const_values;
43 : const char * const *const_names; // NULL terminated
44 : double (* const *funcs1)(void *, double a); // NULL terminated
45 : const char * const *func1_names; // NULL terminated
46 : double (* const *funcs2)(void *, double a, double b); // NULL terminated
47 : const char * const *func2_names; // NULL terminated
48 : void *opaque;
49 : int log_offset;
50 : void *log_ctx;
51 : #define VARS 10
52 : double var[VARS];
53 : } Parser;
54 :
55 : static const AVClass class = { "Eval", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, offsetof(Parser,log_offset), offsetof(Parser,log_ctx) };
56 :
57 : static const int8_t si_prefixes['z' - 'E' + 1] = {
58 : ['y'-'E']= -24,
59 : ['z'-'E']= -21,
60 : ['a'-'E']= -18,
61 : ['f'-'E']= -15,
62 : ['p'-'E']= -12,
63 : ['n'-'E']= - 9,
64 : ['u'-'E']= - 6,
65 : ['m'-'E']= - 3,
66 : ['c'-'E']= - 2,
67 : ['d'-'E']= - 1,
68 : ['h'-'E']= 2,
69 : ['k'-'E']= 3,
70 : ['K'-'E']= 3,
71 : ['M'-'E']= 6,
72 : ['G'-'E']= 9,
73 : ['T'-'E']= 12,
74 : ['P'-'E']= 15,
75 : ['E'-'E']= 18,
76 : ['Z'-'E']= 21,
77 : ['Y'-'E']= 24,
78 : };
79 :
80 0 : double av_strtod(const char *numstr, char **tail)
81 : {
82 : double d;
83 : char *next;
84 0 : d = strtod(numstr, &next);
85 : /* if parsing succeeded, check for and interpret postfixes */
86 0 : if (next!=numstr) {
87 0 : if (next[0] == 'd' && next[1] == 'B') {
88 : /* treat dB as decibels instead of decibytes */
89 0 : d = pow(10, d / 20);
90 0 : next += 2;
91 0 : } else if (*next >= 'E' && *next <= 'z') {
92 0 : int e= si_prefixes[*next - 'E'];
93 0 : if (e) {
94 0 : if (next[1] == 'i') {
95 0 : d*= pow( 2, e/0.3);
96 0 : next+=2;
97 : } else {
98 0 : d*= pow(10, e);
99 0 : next++;
100 : }
101 : }
102 : }
103 :
104 0 : if (*next=='B') {
105 0 : d*=8;
106 0 : next++;
107 : }
108 : }
109 : /* if requested, fill in tail with the position after the last parsed
110 : character */
111 0 : if (tail)
112 0 : *tail = next;
113 0 : return d;
114 : }
115 :
116 : #define IS_IDENTIFIER_CHAR(c) ((c) - '0' <= 9U || (c) - 'a' <= 25U || (c) - 'A' <= 25U || (c) == '_')
117 :
118 0 : static int strmatch(const char *s, const char *prefix)
119 : {
120 : int i;
121 0 : for (i=0; prefix[i]; i++) {
122 0 : if (prefix[i] != s[i]) return 0;
123 : }
124 : /* return 1 only if the s identifier is terminated */
125 0 : return !IS_IDENTIFIER_CHAR(s[i]);
126 : }
127 :
128 : struct AVExpr {
129 : enum {
130 : e_value, e_const, e_func0, e_func1, e_func2,
131 : e_squish, e_gauss, e_ld, e_isnan, e_isinf,
132 : e_mod, e_max, e_min, e_eq, e_gt, e_gte,
133 : e_pow, e_mul, e_div, e_add,
134 : e_last, e_st, e_while, e_floor, e_ceil, e_trunc,
135 : e_sqrt, e_not,
136 : } type;
137 : double value; // is sign in other types
138 : union {
139 : int const_index;
140 : double (*func0)(double);
141 : double (*func1)(void *, double);
142 : double (*func2)(void *, double, double);
143 : } a;
144 : struct AVExpr *param[2];
145 : };
146 :
147 0 : static double eval_expr(Parser *p, AVExpr *e)
148 : {
149 0 : switch (e->type) {
150 0 : case e_value: return e->value;
151 0 : case e_const: return e->value * p->const_values[e->a.const_index];
152 0 : case e_func0: return e->value * e->a.func0(eval_expr(p, e->param[0]));
153 0 : case e_func1: return e->value * e->a.func1(p->opaque, eval_expr(p, e->param[0]));
154 0 : case e_func2: return e->value * e->a.func2(p->opaque, eval_expr(p, e->param[0]), eval_expr(p, e->param[1]));
155 0 : case e_squish: return 1/(1+exp(4*eval_expr(p, e->param[0])));
156 0 : case e_gauss: { double d = eval_expr(p, e->param[0]); return exp(-d*d/2)/sqrt(2*M_PI); }
157 0 : case e_ld: return e->value * p->var[av_clip(eval_expr(p, e->param[0]), 0, VARS-1)];
158 0 : case e_isnan: return e->value * !!isnan(eval_expr(p, e->param[0]));
159 0 : case e_isinf: return e->value * !!isinf(eval_expr(p, e->param[0]));
160 0 : case e_floor: return e->value * floor(eval_expr(p, e->param[0]));
161 0 : case e_ceil : return e->value * ceil (eval_expr(p, e->param[0]));
162 0 : case e_trunc: return e->value * trunc(eval_expr(p, e->param[0]));
163 0 : case e_sqrt: return e->value * sqrt (eval_expr(p, e->param[0]));
164 0 : case e_not: return e->value * eval_expr(p, e->param[0]) == 0;
165 : case e_while: {
166 0 : double d = NAN;
167 0 : while (eval_expr(p, e->param[0]))
168 0 : d=eval_expr(p, e->param[1]);
169 0 : return d;
170 : }
171 : default: {
172 0 : double d = eval_expr(p, e->param[0]);
173 0 : double d2 = eval_expr(p, e->param[1]);
174 0 : switch (e->type) {
175 0 : case e_mod: return e->value * (d - floor(d/d2)*d2);
176 0 : case e_max: return e->value * (d > d2 ? d : d2);
177 0 : case e_min: return e->value * (d < d2 ? d : d2);
178 0 : case e_eq: return e->value * (d == d2 ? 1.0 : 0.0);
179 0 : case e_gt: return e->value * (d > d2 ? 1.0 : 0.0);
180 0 : case e_gte: return e->value * (d >= d2 ? 1.0 : 0.0);
181 0 : case e_pow: return e->value * pow(d, d2);
182 0 : case e_mul: return e->value * (d * d2);
183 0 : case e_div: return e->value * (d / d2);
184 0 : case e_add: return e->value * (d + d2);
185 0 : case e_last:return e->value * d2;
186 0 : case e_st : return e->value * (p->var[av_clip(d, 0, VARS-1)]= d2);
187 : }
188 : }
189 : }
190 0 : return NAN;
191 : }
192 :
193 : static int parse_expr(AVExpr **e, Parser *p);
194 :
195 0 : void av_expr_free(AVExpr *e)
196 : {
197 0 : if (!e) return;
198 0 : av_expr_free(e->param[0]);
199 0 : av_expr_free(e->param[1]);
200 0 : av_freep(&e);
201 : }
202 :
203 0 : static int parse_primary(AVExpr **e, Parser *p)
204 : {
205 0 : AVExpr *d = av_mallocz(sizeof(AVExpr));
206 0 : char *next = p->s, *s0 = p->s;
207 : int ret, i;
208 :
209 0 : if (!d)
210 0 : return AVERROR(ENOMEM);
211 :
212 : /* number */
213 0 : d->value = av_strtod(p->s, &next);
214 0 : if (next != p->s) {
215 0 : d->type = e_value;
216 0 : p->s= next;
217 0 : *e = d;
218 0 : return 0;
219 : }
220 0 : d->value = 1;
221 :
222 : /* named constants */
223 0 : for (i=0; p->const_names && p->const_names[i]; i++) {
224 0 : if (strmatch(p->s, p->const_names[i])) {
225 0 : p->s+= strlen(p->const_names[i]);
226 0 : d->type = e_const;
227 0 : d->a.const_index = i;
228 0 : *e = d;
229 0 : return 0;
230 : }
231 : }
232 :
233 0 : p->s= strchr(p->s, '(');
234 0 : if (!p->s) {
235 0 : av_log(p, AV_LOG_ERROR, "Undefined constant or missing '(' in '%s'\n", s0);
236 0 : p->s= next;
237 0 : av_expr_free(d);
238 0 : return AVERROR(EINVAL);
239 : }
240 0 : p->s++; // "("
241 0 : if (*next == '(') { // special case do-nothing
242 0 : av_freep(&d);
243 0 : if ((ret = parse_expr(&d, p)) < 0)
244 0 : return ret;
245 0 : if (p->s[0] != ')') {
246 0 : av_log(p, AV_LOG_ERROR, "Missing ')' in '%s'\n", s0);
247 0 : av_expr_free(d);
248 0 : return AVERROR(EINVAL);
249 : }
250 0 : p->s++; // ")"
251 0 : *e = d;
252 0 : return 0;
253 : }
254 0 : if ((ret = parse_expr(&(d->param[0]), p)) < 0) {
255 0 : av_expr_free(d);
256 0 : return ret;
257 : }
258 0 : if (p->s[0]== ',') {
259 0 : p->s++; // ","
260 0 : parse_expr(&d->param[1], p);
261 : }
262 0 : if (p->s[0] != ')') {
263 0 : av_log(p, AV_LOG_ERROR, "Missing ')' or too many args in '%s'\n", s0);
264 0 : av_expr_free(d);
265 0 : return AVERROR(EINVAL);
266 : }
267 0 : p->s++; // ")"
268 :
269 0 : d->type = e_func0;
270 0 : if (strmatch(next, "sinh" )) d->a.func0 = sinh;
271 0 : else if (strmatch(next, "cosh" )) d->a.func0 = cosh;
272 0 : else if (strmatch(next, "tanh" )) d->a.func0 = tanh;
273 0 : else if (strmatch(next, "sin" )) d->a.func0 = sin;
274 0 : else if (strmatch(next, "cos" )) d->a.func0 = cos;
275 0 : else if (strmatch(next, "tan" )) d->a.func0 = tan;
276 0 : else if (strmatch(next, "atan" )) d->a.func0 = atan;
277 0 : else if (strmatch(next, "asin" )) d->a.func0 = asin;
278 0 : else if (strmatch(next, "acos" )) d->a.func0 = acos;
279 0 : else if (strmatch(next, "exp" )) d->a.func0 = exp;
280 0 : else if (strmatch(next, "log" )) d->a.func0 = log;
281 0 : else if (strmatch(next, "abs" )) d->a.func0 = fabs;
282 0 : else if (strmatch(next, "squish")) d->type = e_squish;
283 0 : else if (strmatch(next, "gauss" )) d->type = e_gauss;
284 0 : else if (strmatch(next, "mod" )) d->type = e_mod;
285 0 : else if (strmatch(next, "max" )) d->type = e_max;
286 0 : else if (strmatch(next, "min" )) d->type = e_min;
287 0 : else if (strmatch(next, "eq" )) d->type = e_eq;
288 0 : else if (strmatch(next, "gte" )) d->type = e_gte;
289 0 : else if (strmatch(next, "gt" )) d->type = e_gt;
290 0 : else if (strmatch(next, "lte" )) { AVExpr *tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gte; }
291 0 : else if (strmatch(next, "lt" )) { AVExpr *tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gt; }
292 0 : else if (strmatch(next, "ld" )) d->type = e_ld;
293 0 : else if (strmatch(next, "isnan" )) d->type = e_isnan;
294 0 : else if (strmatch(next, "isinf" )) d->type = e_isinf;
295 0 : else if (strmatch(next, "st" )) d->type = e_st;
296 0 : else if (strmatch(next, "while" )) d->type = e_while;
297 0 : else if (strmatch(next, "floor" )) d->type = e_floor;
298 0 : else if (strmatch(next, "ceil" )) d->type = e_ceil;
299 0 : else if (strmatch(next, "trunc" )) d->type = e_trunc;
300 0 : else if (strmatch(next, "sqrt" )) d->type = e_sqrt;
301 0 : else if (strmatch(next, "not" )) d->type = e_not;
302 : else {
303 0 : for (i=0; p->func1_names && p->func1_names[i]; i++) {
304 0 : if (strmatch(next, p->func1_names[i])) {
305 0 : d->a.func1 = p->funcs1[i];
306 0 : d->type = e_func1;
307 0 : *e = d;
308 0 : return 0;
309 : }
310 : }
311 :
312 0 : for (i=0; p->func2_names && p->func2_names[i]; i++) {
313 0 : if (strmatch(next, p->func2_names[i])) {
314 0 : d->a.func2 = p->funcs2[i];
315 0 : d->type = e_func2;
316 0 : *e = d;
317 0 : return 0;
318 : }
319 : }
320 :
321 0 : av_log(p, AV_LOG_ERROR, "Unknown function in '%s'\n", s0);
322 0 : av_expr_free(d);
323 0 : return AVERROR(EINVAL);
324 : }
325 :
326 0 : *e = d;
327 0 : return 0;
328 : }
329 :
330 0 : static AVExpr *new_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1)
331 : {
332 0 : AVExpr *e = av_mallocz(sizeof(AVExpr));
333 0 : if (!e)
334 0 : return NULL;
335 0 : e->type =type ;
336 0 : e->value =value ;
337 0 : e->param[0] =p0 ;
338 0 : e->param[1] =p1 ;
339 0 : return e;
340 : }
341 :
342 0 : static int parse_pow(AVExpr **e, Parser *p, int *sign)
343 : {
344 0 : *sign= (*p->s == '+') - (*p->s == '-');
345 0 : p->s += *sign&1;
346 0 : return parse_primary(e, p);
347 : }
348 :
349 0 : static int parse_dB(AVExpr **e, Parser *p, int *sign)
350 : {
351 : /* do not filter out the negative sign when parsing a dB value.
352 : for example, -3dB is not the same as -(3dB) */
353 0 : if (*p->s == '-') {
354 : char *next;
355 0 : double av_unused ignored = strtod(p->s, &next);
356 0 : if (next != p->s && next[0] == 'd' && next[1] == 'B') {
357 0 : *sign = 0;
358 0 : return parse_primary(e, p);
359 : }
360 : }
361 0 : return parse_pow(e, p, sign);
362 : }
363 :
364 0 : static int parse_factor(AVExpr **e, Parser *p)
365 : {
366 : int sign, sign2, ret;
367 : AVExpr *e0, *e1, *e2;
368 0 : if ((ret = parse_dB(&e0, p, &sign)) < 0)
369 0 : return ret;
370 0 : while(p->s[0]=='^'){
371 0 : e1 = e0;
372 0 : p->s++;
373 0 : if ((ret = parse_dB(&e2, p, &sign2)) < 0) {
374 0 : av_expr_free(e1);
375 0 : return ret;
376 : }
377 0 : e0 = new_eval_expr(e_pow, 1, e1, e2);
378 0 : if (!e0) {
379 0 : av_expr_free(e1);
380 0 : av_expr_free(e2);
381 0 : return AVERROR(ENOMEM);
382 : }
383 0 : if (e0->param[1]) e0->param[1]->value *= (sign2|1);
384 : }
385 0 : if (e0) e0->value *= (sign|1);
386 :
387 0 : *e = e0;
388 0 : return 0;
389 : }
390 :
391 0 : static int parse_term(AVExpr **e, Parser *p)
392 : {
393 : int ret;
394 : AVExpr *e0, *e1, *e2;
395 0 : if ((ret = parse_factor(&e0, p)) < 0)
396 0 : return ret;
397 0 : while (p->s[0]=='*' || p->s[0]=='/') {
398 0 : int c= *p->s++;
399 0 : e1 = e0;
400 0 : if ((ret = parse_factor(&e2, p)) < 0) {
401 0 : av_expr_free(e1);
402 0 : return ret;
403 : }
404 0 : e0 = new_eval_expr(c == '*' ? e_mul : e_div, 1, e1, e2);
405 0 : if (!e0) {
406 0 : av_expr_free(e1);
407 0 : av_expr_free(e2);
408 0 : return AVERROR(ENOMEM);
409 : }
410 : }
411 0 : *e = e0;
412 0 : return 0;
413 : }
414 :
415 0 : static int parse_subexpr(AVExpr **e, Parser *p)
416 : {
417 : int ret;
418 : AVExpr *e0, *e1, *e2;
419 0 : if ((ret = parse_term(&e0, p)) < 0)
420 0 : return ret;
421 0 : while (*p->s == '+' || *p->s == '-') {
422 0 : e1 = e0;
423 0 : if ((ret = parse_term(&e2, p)) < 0) {
424 0 : av_expr_free(e1);
425 0 : return ret;
426 : }
427 0 : e0 = new_eval_expr(e_add, 1, e1, e2);
428 0 : if (!e0) {
429 0 : av_expr_free(e1);
430 0 : av_expr_free(e2);
431 0 : return AVERROR(ENOMEM);
432 : }
433 : };
434 :
435 0 : *e = e0;
436 0 : return 0;
437 : }
438 :
439 0 : static int parse_expr(AVExpr **e, Parser *p)
440 : {
441 : int ret;
442 : AVExpr *e0, *e1, *e2;
443 0 : if (p->stack_index <= 0) //protect against stack overflows
444 0 : return AVERROR(EINVAL);
445 0 : p->stack_index--;
446 :
447 0 : if ((ret = parse_subexpr(&e0, p)) < 0)
448 0 : return ret;
449 0 : while (*p->s == ';') {
450 0 : p->s++;
451 0 : e1 = e0;
452 0 : if ((ret = parse_subexpr(&e2, p)) < 0) {
453 0 : av_expr_free(e1);
454 0 : return ret;
455 : }
456 0 : e0 = new_eval_expr(e_last, 1, e1, e2);
457 0 : if (!e0) {
458 0 : av_expr_free(e1);
459 0 : av_expr_free(e2);
460 0 : return AVERROR(ENOMEM);
461 : }
462 : };
463 :
464 0 : p->stack_index++;
465 0 : *e = e0;
466 0 : return 0;
467 : }
468 :
469 0 : static int verify_expr(AVExpr *e)
470 : {
471 0 : if (!e) return 0;
472 0 : switch (e->type) {
473 : case e_value:
474 0 : case e_const: return 1;
475 : case e_func0:
476 : case e_func1:
477 : case e_squish:
478 : case e_ld:
479 : case e_gauss:
480 : case e_isnan:
481 : case e_isinf:
482 : case e_floor:
483 : case e_ceil:
484 : case e_trunc:
485 : case e_sqrt:
486 : case e_not:
487 0 : return verify_expr(e->param[0]);
488 0 : default: return verify_expr(e->param[0]) && verify_expr(e->param[1]);
489 : }
490 : }
491 :
492 0 : int av_expr_parse(AVExpr **expr, const char *s,
493 : const char * const *const_names,
494 : const char * const *func1_names, double (* const *funcs1)(void *, double),
495 : const char * const *func2_names, double (* const *funcs2)(void *, double, double),
496 : int log_offset, void *log_ctx)
497 : {
498 0 : Parser p = { 0 };
499 0 : AVExpr *e = NULL;
500 0 : char *w = av_malloc(strlen(s) + 1);
501 0 : char *wp = w;
502 0 : const char *s0 = s;
503 0 : int ret = 0;
504 :
505 0 : if (!w)
506 0 : return AVERROR(ENOMEM);
507 :
508 0 : while (*s)
509 0 : if (!av_isspace(*s++)) *wp++ = s[-1];
510 0 : *wp++ = 0;
511 :
512 0 : p.class = &class;
513 0 : p.stack_index=100;
514 0 : p.s= w;
515 0 : p.const_names = const_names;
516 0 : p.funcs1 = funcs1;
517 0 : p.func1_names = func1_names;
518 0 : p.funcs2 = funcs2;
519 0 : p.func2_names = func2_names;
520 0 : p.log_offset = log_offset;
521 0 : p.log_ctx = log_ctx;
522 :
523 0 : if ((ret = parse_expr(&e, &p)) < 0)
524 0 : goto end;
525 0 : if (*p.s) {
526 0 : av_expr_free(e);
527 0 : av_log(&p, AV_LOG_ERROR, "Invalid chars '%s' at the end of expression '%s'\n", p.s, s0);
528 0 : ret = AVERROR(EINVAL);
529 0 : goto end;
530 : }
531 0 : if (!verify_expr(e)) {
532 0 : av_expr_free(e);
533 0 : ret = AVERROR(EINVAL);
534 0 : goto end;
535 : }
536 0 : *expr = e;
537 : end:
538 0 : av_free(w);
539 0 : return ret;
540 : }
541 :
542 0 : double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
543 : {
544 0 : Parser p = { 0 };
545 :
546 0 : p.const_values = const_values;
547 0 : p.opaque = opaque;
548 0 : return eval_expr(&p, e);
549 : }
550 :
551 0 : int av_expr_parse_and_eval(double *d, const char *s,
552 : const char * const *const_names, const double *const_values,
553 : const char * const *func1_names, double (* const *funcs1)(void *, double),
554 : const char * const *func2_names, double (* const *funcs2)(void *, double, double),
555 : void *opaque, int log_offset, void *log_ctx)
556 : {
557 0 : AVExpr *e = NULL;
558 0 : int ret = av_expr_parse(&e, s, const_names, func1_names, funcs1, func2_names, funcs2, log_offset, log_ctx);
559 :
560 0 : if (ret < 0) {
561 0 : *d = NAN;
562 0 : return ret;
563 : }
564 0 : *d = av_expr_eval(e, const_values, opaque);
565 0 : av_expr_free(e);
566 0 : return isnan(*d) ? AVERROR(EINVAL) : 0;
567 : }
568 :
569 : #ifdef TEST
570 : #include <string.h>
571 :
572 : static const double const_values[] = {
573 : M_PI,
574 : M_E,
575 : 0
576 : };
577 :
578 : static const char *const const_names[] = {
579 : "PI",
580 : "E",
581 : 0
582 : };
583 :
584 : int main(int argc, char **argv)
585 : {
586 : int i;
587 : double d;
588 : const char *const *expr;
589 : static const char *const exprs[] = {
590 : "",
591 : "1;2",
592 : "-20",
593 : "-PI",
594 : "+PI",
595 : "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)",
596 : "80G/80Gi",
597 : "1k",
598 : "1Gi",
599 : "1gi",
600 : "1GiFoo",
601 : "1k+1k",
602 : "1Gi*3foo",
603 : "foo",
604 : "foo(",
605 : "foo()",
606 : "foo)",
607 : "sin",
608 : "sin(",
609 : "sin()",
610 : "sin)",
611 : "sin 10",
612 : "sin(1,2,3)",
613 : "sin(1 )",
614 : "1",
615 : "1foo",
616 : "bar + PI + E + 100f*2 + foo",
617 : "13k + 12f - foo(1, 2)",
618 : "1gi",
619 : "1Gi",
620 : "st(0, 123)",
621 : "st(1, 123); ld(1)",
622 : "lte(0, 1)",
623 : "lte(1, 1)",
624 : "lte(1, 0)",
625 : "lt(0, 1)",
626 : "lt(1, 1)",
627 : "gt(1, 0)",
628 : "gt(2, 7)",
629 : "gte(122, 122)",
630 : /* compute 1+2+...+N */
631 : "st(0, 1); while(lte(ld(0), 100), st(1, ld(1)+ld(0));st(0, ld(0)+1)); ld(1)",
632 : /* compute Fib(N) */
633 : "st(1, 1); st(2, 2); st(0, 1); while(lte(ld(0),10), st(3, ld(1)+ld(2)); st(1, ld(2)); st(2, ld(3)); st(0, ld(0)+1)); ld(3)",
634 : "while(0, 10)",
635 : "st(0, 1); while(lte(ld(0),100), st(1, ld(1)+ld(0)); st(0, ld(0)+1))",
636 : "isnan(1)",
637 : "isnan(NAN)",
638 : "isnan(INF)",
639 : "isinf(1)",
640 : "isinf(NAN)",
641 : "isinf(INF)",
642 : "floor(NAN)",
643 : "floor(123.123)",
644 : "floor(-123.123)",
645 : "trunc(123.123)",
646 : "trunc(-123.123)",
647 : "ceil(123.123)",
648 : "ceil(-123.123)",
649 : "sqrt(1764)",
650 : "isnan(sqrt(-1))",
651 : "not(1)",
652 : "not(NAN)",
653 : "not(0)",
654 : "6.0206dB",
655 : "-3.0103dB",
656 : NULL
657 : };
658 :
659 : for (expr = exprs; *expr; expr++) {
660 : printf("Evaluating '%s'\n", *expr);
661 : av_expr_parse_and_eval(&d, *expr,
662 : const_names, const_values,
663 : NULL, NULL, NULL, NULL, NULL, 0, NULL);
664 : if (isnan(d))
665 : printf("'%s' -> nan\n\n", *expr);
666 : else
667 : printf("'%s' -> %f\n\n", *expr, d);
668 : }
669 :
670 : av_expr_parse_and_eval(&d, "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)",
671 : const_names, const_values,
672 : NULL, NULL, NULL, NULL, NULL, 0, NULL);
673 : printf("%f == 12.7\n", d);
674 : av_expr_parse_and_eval(&d, "80G/80Gi",
675 : const_names, const_values,
676 : NULL, NULL, NULL, NULL, NULL, 0, NULL);
677 : printf("%f == 0.931322575\n", d);
678 :
679 : if (argc > 1 && !strcmp(argv[1], "-t")) {
680 : for (i = 0; i < 1050; i++) {
681 : START_TIMER;
682 : av_expr_parse_and_eval(&d, "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)",
683 : const_names, const_values,
684 : NULL, NULL, NULL, NULL, NULL, 0, NULL);
685 : STOP_TIMER("av_expr_parse_and_eval");
686 : }
687 : }
688 :
689 : return 0;
690 : }
691 : #endif
|