Mercurial > libavcodec.hg
annotate eval.c @ 3990:746a60ba3177 libavcodec
enable CMOV_IS_FAST as its faster or equal speed on every cpu (duron, athlon, PM, P3) from which ive seen benchmarks, it might be slower on P4 but noone has posted benchmarks ...
author | michael |
---|---|
date | Wed, 11 Oct 2006 12:23:40 +0000 |
parents | c8c591fe26f8 |
children | 5160e1bdeff2 |
rev | line source |
---|---|
612 | 1 /* |
2 * simple arithmetic expression evaluator | |
3 * | |
4 * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at> | |
5 * | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3920
diff
changeset
|
6 * This file is part of FFmpeg. |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3920
diff
changeset
|
7 * |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3920
diff
changeset
|
8 * FFmpeg is free software; you can redistribute it and/or |
612 | 9 * modify it under the terms of the GNU Lesser General Public |
10 * License as published by the Free Software Foundation; either | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3920
diff
changeset
|
11 * version 2.1 of the License, or (at your option) any later version. |
612 | 12 * |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3920
diff
changeset
|
13 * FFmpeg is distributed in the hope that it will be useful, |
612 | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 * Lesser General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU Lesser General Public | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3920
diff
changeset
|
19 * License along with FFmpeg; if not, write to the Free Software |
3036
0b546eab515d
Update licensing information: The FSF changed postal address.
diego
parents:
2967
diff
changeset
|
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
612 | 21 * |
22 */ | |
23 | |
1106 | 24 /** |
25 * @file eval.c | |
26 * simple arithmetic expression evaluator. | |
27 * | |
612 | 28 * see http://joe.hotchkiss.com/programming/eval/eval.html |
29 */ | |
30 | |
1057 | 31 #include "avcodec.h" |
32 #include "mpegvideo.h" | |
33 | |
612 | 34 #include <stdio.h> |
35 #include <stdlib.h> | |
36 #include <string.h> | |
37 #include <math.h> | |
38 | |
614
b786f15df503
NAN doesnt exist on FreeBSD patch by (Rmi Guyomarch <rguyom at pobox dot com>)
michaelni
parents:
612
diff
changeset
|
39 #ifndef NAN |
3753 | 40 #define NAN 0.0/0.0 |
614
b786f15df503
NAN doesnt exist on FreeBSD patch by (Rmi Guyomarch <rguyom at pobox dot com>)
michaelni
parents:
612
diff
changeset
|
41 #endif |
b786f15df503
NAN doesnt exist on FreeBSD patch by (Rmi Guyomarch <rguyom at pobox dot com>)
michaelni
parents:
612
diff
changeset
|
42 |
627 | 43 #ifndef M_PI |
44 #define M_PI 3.14159265358979323846 | |
45 #endif | |
46 | |
612 | 47 typedef struct Parser{ |
48 int stack_index; | |
49 char *s; | |
50 double *const_value; | |
1057 | 51 const char **const_name; // NULL terminated |
612 | 52 double (**func1)(void *, double a); // NULL terminated |
1057 | 53 const char **func1_name; // NULL terminated |
612 | 54 double (**func2)(void *, double a, double b); // NULL terminated |
55 char **func2_name; // NULL terminated | |
56 void *opaque; | |
3770
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
57 char **error; |
612 | 58 } Parser; |
59 | |
3778 | 60 static double evalExpression(Parser *p); |
61 | |
62 static int8_t si_prefixes['z' - 'E' + 1]={ | |
63 ['y'-'E']= -24, | |
64 ['z'-'E']= -21, | |
65 ['a'-'E']= -18, | |
66 ['f'-'E']= -15, | |
67 ['p'-'E']= -12, | |
68 ['n'-'E']= - 9, | |
69 ['u'-'E']= - 6, | |
70 ['m'-'E']= - 3, | |
71 ['c'-'E']= - 2, | |
72 ['d'-'E']= - 1, | |
73 ['h'-'E']= 2, | |
74 ['k'-'E']= 3, | |
75 ['K'-'E']= 3, | |
76 ['M'-'E']= 6, | |
77 ['G'-'E']= 9, | |
78 ['T'-'E']= 12, | |
79 ['P'-'E']= 15, | |
80 ['E'-'E']= 18, | |
81 ['Z'-'E']= 21, | |
82 ['Y'-'E']= 24, | |
83 }; | |
3756 | 84 |
3778 | 85 /** strtod() function extended with 'k', 'M', 'G', 'ki', 'Mi', 'Gi' and 'B' |
86 * postfixes. This allows using f.e. kB, MiB, G and B as a postfix. This | |
87 * function assumes that the unit of numbers is bits not bytes. | |
88 */ | |
89 static double av_strtod(const char *name, char **tail) { | |
90 double d; | |
91 char *next; | |
92 d = strtod(name, &next); | |
93 /* if parsing succeeded, check for and interpret postfixes */ | |
94 if (next!=name) { | |
95 | |
96 if(*next >= 'E' && *next <= 'z'){ | |
97 int e= si_prefixes[*next - 'E']; | |
98 if(e){ | |
99 if(next[1] == 'i'){ | |
100 d*= pow( 2, e/0.3); | |
101 next+=2; | |
102 }else{ | |
103 d*= pow(10, e); | |
104 next++; | |
105 } | |
106 } | |
107 } | |
108 | |
109 if(*next=='B') { | |
110 d*=8; | |
111 *next++; | |
112 } | |
113 } | |
114 /* if requested, fill in tail with the position after the last parsed | |
115 character */ | |
116 if (tail) | |
117 *tail = next; | |
118 return d; | |
119 } | |
612 | 120 |
1057 | 121 static int strmatch(const char *s, const char *prefix){ |
612 | 122 int i; |
123 for(i=0; prefix[i]; i++){ | |
124 if(prefix[i] != s[i]) return 0; | |
125 } | |
126 return 1; | |
127 } | |
128 | |
2434 | 129 static double evalPrimary(Parser *p){ |
612 | 130 double d, d2=NAN; |
131 char *next= p->s; | |
132 int i; | |
133 | |
134 /* number */ | |
3731
8b8773577dd9
Add support for SI (k, M, ...) and IEC/IEEE (Ki, Mi, ...) units.
takis
parents:
3730
diff
changeset
|
135 d= av_strtod(p->s, &next); |
612 | 136 if(next != p->s){ |
137 p->s= next; | |
2434 | 138 return d; |
612 | 139 } |
2967 | 140 |
612 | 141 /* named constants */ |
2433 | 142 for(i=0; p->const_name && p->const_name[i]; i++){ |
612 | 143 if(strmatch(p->s, p->const_name[i])){ |
144 p->s+= strlen(p->const_name[i]); | |
2434 | 145 return p->const_value[i]; |
612 | 146 } |
147 } | |
2967 | 148 |
612 | 149 p->s= strchr(p->s, '('); |
150 if(p->s==NULL){ | |
3770
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
151 *p->error = "missing ("; |
3754 | 152 p->s= next; |
2434 | 153 return NAN; |
612 | 154 } |
155 p->s++; // "(" | |
2434 | 156 d= evalExpression(p); |
1815 | 157 if(p->s[0]== ','){ |
158 p->s++; // "," | |
2434 | 159 d2= evalExpression(p); |
612 | 160 } |
1815 | 161 if(p->s[0] != ')'){ |
3770
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
162 *p->error = "missing )"; |
2434 | 163 return NAN; |
1815 | 164 } |
165 p->s++; // ")" | |
2967 | 166 |
612 | 167 if( strmatch(next, "sinh" ) ) d= sinh(d); |
168 else if( strmatch(next, "cosh" ) ) d= cosh(d); | |
169 else if( strmatch(next, "tanh" ) ) d= tanh(d); | |
170 else if( strmatch(next, "sin" ) ) d= sin(d); | |
171 else if( strmatch(next, "cos" ) ) d= cos(d); | |
172 else if( strmatch(next, "tan" ) ) d= tan(d); | |
173 else if( strmatch(next, "exp" ) ) d= exp(d); | |
174 else if( strmatch(next, "log" ) ) d= log(d); | |
175 else if( strmatch(next, "squish") ) d= 1/(1+exp(4*d)); | |
176 else if( strmatch(next, "gauss" ) ) d= exp(-d*d/2)/sqrt(2*M_PI); | |
1057 | 177 else if( strmatch(next, "abs" ) ) d= fabs(d); |
3755 | 178 else if( strmatch(next, "max" ) ) d= d > d2 ? d : d2; |
179 else if( strmatch(next, "min" ) ) d= d < d2 ? d : d2; | |
180 else if( strmatch(next, "gt" ) ) d= d > d2 ? 1.0 : 0.0; | |
181 else if( strmatch(next, "gte" ) ) d= d >= d2 ? 1.0 : 0.0; | |
182 else if( strmatch(next, "lt" ) ) d= d > d2 ? 0.0 : 1.0; | |
183 else if( strmatch(next, "lte" ) ) d= d >= d2 ? 0.0 : 1.0; | |
612 | 184 else if( strmatch(next, "eq" ) ) d= d == d2 ? 1.0 : 0.0; |
2434 | 185 else if( strmatch(next, "(" ) ) d= d; |
612 | 186 // else if( strmatch(next, "l1" ) ) d= 1 + d2*(d - 1); |
187 // else if( strmatch(next, "sq01" ) ) d= (d >= 0.0 && d <=1.0) ? 1.0 : 0.0; | |
188 else{ | |
189 for(i=0; p->func1_name && p->func1_name[i]; i++){ | |
190 if(strmatch(next, p->func1_name[i])){ | |
2434 | 191 return p->func1[i](p->opaque, d); |
612 | 192 } |
193 } | |
194 | |
195 for(i=0; p->func2_name && p->func2_name[i]; i++){ | |
196 if(strmatch(next, p->func2_name[i])){ | |
2434 | 197 return p->func2[i](p->opaque, d, d2); |
612 | 198 } |
199 } | |
200 | |
3770
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
201 *p->error = "unknown function"; |
2434 | 202 return NAN; |
612 | 203 } |
2433 | 204 |
2434 | 205 return d; |
2967 | 206 } |
2436 | 207 |
2434 | 208 static double evalPow(Parser *p){ |
2436 | 209 int sign= (*p->s == '+') - (*p->s == '-'); |
210 p->s += sign&1; | |
211 return (sign|1) * evalPrimary(p); | |
2434 | 212 } |
612 | 213 |
2434 | 214 static double evalFactor(Parser *p){ |
215 double ret= evalPow(p); | |
216 while(p->s[0]=='^'){ | |
612 | 217 p->s++; |
2434 | 218 ret= pow(ret, evalPow(p)); |
612 | 219 } |
2434 | 220 return ret; |
612 | 221 } |
222 | |
2434 | 223 static double evalTerm(Parser *p){ |
224 double ret= evalFactor(p); | |
225 while(p->s[0]=='*' || p->s[0]=='/'){ | |
226 if(*p->s++ == '*') ret*= evalFactor(p); | |
227 else ret/= evalFactor(p); | |
612 | 228 } |
2434 | 229 return ret; |
612 | 230 } |
231 | |
2434 | 232 static double evalExpression(Parser *p){ |
2436 | 233 double ret= 0; |
612 | 234 |
2434 | 235 if(p->stack_index <= 0) //protect against stack overflows |
236 return NAN; | |
237 p->stack_index--; | |
238 | |
2436 | 239 do{ |
240 ret += evalTerm(p); | |
241 }while(*p->s == '+' || *p->s == '-'); | |
612 | 242 |
2434 | 243 p->stack_index++; |
612 | 244 |
2434 | 245 return ret; |
612 | 246 } |
247 | |
3770
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
248 double ff_eval2(char *s, double *const_value, const char **const_name, |
1057 | 249 double (**func1)(void *, double), const char **func1_name, |
612 | 250 double (**func2)(void *, double, double), char **func2_name, |
3770
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
251 void *opaque, char **error){ |
612 | 252 Parser p; |
2967 | 253 |
2434 | 254 p.stack_index=100; |
612 | 255 p.s= s; |
256 p.const_value= const_value; | |
257 p.const_name = const_name; | |
258 p.func1 = func1; | |
259 p.func1_name = func1_name; | |
260 p.func2 = func2; | |
261 p.func2_name = func2_name; | |
262 p.opaque = opaque; | |
3770
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
263 p.error= error; |
2967 | 264 |
2434 | 265 return evalExpression(&p); |
612 | 266 } |
2433 | 267 |
3779
3f7aa9fa5c98
Break compatibility only when first part of version number changes, in this
takis
parents:
3778
diff
changeset
|
268 #if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) |
3770
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
269 attribute_deprecated double ff_eval(char *s, double *const_value, const char **const_name, |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
270 double (**func1)(void *, double), const char **func1_name, |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
271 double (**func2)(void *, double, double), char **func2_name, |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
272 void *opaque){ |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
273 char *error=NULL; |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
274 double ret; |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
275 ret = ff_eval2(s, const_value, const_name, func1, func1_name, func2, func2_name, opaque, &error); |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
276 if (error) |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
277 av_log(NULL, AV_LOG_ERROR, "Error evaluating \"%s\": %s\n", s, error); |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
278 return ret; |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
279 } |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
280 #endif |
ea345e1e440f
Introduce ff_eval2 which is equivalent to ff_eval but does not log anything.
takis
parents:
3756
diff
changeset
|
281 |
2433 | 282 #ifdef TEST |
2967 | 283 #undef printf |
2433 | 284 static double const_values[]={ |
285 M_PI, | |
286 M_E, | |
287 0 | |
288 }; | |
289 static const char *const_names[]={ | |
290 "PI", | |
291 "E", | |
292 0 | |
293 }; | |
294 main(){ | |
2436 | 295 int i; |
2433 | 296 printf("%f == 12.7\n", ff_eval("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_values, const_names, NULL, NULL, NULL, NULL, NULL)); |
3730 | 297 printf("%f == 0.931322575\n", ff_eval("80G/80Gi", const_values, const_names, NULL, NULL, NULL, NULL, NULL)); |
2967 | 298 |
2436 | 299 for(i=0; i<1050; i++){ |
300 START_TIMER | |
301 ff_eval("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_values, const_names, NULL, NULL, NULL, NULL, NULL); | |
302 STOP_TIMER("ff_eval") | |
303 } | |
2433 | 304 } |
305 #endif |