Rev 10 | Rev 7847 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 10 | Rev 7798 | ||
---|---|---|---|
Line 18... | Line 18... | ||
18 | /* log(-1) does not make sense in real */ |
18 | /* log(-1) does not make sense in real */ |
19 | #ifndef NAN |
19 | #ifndef NAN |
20 | #define NAN log(-1) |
20 | #define NAN log(-1) |
21 | #endif |
21 | #endif |
22 | 22 | ||
23 |
|
23 | /* Only two decimal points, less than 1 million. |
24 |
|
24 | * No check of buffer length which should be at least 12. |
25 |
|
25 | * returns the end of buffer. */ |
26 | char *moneyprint(char *p, double s) |
26 | char *moneyprint(char *p, double s) |
27 | { |
27 | { |
28 | char *p1, *p2, buf[16]; |
28 | char *p1, *p2, buf[16]; |
29 | int t, t1, t2; |
29 | int t, t1, t2; |
30 | if(s<0) {*p++='-'; s=-s;} |
30 | if(s<0) {*p++='-'; s=-s;} |
Line 33... | Line 33... | ||
33 | if(t==0) {*p++='0'; *p=0; return p;} |
33 | if(t==0) {*p++='0'; *p=0; return p;} |
34 | t1=t/100; t2=t%100; p1=buf+10; |
34 | t1=t/100; t2=t%100; p1=buf+10; |
35 | for(*p1--=t1%10+'0',t1/=10;t1>0;*p1--=t1%10+'0',t1/=10); |
35 | for(*p1--=t1%10+'0',t1/=10;t1>0;*p1--=t1%10+'0',t1/=10); |
36 | p2=buf+11; |
36 | p2=buf+11; |
37 | if(t2) { |
37 | if(t2) { |
38 |
|
38 | *p2++='.'; |
39 |
|
39 | *p2++=t2/10+'0'; t2%=10; |
40 |
|
40 | if(t2) *p2++=t2+'0'; |
41 | } |
41 | } |
42 | p1++; *p2=0; memmove(p,p1,p2-p1+1); p+=p2-p1; |
42 | p1++; *p2=0; memmove(p,p1,p2-p1+1); p+=p2-p1; |
43 | return p; |
43 | return p; |
44 | } |
44 | } |
45 | 45 | ||
46 | /* #define RAND_BUF_SIZE 4096 |
46 | /* #define RAND_BUF_SIZE 4096 |
47 | static char rand_buf[RAND_BUF_SIZE]; |
47 | static char rand_buf[RAND_BUF_SIZE]; |
- | 48 | */ |
|
48 |
|
49 | /* The trouble here is that httpd does not initialize |
49 |
|
50 | * the variable RANDOM. |
50 |
|
51 | * So I use time (microseconds) to get a quick solution. */ |
51 | void init_random(void) |
52 | void init_random(void) |
52 | { |
53 | { |
53 | int r; |
54 | int r; |
54 | struct timeval t; |
55 | struct timeval t; |
55 | /* initstate(1,rand_buf,RAND_BUF_SIZE); */ |
56 | /* initstate(1,rand_buf,RAND_BUF_SIZE); */ |
Line 57... | Line 58... | ||
57 | r=t.tv_usec+t.tv_sec*1000; |
58 | r=t.tv_usec+t.tv_sec*1000; |
58 | if(r<0) r=-r; if(r==0) r=1; |
59 | if(r<0) r=-r; if(r==0) r=1; |
59 | srandom(r); |
60 | srandom(r); |
60 | } |
61 | } |
61 | 62 | ||
62 |
|
63 | /* gives a double random number between 0 and m */ |
63 | double drand(double m) |
64 | double drand(double m) |
64 | { |
65 | { |
65 | double r; |
66 | double r; |
66 | r=((double) random()+(double) random()/(double) RAND_MAX); |
67 | r=((double) random()+(double) random()/(double) RAND_MAX); |
67 | return (r/(double) RAND_MAX)*m; |
68 | return (r/(double) RAND_MAX)*m; |
68 | } |
69 | } |
69 | 70 | ||
70 |
|
71 | /* gives a random integer between 0 and n. |
71 |
|
72 | * n maybe floating, but will be rounded */ |
72 | double irand(double n) |
73 | double irand(double n) |
73 | { |
74 | { |
74 | int end,r; |
75 | int end,r; |
75 | if(n==0) return 0; |
76 | if(n==0) return 0; |
76 | if(n>0) end=n; else end=-n; |
77 | if(n>0) end=n; else end=-n; |
77 | r=(double) random()*end/RAND_MAX; |
78 | r=(double) random()*end/RAND_MAX; |
78 | if(r==n) r--; |
79 | if(r==n) r--; |
79 | if(n>0) return r; else return -r; |
80 | if(n>0) return r; else return -r; |
80 | } |
81 | } |
81 | 82 | ||
82 |
|
83 | /* sign of d */ |
83 | double sign(double d) |
84 | double sign(double d) |
84 | { |
85 | { |
85 | if(d==0) return 0; |
86 | if(d==0) return 0; |
86 | if(d<0) return -1; |
87 | if(d<0) return -1; |
87 | else return 1; |
88 | else return 1; |
88 | } |
89 | } |
89 | 90 | ||
90 |
|
91 | /* rounding to integer: problem with half-way rounding */ |
91 | double myround(double d) |
92 | double myround(double d) |
92 | { |
93 | { |
93 | long int t; |
94 | long int t; |
94 | if(d<0) t=d-0.5; else t=d+0.5; |
95 | if(d<0) t=d-0.5; else t=d+0.5; |
95 | return t; |
96 | return t; |
96 | } |
97 | } |
97 | 98 | ||
98 |
|
99 | /* log of base 2 */ |
99 | double mylog2(double d) |
100 | double mylog2(double d) |
100 | { |
101 | { |
101 | return log(d)/log(2); |
102 | return log(d)/log(2); |
102 | } |
103 | } |
103 | 104 | ||
104 |
|
105 | /* sec */ |
105 | double sec(double d) |
106 | double sec(double d) |
106 | { |
107 | { return 1/cos(d);} |
107 | 108 | ||
108 |
|
109 | /* csc */ |
109 | double csc(double d) |
110 | double csc(double d) |
110 | { |
111 | { return 1/sin(d);} |
111 | 112 | ||
112 |
|
113 | /* cotangent function */ |
113 | double cotan(double d) |
114 | double cotan(double d) |
114 | { |
115 | { |
115 | return 1/tan(d); |
116 | return 1/tan(d); |
116 | } |
117 | } |
117 | 118 | ||
118 |
|
119 | /* hyperbolic cotangent */ |
119 | double cotanh(double d) |
120 | double cotanh(double d) |
120 | { |
121 | { |
121 | return 1/tanh(d); |
122 | return 1/tanh(d); |
122 | } |
123 | } |
123 | 124 | ||
124 |
|
125 | /* factorial of an integer */ |
125 | double factorial(double d) |
126 | double factorial(double d) |
126 | { |
127 | { |
127 | int i,n; double t; |
128 | int i,n; double t; |
128 | n=d; |
129 | n=d; |
129 | if(n<0 || n!=d) return NAN; |
130 | if(n<0 || n!=d) return NAN; |
130 | if(n>1000) return HUGE_VAL; |
131 | if(n>1000) return HUGE_VAL; |
131 | t=1; for(i=1;i<=n;i++) t=t*i; |
132 | t=1; for(i=1;i<=n;i++) t=t*i; |
132 | return t; |
133 | return t; |
133 | } |
134 | } |
134 | 135 | ||
135 |
|
136 | /* binomial coefficient */ |
136 | double binomial(double d1,double d2) |
137 | double binomial(double d1,double d2) |
137 | { |
138 | { |
138 | return factorial(d1)/(factorial(d2)*factorial(d1-d2)); |
139 | return factorial(d1)/(factorial(d2)*factorial(d1-d2)); |
139 | } |
140 | } |
140 | 141 | ||
141 |
|
142 | /* max and min */ |
142 | double max(double d1, double d2) |
143 | double max(double d1, double d2) |
143 | { |
144 | { |
144 | if(!finite(d1) || !finite(d2)) return NAN; |
145 | if(!finite(d1) || !finite(d2)) return NAN; |
145 | if(d1<d2) return d2; else return d1; |
146 | if(d1<d2) return d2; else return d1; |
146 | } |
147 | } |
Line 148... | Line 149... | ||
148 | { |
149 | { |
149 | if(!finite(d1) || !finite(d2)) return NAN; |
150 | if(!finite(d1) || !finite(d2)) return NAN; |
150 | if(d1<d2) return d1; else return d2; |
151 | if(d1<d2) return d1; else return d2; |
151 | } |
152 | } |
152 | 153 | ||
153 |
|
154 | /* gcd and lcm, not really checking errors. */ |
154 | double gcd(double n1, double n2) |
155 | double gcd(double n1, double n2) |
155 | { |
156 | { |
156 | unsigned long long int l1, l2, ll; |
157 | unsigned long long int l1, l2, ll; |
157 | n1=abs(n1); n2=abs(n2); |
158 | n1=abs(n1); n2=abs(n2); |
158 | if(!finite(n1) || !finite(n2) || n1<0 || n2<0 || |
159 | if(!finite(n1) || !finite(n2) || n1<0 || n2<0 || |
159 | n1>1E18 || n2>1E18) return NAN; |
160 | n1>1E18 || n2>1E18) return NAN; |
160 | l1=n1; l2=n2; |
161 | l1=n1; l2=n2; |
161 | if(l1<l2) { |
162 | if(l1<l2) { |
162 |
|
163 | ll=l1;l1=l2;l2=ll; |
163 | } |
164 | } |
164 | if(l1==0) return NAN; |
165 | if(l1==0) return NAN; |
165 | while(l2>0) { |
166 | while(l2>0) { |
166 |
|
167 | ll=l2;l2=l1%l2;l1=ll; |
167 | } |
168 | } |
168 | return l1; |
169 | return l1; |
169 | } |
170 | } |
170 | 171 | ||
171 | double lcm(double n1, double n2) |
172 | double lcm(double n1, double n2) |
Line 285... | Line 286... | ||
285 | void set_evalue_pointer(char *p) |
286 | void set_evalue_pointer(char *p) |
286 | { |
287 | { |
287 | evalue_pt=p; |
288 | evalue_pt=p; |
288 | } |
289 | } |
289 | 290 | ||
290 |
|
291 | /* get position of name in nametable */ |
291 | int eval_getpos(char *name) |
292 | int eval_getpos(char *name) |
292 | { |
293 | { |
293 | return search_list(evalname,evalname_no,sizeof(evalname[0]),name); |
294 | return search_list(evalname,evalname_no,sizeof(evalname[0]),name); |
294 | } |
295 | } |
295 | 296 | ||
296 |
|
297 | /* set value to name */ |
297 | void eval_setval(int pos, double v) |
298 | void eval_setval(int pos, double v) |
298 | { |
299 | { |
299 | if(pos>=0 && pos<evalname_no) evalname[pos].val=v; |
300 | if(pos>=0 && pos<evalname_no) evalname[pos].val=v; |
300 | } |
301 | } |
301 | 302 | ||
302 |
|
303 | /* get string pointer (after evaluation) */ |
303 | char *get_evalue_pointer(void) |
304 | char *get_evalue_pointer(void) |
304 | { |
305 | { |
305 | return evalue_pt; |
306 | return evalue_pt; |
306 | } |
307 | } |
307 | 308 | ||
Line 309... | Line 310... | ||
309 | { |
310 | { |
310 | double d,dd; |
311 | double d,dd; |
311 | int i,k; |
312 | int i,k; |
312 | char buf[32]; |
313 | char buf[32]; |
313 | 314 | ||
314 | 315 | ||
315 | if(evalue_error) return NAN; |
316 | if(evalue_error) return NAN; |
316 | d=0; |
317 | d=0; |
317 | while(*evalue_pt=='+') evalue_pt++; |
318 | while(*evalue_pt=='+') evalue_pt++; |
318 | if(*evalue_pt==0) return 0; /* empty string */ |
319 | if(*evalue_pt==0) return 0; /* empty string */ |
319 | switch(*evalue_pt) { |
320 | switch(*evalue_pt) { |
320 |
|
321 | case '(': |
321 |
|
322 | evalue_pt++; d=_evalue(')');goto vld; |
322 |
|
323 | case '|': |
323 |
|
324 | if(ord=='|') { |
324 |
|
325 | evalue_pt++; return 0; |
325 |
|
326 | } |
326 |
|
327 | evalue_pt++; d=fabs(_evalue('|'));goto vld; |
327 |
|
328 | case '-': |
328 |
|
329 | evalue_pt++; d=-_evalue(6);goto vld; |
329 | } |
330 | } |
330 | if((128&*evalue_pt)!=0) { |
331 | if((128&*evalue_pt)!=0) {/* special character */ |
331 |
|
332 | k=(*evalue_pt)&255; evalue_pt++; |
332 |
|
333 | if(k>=130 && k<140) { |
333 |
|
334 | i=(k-130)*200; k=(*evalue_pt)&255; evalue_pt++; |
334 |
|
335 | if(k<33 || k>=233) goto badeval; |
335 |
|
336 | i+=k-33; if(i<0 || i>=evalname_no) goto badeval; |
336 |
|
337 | goto ename; |
337 |
|
338 | } |
338 |
|
339 | if(k>=140 && k<150) { |
339 |
|
340 | i=(k-140)*200; k=(*evalue_pt)&255; evalue_pt++; |
340 |
|
341 | if(k<33 || k>=233) goto badeval; |
341 |
|
342 | if(ev_var==NULL || ev_varcnt==NULL) goto badeval; |
342 |
|
343 | i+=k-33; if(i<0 || i>=*ev_varcnt) goto badeval; |
343 |
|
344 | goto vname; |
344 |
|
345 | } |
345 |
|
346 | evalue_pt++; goto badeval; |
346 | } |
347 | } |
347 | if(*evalue_pt=='.' || myisdigit(*evalue_pt)) |
348 | if(*evalue_pt=='.' || myisdigit(*evalue_pt)) |
348 |
|
349 | {d=strtod(evalue_pt,&evalue_pt);goto binary;} |
349 | for(i=0;myisalnum(*(evalue_pt+i)) && i<16; i++) |
350 | for(i=0;myisalnum(*(evalue_pt+i)) && i<16; i++) |
350 | buf[i]=*(evalue_pt+i); |
351 | buf[i]=*(evalue_pt+i); |
351 | buf[i]=0; evalue_pt+=i; |
352 | buf[i]=0; evalue_pt+=i; |
352 | if(i==0) goto badeval; |
353 | if(i==0) goto badeval; |
353 | if(ev_varcnt!=NULL && ev_var!=NULL && *ev_varcnt>0) |
354 | if(ev_varcnt!=NULL && ev_var!=NULL && *ev_varcnt>0) |
354 | for(i=0;i<*ev_varcnt;i++) { |
355 | for(i=0;i<*ev_varcnt;i++) { |
355 |
|
356 | if(strcmp(buf,ev_var[i].name)==0) { |
356 |
|
357 | vname: d=ev_var[i].value; goto vld; |
357 |
|
358 | } |
358 | } |
359 | } |
359 | i=search_list(evalname,evalname_no,sizeof(evalname[0]),buf); |
360 | i=search_list(evalname,evalname_no,sizeof(evalname[0]),buf); |
360 | ename: if(i>=0) switch(evalname[i].type) { |
361 | ename: if(i>=0) switch(evalname[i].type) { /* evaluation of expressions */ |
361 |
|
362 | case 0: { |
362 |
|
363 | d=evalname[i].val; |
363 |
|
364 | if(evalname[i].f1!=NULL) { |
364 |
|
365 | if(d==0) d=NAN; if(d==1) d=HUGE_VAL; |
365 |
|
366 | } |
366 |
|
367 | break; |
367 |
|
368 | } |
368 |
|
369 | case 1: { |
369 |
|
370 | if(*evalue_pt!='(') return NAN; |
370 |
|
371 | evalue_pt++; |
371 |
|
372 | d=evalname[i].f1(_evalue(')')); break;/* evaluation of function */ |
372 |
|
373 | } |
373 |
|
374 | case 2: { |
374 |
|
375 | double parm1,parm2; |
375 |
|
376 | if(*evalue_pt!='(') return NAN; |
376 |
|
377 | evalue_pt++; |
377 |
|
378 | parm1=_evalue(',');parm2=_evalue(')'); |
378 |
|
379 | d=evalname[i].f2(parm1,parm2); break; |
379 |
|
380 | } |
380 |
|
381 | default: { /* This is impossible. */ |
381 |
|
382 | return NAN; |
382 |
|
383 | } |
383 | } |
384 | } |
384 | else { |
385 | else { |
385 |
|
386 | badeval: evalue_error=-1; return NAN; |
386 | } |
387 | } |
387 | vld: |
388 | vld: |
388 | if(evalue_error) return NAN; |
389 | if(evalue_error) return NAN; |
389 | binary: |
390 | binary: /*evaluation des expressions */ |
390 | if(*evalue_pt=='!') { |
391 | if(*evalue_pt=='!') { |
391 |
|
392 | evalue_pt++; d=factorial(d); |
392 | } |
393 | } |
393 | if(*evalue_pt==ord) {evalue_pt++;goto ok;} |
394 | if(*evalue_pt==ord) {evalue_pt++;goto ok;}/* */ |
394 | if(*evalue_pt==0 || |
395 | if(*evalue_pt==0 || /* chaine de caractere finie*/ |
395 | (ord<10 && (*evalue_pt==',' || *evalue_pt==';' || *evalue_pt==')' |
396 | (ord<10 && (*evalue_pt==',' || *evalue_pt==';' || *evalue_pt==')' |
396 |
|
397 | || *evalue_pt=='|'))) |
397 | goto ok; |
398 | goto ok; |
398 | switch(*evalue_pt) { |
399 | switch(*evalue_pt) { |
399 |
|
400 | case '+': |
400 |
|
401 | if(ord<=8) break; |
401 |
|
402 | evalue_pt++; d+=_evalue(8);goto vld; |
402 |
|
403 | case '-': |
403 |
|
404 | if(ord<=8) break; |
404 |
|
405 | evalue_pt++; d-=_evalue(8);goto vld; |
405 |
|
406 | case '*': |
406 |
|
407 | if(ord<=6) break; |
407 |
|
408 | evalue_pt++; d*=_evalue(6);goto vld; |
408 |
|
409 | case '/': |
409 |
|
410 | if(ord<=6) break; |
410 |
|
411 | evalue_pt++; dd=_evalue(6); |
411 |
|
412 | if(dd==0) {evalue_error=10;return NAN;} |
412 |
|
413 | d/=dd;goto vld; |
413 |
|
414 | case '%': { |
414 |
|
415 | int di, ddi; |
415 |
|
416 | if(ord<=6) break; |
416 |
|
417 | evalue_pt++; dd=_evalue(6); |
417 |
|
418 | if(dd==0) {evalue_error=10;return NAN;} |
418 |
|
419 | di=d; ddi=dd; d=di%ddi;goto vld; |
419 |
|
420 | } |
420 |
|
421 | case '^': { |
421 |
|
422 | if(ord<5) break; |
422 |
|
423 | evalue_pt++; d=pow(d,_evalue(5));goto vld; |
423 |
|
424 | } |
424 |
|
425 | default : { |
425 | /*if(ord<=6) break; |
- | |
426 | d*=_evalue(6);goto vld;*/ |
- | |
427 |
|
426 | return NAN; |
428 |
|
427 | } |
429 | } |
428 | } |
430 | ok: return d; |
429 | ok: return d; |
431 | } |
430 | } |
432 | 431 | ||
433 |
|
432 | /* substitute variable names by their environment strings |
434 |
|
433 | * The buffer pointed to by p must have enough space |
435 |
|
434 | * (defined by MAX_LINELEN). */ |
436 | char *_substit(char *p) |
435 | char *_substit(char *p) |
437 | { |
436 | { |
438 | return p; |
437 | return p; |
439 | } |
438 | } |
440 | 439 | ||
441 | char *(*substitute) (char *p)=_substit; |
440 | char *(*substitute) (char *p)=_substit; |
442 | 441 | ||
443 |
|
442 | /* evalue a string to double */ |
444 | double strevalue(char *p) |
443 | double strevalue(char *p) |
445 | { |
444 | { |
446 | char buf[MAX_LINELEN+1]; |
445 | char buf[MAX_LINELEN+1]; |
447 | 446 | ||
448 | if(p==NULL) return 0; |
447 | if(p==NULL) return 0; |
449 | mystrncpy(buf,p,sizeof(buf)); |
448 | mystrncpy(buf,p,sizeof(buf)); |
450 | substitute(buf); nospace(buf); |
449 | substitute(buf); nospace(buf); |
451 | if(check_parentheses(buf,0)) return NAN; |
450 | if(check_parentheses(buf,0)) return NAN; |
452 | set_evalue_error(0); |
451 | set_evalue_error(0); |
453 | set_evalue_pointer(buf); |
452 | set_evalue_pointer(buf); |
454 | return _evalue(10); |
453 | return _evalue(10); |
455 | } |
454 | } |
456 | 455 | ||
457 |
|
456 | /* compile an expression for faster evaluation |
458 |
|
457 | * returns -1 if cannot be compiled. |
459 | |
458 | * else returns the number of compilations. |
- | 459 | */ |
|
460 | int evalue_compile(char *p) |
460 | int evalue_compile(char *p) |
461 | { |
461 | { |
462 | char *p1, *p2, *pe, name[256], buf[8]; |
462 | char *p1, *p2, *pe, name[256], buf[8]; |
463 | int i,k; |
463 | int i,k; |
464 | 464 | ||
465 | k=0; |
465 | k=0; |
466 | for(p1=p; *p1; p1++) if((128&*p1)!=0) return -1; |
466 | for(p1=p; *p1; p1++) if((128&*p1)!=0) return -1; |
467 | nospace(p); |
467 | nospace(p); |
468 | for(p1=find_mathvar_start(p); *p1; p1=find_mathvar_start(pe)) { |
468 | for(p1=find_mathvar_start(p); *p1; p1=find_mathvar_start(pe)) { |
469 |
|
469 | pe=find_mathvar_end(p1); |
470 |
|
470 | if(!myisalpha(*p1)) continue; |
471 |
|
471 | p2=pe; if(p2-p1>16) continue; |
472 |
|
472 | memmove(name,p1,p2-p1); name[p2-p1]=0; |
473 |
|
473 | /* replace the variables by a number |
474 | for(i=0;i<*ev_varcnt && strcmp(name,ev_var[i].name)!=0;i++); |
- | |
475 |
|
474 | * at most 2000 variables on two characters : |
476 |
|
475 | * variable: 140 <= integer <150, number between 33 and 233 |
477 |
|
476 | * function: 130 <= integer < 140, number between 33 and 233 |
478 | pe=p1+2; k++; continue; |
- | |
479 | } |
- | |
480 |
|
477 | */ |
- | 478 | if(ev_varcnt!=NULL && ev_var!=NULL && *ev_varcnt>0) { |
|
481 | i= |
479 | for(i=0;i<*ev_varcnt && strcmp(name,ev_var[i].name)!=0;i++); |
482 | if(i |
480 | if(i<*ev_varcnt && i<2000) { |
483 |
|
481 | buf[0]=i/200+140; buf[1]=i%200+33; buf[2]=0; |
484 |
|
482 | string_modify(p,p1,p2,"%s",buf); |
485 |
|
483 | pe=p1+2; k++; continue; |
486 | } |
484 | } |
487 | } |
485 | } |
- | 486 | i=search_list(evalname,evalname_no,sizeof(evalname[0]),name); |
|
- | 487 | if(i>=0 && i<2000) { |
|
- | 488 | buf[0]=i/200+130; buf[1]=i%200+33; buf[2]=0; |
|
- | 489 | string_modify(p,p1,p2,"%s",buf); |
|
- | 490 | pe=p1+2; k++; continue; |
|
- | 491 | } |
|
- | 492 | } |
|
488 |
|
493 | return k; |
489 | } |
494 | } |
490 | - |