Rev 11126 | Rev 12260 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
10 | reyssat | 1 | /* Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis |
2 | * |
||
3 | * This program is free software; you can redistribute it and/or modify |
||
4 | * it under the terms of the GNU General Public License as published by |
||
5 | * the Free Software Foundation; either version 2 of the License, or |
||
6 | * (at your option) any later version. |
||
7 | * |
||
8 | * This program is distributed in the hope that it will be useful, |
||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
11 | * GNU General Public License for more details. |
||
12 | * |
||
13 | * You should have received a copy of the GNU General Public License |
||
14 | * along with this program; if not, write to the Free Software |
||
15 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
16 | */ |
||
8160 | bpr | 17 | #include "libwims.h" |
10 | reyssat | 18 | |
19 | /* log(-1) does not make sense in real */ |
||
20 | #ifndef NAN |
||
21 | #define NAN log(-1) |
||
22 | #endif |
||
23 | |||
7798 | bpr | 24 | /* Only two decimal points, less than 1 million. |
25 | * No check of buffer length which should be at least 12. |
||
26 | * returns the end of buffer. */ |
||
10 | reyssat | 27 | char *moneyprint(char *p, double s) |
28 | { |
||
29 | char *p1, *p2, buf[16]; |
||
30 | int t, t1, t2; |
||
31 | if(s<0) {*p++='-'; s=-s;} |
||
32 | if(s>999999) s=999999; |
||
33 | t=floor(s*100+0.5); if(t>99999999) t=99999999; if(t<0) t=0; |
||
34 | if(t==0) {*p++='0'; *p=0; return p;} |
||
35 | t1=t/100; t2=t%100; p1=buf+10; |
||
36 | for(*p1--=t1%10+'0',t1/=10;t1>0;*p1--=t1%10+'0',t1/=10); |
||
37 | p2=buf+11; |
||
38 | if(t2) { |
||
7798 | bpr | 39 | *p2++='.'; |
40 | *p2++=t2/10+'0'; t2%=10; |
||
41 | if(t2) *p2++=t2+'0'; |
||
10 | reyssat | 42 | } |
43 | p1++; *p2=0; memmove(p,p1,p2-p1+1); p+=p2-p1; |
||
44 | return p; |
||
45 | } |
||
46 | |||
47 | /* #define RAND_BUF_SIZE 4096 |
||
48 | static char rand_buf[RAND_BUF_SIZE]; |
||
7798 | bpr | 49 | */ |
50 | /* The trouble here is that httpd does not initialize |
||
51 | * the variable RANDOM. |
||
52 | * So I use time (microseconds) to get a quick solution. */ |
||
10 | reyssat | 53 | void init_random(void) |
54 | { |
||
55 | int r; |
||
56 | struct timeval t; |
||
57 | /* initstate(1,rand_buf,RAND_BUF_SIZE); */ |
||
58 | gettimeofday(&t,NULL); |
||
59 | r=t.tv_usec+t.tv_sec*1000; |
||
11126 | georgesk | 60 | if(r<0) r=-r; |
61 | if(r==0) r=1; |
||
10 | reyssat | 62 | srandom(r); |
63 | } |
||
64 | |||
7798 | bpr | 65 | /* gives a double random number between 0 and m */ |
10 | reyssat | 66 | double drand(double m) |
67 | { |
||
68 | double r; |
||
69 | r=((double) random()+(double) random()/(double) RAND_MAX); |
||
70 | return (r/(double) RAND_MAX)*m; |
||
71 | } |
||
72 | |||
7798 | bpr | 73 | /* gives a random integer between 0 and n. |
74 | * n maybe floating, but will be rounded */ |
||
10 | reyssat | 75 | double irand(double n) |
76 | { |
||
77 | int end,r; |
||
78 | if(n==0) return 0; |
||
79 | if(n>0) end=n; else end=-n; |
||
80 | r=(double) random()*end/RAND_MAX; |
||
81 | if(r==n) r--; |
||
7798 | bpr | 82 | if(n>0) return r; else return -r; |
10 | reyssat | 83 | } |
84 | |||
7798 | bpr | 85 | /* sign of d */ |
10 | reyssat | 86 | double sign(double d) |
87 | { |
||
88 | if(d==0) return 0; |
||
89 | if(d<0) return -1; |
||
90 | else return 1; |
||
91 | } |
||
92 | |||
7798 | bpr | 93 | /* rounding to integer: problem with half-way rounding */ |
10 | reyssat | 94 | double myround(double d) |
95 | { |
||
96 | long int t; |
||
97 | if(d<0) t=d-0.5; else t=d+0.5; |
||
98 | return t; |
||
99 | } |
||
100 | |||
7798 | bpr | 101 | /* log of base 2 */ |
10 | reyssat | 102 | double mylog2(double d) |
103 | { |
||
104 | return log(d)/log(2); |
||
105 | } |
||
106 | |||
7798 | bpr | 107 | /* sec */ |
10 | reyssat | 108 | double sec(double d) |
7798 | bpr | 109 | { return 1/cos(d);} |
10 | reyssat | 110 | |
7798 | bpr | 111 | /* csc */ |
10 | reyssat | 112 | double csc(double d) |
7798 | bpr | 113 | { return 1/sin(d);} |
10 | reyssat | 114 | |
7798 | bpr | 115 | /* cotangent function */ |
10 | reyssat | 116 | double cotan(double d) |
117 | { |
||
118 | return 1/tan(d); |
||
119 | } |
||
120 | |||
7798 | bpr | 121 | /* hyperbolic cotangent */ |
10 | reyssat | 122 | double cotanh(double d) |
123 | { |
||
124 | return 1/tanh(d); |
||
125 | } |
||
126 | |||
7798 | bpr | 127 | /* factorial of an integer */ |
10 | reyssat | 128 | double factorial(double d) |
129 | { |
||
130 | int i,n; double t; |
||
131 | n=d; |
||
132 | if(n<0 || n!=d) return NAN; |
||
133 | if(n>1000) return HUGE_VAL; |
||
134 | t=1; for(i=1;i<=n;i++) t=t*i; |
||
135 | return t; |
||
136 | } |
||
137 | |||
7798 | bpr | 138 | /* binomial coefficient */ |
10 | reyssat | 139 | double binomial(double d1,double d2) |
140 | { |
||
141 | return factorial(d1)/(factorial(d2)*factorial(d1-d2)); |
||
142 | } |
||
143 | |||
7798 | bpr | 144 | /* max and min */ |
10 | reyssat | 145 | double max(double d1, double d2) |
146 | { |
||
8171 | bpr | 147 | if(!isfinite(d1) || !isfinite(d2)) return NAN; |
10 | reyssat | 148 | if(d1<d2) return d2; else return d1; |
149 | } |
||
150 | double min(double d1, double d2) |
||
151 | { |
||
8171 | bpr | 152 | if(!isfinite(d1) || !isfinite(d2)) return NAN; |
10 | reyssat | 153 | if(d1<d2) return d1; else return d2; |
154 | } |
||
155 | |||
7798 | bpr | 156 | /* gcd and lcm, not really checking errors. */ |
10 | reyssat | 157 | double gcd(double n1, double n2) |
158 | { |
||
159 | unsigned long long int l1, l2, ll; |
||
8862 | bpr | 160 | n1=fabs(n1); n2=fabs(n2); |
8171 | bpr | 161 | if(!isfinite(n1) || !isfinite(n2) || n1<0 || n2<0 || |
10 | reyssat | 162 | n1>1E18 || n2>1E18) return NAN; |
163 | l1=n1; l2=n2; |
||
164 | if(l1<l2) { |
||
7798 | bpr | 165 | ll=l1;l1=l2;l2=ll; |
10 | reyssat | 166 | } |
167 | if(l1==0) return NAN; |
||
168 | while(l2>0) { |
||
7798 | bpr | 169 | ll=l2;l2=l1%l2;l1=ll; |
10 | reyssat | 170 | } |
171 | return l1; |
||
172 | } |
||
173 | |||
174 | double lcm(double n1, double n2) |
||
175 | { |
||
176 | return n1*n2/gcd(n1,n2); |
||
177 | } |
||
178 | |||
179 | struct { |
||
180 | char *name; |
||
181 | int type; |
||
182 | double val; |
||
183 | double (*f1) (double parm); |
||
184 | double (*f2) (double parm1, double parm2); |
||
185 | } evalname[]={ |
||
186 | {"Argch", 1, 0, acosh, NULL}, |
||
187 | {"Argsh", 1, 0, asinh, NULL}, |
||
188 | {"Argth", 1, 0, atanh, NULL}, |
||
189 | {"E", 0, M_E, NULL, NULL}, |
||
190 | {"EULER", 0, 0.57721566490153286, NULL, NULL}, |
||
191 | {EV_S, 0, 0, NULL, NULL}, |
||
192 | {EV_T, 0, 0, NULL, NULL}, |
||
193 | {EV_X, 0, 0, NULL, NULL}, |
||
194 | {EV_Y, 0, 0, NULL, NULL}, |
||
195 | {"Euler", 0, 0.57721566490153286, NULL, NULL}, |
||
196 | {"Inf", 0, 1, log, NULL}, |
||
197 | {"NaN", 0, 0, log, NULL}, |
||
198 | {"PI", 0, M_PI, NULL, NULL}, |
||
199 | {"Pi", 0, M_PI, NULL, NULL}, |
||
200 | {"abs", 1, 0, fabs, NULL}, |
||
201 | {"acos", 1, 0, acos, NULL}, |
||
202 | {"acosh", 1, 0, acosh, NULL}, |
||
203 | {"arccos",1, 0, acos, NULL}, |
||
204 | {"arcsin",1, 0, asin, NULL}, |
||
205 | {"arctan",1, 0, atan, NULL}, |
||
206 | {"arctg", 1, 0, atan, NULL}, |
||
207 | {"argch", 1, 0, acosh, NULL}, |
||
208 | {"argsh", 1, 0, asinh, NULL}, |
||
209 | {"argth", 1, 0, atanh, NULL}, |
||
210 | {"asin", 1, 0, asin, NULL}, |
||
211 | {"asinh", 1, 0, asinh, NULL}, |
||
212 | {"atan", 1, 0, atan, NULL}, |
||
213 | {"atanh", 1, 0, atanh, NULL}, |
||
214 | {"binomial",2, 0, NULL, binomial}, |
||
215 | {"ceil", 1, 0, ceil, NULL}, /* round-up integer */ |
||
216 | {"ch", 1, 0, cosh, NULL}, |
||
217 | {"cos", 1, 0, cos, NULL}, |
||
218 | {"cosh", 1, 0, cosh, NULL}, |
||
219 | {"cot", 1, 0, cotan, NULL}, |
||
220 | {"cotan", 1, 0, cotan, NULL}, |
||
221 | {"cotanh",1, 0, cotanh, NULL}, |
||
222 | {"coth", 1, 0, cotanh, NULL}, |
||
223 | {"csc", 1, 0, csc, NULL}, |
||
224 | {"ctg", 1, 0, cotan, NULL}, |
||
225 | {"cth", 1, 0, cotanh, NULL}, |
||
226 | {"drand", 1, 0, drand, NULL}, |
||
227 | {"e", 0, M_E, NULL, NULL}, |
||
228 | {"erf", 1, 0, erf, NULL}, |
||
229 | {"erfc", 1, 0, erfc, NULL}, |
||
230 | {"euler", 0, 0.57721566490153286, NULL, NULL}, |
||
231 | {"exp", 1, 0, exp, NULL}, |
||
232 | {"factorial",1, 0, factorial, NULL}, |
||
233 | {"floor", 1, 0, floor, NULL}, |
||
234 | {"gcd", 2, 0, NULL, gcd}, |
||
235 | {"irand", 1, 0, irand, NULL}, |
||
236 | /* {"j0", 1, 0, j0, NULL}, */ /* Bessel functions */ |
||
237 | /* {"j1", 1, 0, j1, NULL}, */ |
||
238 | {"lcm", 2, 0, NULL, lcm}, |
||
239 | {"lg", 1, 0, log10, NULL}, |
||
240 | {"lgamma",1, 0, lgamma, NULL}, /* log of Gamma function */ |
||
241 | {"ln", 1, 0, log, NULL}, |
||
242 | {"log", 1, 0, log, NULL}, |
||
243 | {"log10", 1, 0, log10, NULL}, |
||
244 | {"log2", 1, 0, mylog2, NULL}, |
||
245 | {"max", 2, 0, NULL, max}, |
||
246 | {"min", 2, 0, NULL, min}, |
||
247 | {"pi", 0, M_PI, NULL, NULL}, |
||
248 | {"pow", 2, 0, NULL, pow}, |
||
249 | {"rand", 1, 0, drand, NULL}, |
||
250 | {"randdouble",1, 0, drand, NULL}, |
||
251 | {"randfloat",1, 0, drand, NULL}, |
||
252 | {"randint",1, 0, irand, NULL}, |
||
253 | {"random",1, 0, drand, NULL}, |
||
254 | {"randreal",1, 0, drand, NULL}, |
||
255 | {"rint", 1, 0, myround, NULL}, /* closest integer */ |
||
256 | {"round", 1, 0, myround, NULL}, /* closest integer */ |
||
257 | {"sec", 1, 0, sec, NULL}, |
||
258 | {"sgn", 1, 0, sign, NULL}, /* sign of the value */ |
||
259 | {"sh", 1, 0, sinh, NULL}, |
||
260 | {"sign", 1, 0, sign, NULL}, /* sign of the value */ |
||
261 | {"sin", 1, 0, sin, NULL}, |
||
262 | {"sinh", 1, 0, sinh, NULL}, |
||
263 | {"sqrt", 1, 0, sqrt, NULL}, |
||
264 | {"tan", 1, 0, tan, NULL}, |
||
265 | {"tanh", 1, 0, tanh, NULL}, |
||
266 | {"tg", 1, 0, tan, NULL}, |
||
267 | {"th", 1, 0, tanh, NULL}, |
||
268 | /* {"y0", 1, 0, y0, NULL}, */ |
||
269 | /* {"y1", 1, 0, y1, NULL}, */ |
||
270 | }; |
||
271 | #define evalname_no (sizeof(evalname)/sizeof(evalname[0])) |
||
272 | |||
273 | int get_evalcnt(void) {return evalname_no;} |
||
274 | char *get_evalname(int i) {return evalname[i].name;} |
||
275 | int get_evaltype(int i) {return evalname[i].type;} |
||
276 | int evaltab_verify(void) {return verify_order(evalname,evalname_no,sizeof(evalname[0]));} |
||
277 | int search_evaltab(char *p) { |
||
278 | return search_list(evalname,evalname_no,sizeof(evalname[0]),p); |
||
279 | } |
||
280 | |||
281 | static char *evalue_pt; |
||
282 | int evalue_error; |
||
283 | |||
284 | int get_evalue_error(void) { return evalue_error; } |
||
285 | void set_evalue_error(int e) {evalue_error=e; return;} |
||
286 | |||
287 | /* prepare pointer for evaluation */ |
||
288 | void set_evalue_pointer(char *p) |
||
289 | { |
||
290 | evalue_pt=p; |
||
291 | } |
||
292 | |||
7798 | bpr | 293 | /* get position of name in nametable */ |
10 | reyssat | 294 | int eval_getpos(char *name) |
295 | { |
||
296 | return search_list(evalname,evalname_no,sizeof(evalname[0]),name); |
||
297 | } |
||
298 | |||
7798 | bpr | 299 | /* set value to name */ |
10 | reyssat | 300 | void eval_setval(int pos, double v) |
301 | { |
||
302 | if(pos>=0 && pos<evalname_no) evalname[pos].val=v; |
||
303 | } |
||
304 | |||
7798 | bpr | 305 | /* get string pointer (after evaluation) */ |
10 | reyssat | 306 | char *get_evalue_pointer(void) |
307 | { |
||
308 | return evalue_pt; |
||
309 | } |
||
310 | |||
311 | double _evalue(int ord) |
||
312 | { |
||
313 | double d,dd; |
||
314 | int i,k; |
||
315 | char buf[32]; |
||
316 | |||
7798 | bpr | 317 | |
10 | reyssat | 318 | if(evalue_error) return NAN; |
319 | d=0; |
||
320 | while(*evalue_pt=='+') evalue_pt++; |
||
321 | if(*evalue_pt==0) return 0; /* empty string */ |
||
322 | switch(*evalue_pt) { |
||
7798 | bpr | 323 | case '(': |
324 | evalue_pt++; d=_evalue(')');goto vld; |
||
325 | case '|': |
||
326 | if(ord=='|') { |
||
327 | evalue_pt++; return 0; |
||
328 | } |
||
329 | evalue_pt++; d=fabs(_evalue('|'));goto vld; |
||
330 | case '-': |
||
331 | evalue_pt++; d=-_evalue(6);goto vld; |
||
10 | reyssat | 332 | } |
7798 | bpr | 333 | if((128&*evalue_pt)!=0) {/* special character */ |
334 | k=(*evalue_pt)&255; evalue_pt++; |
||
335 | if(k>=130 && k<140) { |
||
336 | i=(k-130)*200; k=(*evalue_pt)&255; evalue_pt++; |
||
337 | if(k<33 || k>=233) goto badeval; |
||
338 | i+=k-33; if(i<0 || i>=evalname_no) goto badeval; |
||
339 | goto ename; |
||
340 | } |
||
341 | if(k>=140 && k<150) { |
||
342 | i=(k-140)*200; k=(*evalue_pt)&255; evalue_pt++; |
||
343 | if(k<33 || k>=233) goto badeval; |
||
344 | if(ev_var==NULL || ev_varcnt==NULL) goto badeval; |
||
345 | i+=k-33; if(i<0 || i>=*ev_varcnt) goto badeval; |
||
346 | goto vname; |
||
347 | } |
||
348 | evalue_pt++; goto badeval; |
||
10 | reyssat | 349 | } |
350 | if(*evalue_pt=='.' || myisdigit(*evalue_pt)) |
||
7798 | bpr | 351 | {d=strtod(evalue_pt,&evalue_pt);goto binary;} |
10 | reyssat | 352 | for(i=0;myisalnum(*(evalue_pt+i)) && i<16; i++) |
353 | buf[i]=*(evalue_pt+i); |
||
354 | buf[i]=0; evalue_pt+=i; |
||
355 | if(i==0) goto badeval; |
||
356 | if(ev_varcnt!=NULL && ev_var!=NULL && *ev_varcnt>0) |
||
357 | for(i=0;i<*ev_varcnt;i++) { |
||
7798 | bpr | 358 | if(strcmp(buf,ev_var[i].name)==0) { |
359 | vname: d=ev_var[i].value; goto vld; |
||
360 | } |
||
10 | reyssat | 361 | } |
362 | i=search_list(evalname,evalname_no,sizeof(evalname[0]),buf); |
||
7798 | bpr | 363 | ename: if(i>=0) switch(evalname[i].type) { /* evaluation of expressions */ |
364 | case 0: { |
||
365 | d=evalname[i].val; |
||
366 | if(evalname[i].f1!=NULL) { |
||
11126 | georgesk | 367 | if(d==0) d=NAN; |
11132 | bpr | 368 | if(d==1) d=HUGE_VAL; |
7798 | bpr | 369 | } |
370 | break; |
||
371 | } |
||
372 | case 1: { |
||
373 | if(*evalue_pt!='(') return NAN; |
||
374 | evalue_pt++; |
||
375 | d=evalname[i].f1(_evalue(')')); break;/* evaluation of function */ |
||
376 | } |
||
377 | case 2: { |
||
378 | double parm1,parm2; |
||
379 | if(*evalue_pt!='(') return NAN; |
||
380 | evalue_pt++; |
||
381 | parm1=_evalue(',');parm2=_evalue(')'); |
||
382 | d=evalname[i].f2(parm1,parm2); break; |
||
383 | } |
||
384 | default: { /* This is impossible. */ |
||
385 | return NAN; |
||
386 | } |
||
10 | reyssat | 387 | } |
388 | else { |
||
7798 | bpr | 389 | badeval: evalue_error=-1; return NAN; |
10 | reyssat | 390 | } |
391 | vld: |
||
392 | if(evalue_error) return NAN; |
||
7798 | bpr | 393 | binary: /*evaluation des expressions */ |
10 | reyssat | 394 | if(*evalue_pt=='!') { |
7798 | bpr | 395 | evalue_pt++; d=factorial(d); |
10 | reyssat | 396 | } |
7798 | bpr | 397 | if(*evalue_pt==ord) {evalue_pt++;goto ok;}/* */ |
398 | if(*evalue_pt==0 || /* chaine de caractere finie*/ |
||
10 | reyssat | 399 | (ord<10 && (*evalue_pt==',' || *evalue_pt==';' || *evalue_pt==')' |
7798 | bpr | 400 | || *evalue_pt=='|'))) |
10 | reyssat | 401 | goto ok; |
402 | switch(*evalue_pt) { |
||
7798 | bpr | 403 | case '+': |
404 | if(ord<=8) break; |
||
405 | evalue_pt++; d+=_evalue(8);goto vld; |
||
406 | case '-': |
||
407 | if(ord<=8) break; |
||
408 | evalue_pt++; d-=_evalue(8);goto vld; |
||
409 | case '*': |
||
410 | if(ord<=6) break; |
||
411 | evalue_pt++; d*=_evalue(6);goto vld; |
||
412 | case '/': |
||
413 | if(ord<=6) break; |
||
414 | evalue_pt++; dd=_evalue(6); |
||
415 | if(dd==0) {evalue_error=10;return NAN;} |
||
416 | d/=dd;goto vld; |
||
417 | case '%': { |
||
418 | int di, ddi; |
||
419 | if(ord<=6) break; |
||
420 | evalue_pt++; dd=_evalue(6); |
||
421 | if(dd==0) {evalue_error=10;return NAN;} |
||
422 | di=d; ddi=dd; d=di%ddi;goto vld; |
||
423 | } |
||
424 | case '^': { |
||
425 | if(ord<5) break; |
||
426 | evalue_pt++; d=pow(d,_evalue(5));goto vld; |
||
427 | } |
||
428 | default : { |
||
429 | return NAN; |
||
430 | } |
||
10 | reyssat | 431 | } |
432 | ok: return d; |
||
433 | } |
||
434 | |||
7798 | bpr | 435 | /* substitute variable names by their environment strings |
436 | * The buffer pointed to by p must have enough space |
||
437 | * (defined by MAX_LINELEN). */ |
||
10 | reyssat | 438 | char *_substit(char *p) |
439 | { |
||
440 | return p; |
||
441 | } |
||
442 | |||
443 | char *(*substitute) (char *p)=_substit; |
||
444 | |||
7847 | bpr | 445 | double checked_eval( char* p) |
446 | { |
||
447 | set_evalue_error(0); |
||
448 | set_evalue_pointer(p); |
||
449 | return _evalue(10); |
||
450 | } |
||
451 | |||
7798 | bpr | 452 | /* evalue a string to double */ |
10 | reyssat | 453 | double strevalue(char *p) |
454 | { |
||
455 | char buf[MAX_LINELEN+1]; |
||
7798 | bpr | 456 | |
10 | reyssat | 457 | if(p==NULL) return 0; |
458 | mystrncpy(buf,p,sizeof(buf)); |
||
459 | substitute(buf); nospace(buf); |
||
7847 | bpr | 460 | if(check_parentheses(buf,0)) {return NAN;} |
461 | return checked_eval(buf); |
||
10 | reyssat | 462 | } |
463 | |||
7847 | bpr | 464 | |
7798 | bpr | 465 | /* compile an expression for faster evaluation |
466 | * returns -1 if cannot be compiled. |
||
467 | * else returns the number of compilations. |
||
468 | */ |
||
10 | reyssat | 469 | int evalue_compile(char *p) |
470 | { |
||
471 | char *p1, *p2, *pe, name[256], buf[8]; |
||
472 | int i,k; |
||
7798 | bpr | 473 | |
10 | reyssat | 474 | k=0; |
475 | for(p1=p; *p1; p1++) if((128&*p1)!=0) return -1; |
||
476 | nospace(p); |
||
477 | for(p1=find_mathvar_start(p); *p1; p1=find_mathvar_start(pe)) { |
||
7798 | bpr | 478 | pe=find_mathvar_end(p1); |
479 | if(!myisalpha(*p1)) continue; |
||
480 | p2=pe; if(p2-p1>16) continue; |
||
481 | memmove(name,p1,p2-p1); name[p2-p1]=0; |
||
482 | /* replace the variables by a number |
||
483 | * at most 2000 variables on two characters : |
||
484 | * variable: 140 <= integer <150, number between 33 and 233 |
||
485 | * function: 130 <= integer < 140, number between 33 and 233 |
||
486 | */ |
||
487 | if(ev_varcnt!=NULL && ev_var!=NULL && *ev_varcnt>0) { |
||
488 | for(i=0;i<*ev_varcnt && strcmp(name,ev_var[i].name)!=0;i++); |
||
489 | if(i<*ev_varcnt && i<2000) { |
||
490 | buf[0]=i/200+140; buf[1]=i%200+33; buf[2]=0; |
||
491 | string_modify(p,p1,p2,"%s",buf); |
||
492 | pe=p1+2; k++; continue; |
||
493 | } |
||
10 | reyssat | 494 | } |
7798 | bpr | 495 | i=search_list(evalname,evalname_no,sizeof(evalname[0]),name); |
496 | if(i>=0 && i<2000) { |
||
497 | buf[0]=i/200+130; buf[1]=i%200+33; buf[2]=0; |
||
498 | string_modify(p,p1,p2,"%s",buf); |
||
499 | pe=p1+2; k++; continue; |
||
500 | } |
||
501 | } |
||
502 | return k; |
||
10 | reyssat | 503 | } |
7847 | bpr | 504 | |
505 | /* add evaluator (Dominique Bernardi june 2014) |
||
506 | In addition to the general evaluation functions, there is a simple mean |
||
507 | to evaluate standard functions with at most four variables |
||
508 | named "x", "y", "s" and "t". The simplest one is |
||
509 | |||
510 | double eval_simple (char *p, double x, double y, double s, double t); |
||
511 | |||
512 | which does exactly that. In case of multiple evaluation of the same function |
||
513 | for different values of the variable(s), it is possible to speed up a bit |
||
514 | the evaluation by "precompiling" the string to be evaluated. |
||
515 | This precompilation is done by |
||
516 | |||
517 | eval_struct* eval_create (char *p); |
||
518 | |||
519 | which returns a newly allocated pointer to something. One can use |
||
520 | this pointer in functions like |
||
521 | |||
522 | eval_x, eval_t, eval_x_y |
||
523 | |||
524 | When the struct is no longer useful, one can reclaim the memory it used with |
||
525 | |||
526 | void eval_destroy (eval_struct *q); |
||
527 | |||
528 | */ |
||
529 | |||
530 | void _aux (char *q, char *varn, char *subst, int *v) |
||
531 | { |
||
532 | char *pp; |
||
533 | for(pp=varchr(q,varn); pp; pp=varchr(pp,varn)) |
||
534 | { |
||
535 | string_modify(q,pp,pp+strlen(varn),"%s",subst); |
||
536 | pp+=strlen(subst); |
||
537 | } |
||
538 | *v = eval_getpos(subst); |
||
539 | } |
||
540 | |||
541 | eval_struct * eval_create (char *in_p) |
||
542 | { |
||
543 | eval_struct *p = malloc (sizeof(eval_struct)); |
||
544 | char *q = malloc(MAX_LINELEN+1); |
||
545 | strncpy (q, in_p, MAX_LINELEN); |
||
546 | _aux (q, "x", EV_X, &p->x); |
||
547 | _aux (q, "y", EV_Y, &p->y); |
||
548 | _aux (q, "s", EV_S, &p->s); |
||
549 | _aux (q, "t", EV_T, &p->t); |
||
550 | evalue_compile(q); |
||
551 | p->texte = q; |
||
552 | return p; |
||
553 | } |
||
554 | |||
555 | double eval_multiple (eval_struct *p, double x, double y, double s, double t) |
||
556 | { |
||
557 | eval_setval(p->x,x); |
||
558 | eval_setval(p->y,y); |
||
559 | eval_setval(p->s,s); |
||
560 | eval_setval(p->t,t); |
||
561 | return checked_eval(p->texte); |
||
562 | } |
||
563 | /* non yet useful |
||
564 | double eval_simple (char *p, double x, double y, double s, double t) |
||
565 | { |
||
566 | eval_struct *q = eval_create (p); |
||
567 | double r = eval (q, x, y, s, t); |
||
568 | eval_destroy(q); |
||
569 | return r; |
||
570 | } |
||
571 | |||
572 | */ |
||
573 | |||
574 | double eval_x (eval_struct *p, double x) |
||
575 | { |
||
576 | eval_setval(p->x,x); |
||
577 | return checked_eval(p->texte); |
||
578 | } |
||
579 | |||
580 | double eval_t (eval_struct *p, double t) |
||
581 | { |
||
582 | eval_setval(p->t,t); |
||
583 | return checked_eval(p->texte); |
||
584 | } |
||
585 | |||
586 | double eval_x_y (eval_struct *p, double x, double y) |
||
587 | { |
||
588 | eval_setval(p->x,x); |
||
589 | eval_setval(p->y,y); |
||
590 | return checked_eval(p->texte); |
||
591 | } |
||
592 | |||
593 | void eval_destroy(eval_struct *q) {free (q->texte); free (q);} |