ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.31
Committed: Mon Feb 26 20:55:00 2024 UTC (2 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.30: +3 -3 lines
Log Message:
fix: Indexing error in last change

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.31 static const char RCSid[] = "$Id: calfunc.c,v 2.30 2024/02/26 18:16:35 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * calfunc.c - routines for calcomp using functions.
6     *
7 greg 2.8 * If VARIABLE is not set, only library functions
8     * can be accessed.
9     *
10     * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
11     */
12    
13 greg 2.9 #include "copyright.h"
14 greg 1.1
15     #include <stdio.h>
16 schorsch 2.11 #include <string.h>
17 greg 1.1 #include <errno.h>
18 greg 2.30 #include <stdlib.h>
19 greg 2.5 #include <math.h>
20    
21 schorsch 2.12 #include "rterror.h"
22 greg 1.1 #include "calcomp.h"
23    
24 greg 1.5 /* bits in argument flag (better be right!) */
25     #define AFLAGSIZ (8*sizeof(unsigned long))
26 greg 2.29 #define ALISTSIZ 10 /* maximum saved argument list */
27 greg 1.1
28     typedef struct activation {
29     char *name; /* function name */
30     struct activation *prev; /* previous activation */
31     double *ap; /* argument list */
32     unsigned long an; /* computed argument flags */
33     EPNODE *fun; /* argument function */
34     } ACTIVATION; /* an activation record */
35    
36     static ACTIVATION *curact = NULL;
37    
38 schorsch 2.12 static double libfunc(char *fname, VARDEF *vp);
39 greg 1.1
40 greg 2.8 #ifndef MAXLIB
41 greg 1.1 #define MAXLIB 64 /* maximum number of library functions */
42 greg 2.8 #endif
43 greg 1.1
44 greg 2.21 static double l_if(char *), l_select(char *);
45     static double l_min(char *), l_max(char *);
46     static double l_rand(char *);
47 greg 2.13 static double l_floor(char *), l_ceil(char *);
48     static double l_sqrt(char *);
49     static double l_sin(char *), l_cos(char *), l_tan(char *);
50     static double l_asin(char *), l_acos(char *), l_atan(char *), l_atan2(char *);
51     static double l_exp(char *), l_log(char *), l_log10(char *);
52 greg 1.1
53     /* functions must be listed alphabetically */
54     static LIBR library[MAXLIB] = {
55 greg 1.4 { "acos", 1, ':', l_acos },
56     { "asin", 1, ':', l_asin },
57     { "atan", 1, ':', l_atan },
58     { "atan2", 2, ':', l_atan2 },
59     { "ceil", 1, ':', l_ceil },
60     { "cos", 1, ':', l_cos },
61     { "exp", 1, ':', l_exp },
62     { "floor", 1, ':', l_floor },
63     { "if", 3, ':', l_if },
64     { "log", 1, ':', l_log },
65     { "log10", 1, ':', l_log10 },
66 greg 2.21 { "max", 1, ':', l_max },
67     { "min", 1, ':', l_min },
68 greg 1.4 { "rand", 1, ':', l_rand },
69     { "select", 1, ':', l_select },
70     { "sin", 1, ':', l_sin },
71     { "sqrt", 1, ':', l_sqrt },
72     { "tan", 1, ':', l_tan },
73 greg 1.1 };
74    
75 greg 2.22 static int libsize = 18;
76 greg 1.1
77     #define resolve(ep) ((ep)->type==VAR?(ep)->v.ln:argf((ep)->v.chan))
78    
79    
80     int
81 greg 2.21 fundefined( /* return # of req'd arguments for function */
82 greg 2.16 char *fname
83     )
84 greg 1.1 {
85 greg 2.16 LIBR *lp;
86     VARDEF *vp;
87 greg 1.1
88 greg 2.7 if ((vp = varlookup(fname)) != NULL && vp->def != NULL
89     && vp->def->v.kid->type == FUNC)
90 greg 1.1 return(nekids(vp->def->v.kid) - 1);
91 greg 2.7 lp = vp != NULL ? vp->lib : liblookup(fname);
92     if (lp == NULL)
93     return(0);
94     return(lp->nargs);
95 greg 1.1 }
96    
97    
98     double
99 greg 2.16 funvalue( /* return a function value to the user */
100     char *fname,
101     int n,
102     double *a
103     )
104 greg 1.1 {
105     ACTIVATION act;
106 greg 2.16 VARDEF *vp;
107 greg 1.1 double rval;
108     /* push environment */
109     act.name = fname;
110     act.prev = curact;
111     act.ap = a;
112 greg 2.19 if (n < AFLAGSIZ)
113     act.an = (1L<<n)-1;
114     else {
115 greg 1.5 act.an = ~0;
116 greg 2.19 if (n > AFLAGSIZ)
117     wputs("Excess arguments in funvalue()\n");
118     }
119 greg 1.1 act.fun = NULL;
120     curact = &act;
121    
122     if ((vp = varlookup(fname)) == NULL || vp->def == NULL
123     || vp->def->v.kid->type != FUNC)
124     rval = libfunc(fname, vp);
125     else
126     rval = evalue(vp->def->v.kid->sibling);
127    
128     curact = act.prev; /* pop environment */
129     return(rval);
130     }
131    
132    
133 greg 2.8 void
134 greg 2.16 funset( /* set a library function */
135     char *fname,
136     int nargs,
137     int assign,
138     double (*fptr)(char *)
139     )
140 greg 1.1 {
141 greg 2.6 int oldlibsize = libsize;
142 greg 2.8 char *cp;
143 greg 2.16 LIBR *lp;
144 greg 2.8 /* check for context */
145     for (cp = fname; *cp; cp++)
146     ;
147     if (cp == fname)
148     return;
149 greg 2.21 while (cp[-1] == CNTXMARK) {
150 greg 2.8 *--cp = '\0';
151 greg 2.21 if (cp == fname) return;
152     }
153 greg 2.2 if ((lp = liblookup(fname)) == NULL) { /* insert */
154 greg 2.25 if (fptr == NULL)
155     return; /* nothing! */
156 greg 1.1 if (libsize >= MAXLIB) {
157     eputs("Too many library functons!\n");
158     quit(1);
159     }
160     for (lp = &library[libsize]; lp > library; lp--)
161 greg 2.17 if (strcmp(lp[-1].fname, fname) > 0)
162     lp[0] = lp[-1];
163     else
164 greg 1.1 break;
165     libsize++;
166     }
167 greg 2.2 if (fptr == NULL) { /* delete */
168     while (lp < &library[libsize-1]) {
169 greg 2.17 lp[0] = lp[1];
170 greg 2.2 lp++;
171     }
172     libsize--;
173     } else { /* or assign */
174     lp[0].fname = fname; /* string must be static! */
175     lp[0].nargs = nargs;
176     lp[0].atyp = assign;
177     lp[0].f = fptr;
178     }
179 greg 2.6 if (libsize != oldlibsize)
180     libupdate(fname); /* relink library */
181 greg 1.1 }
182    
183    
184     int
185 greg 2.16 nargum(void) /* return number of available arguments */
186 greg 1.1 {
187 greg 2.16 int n;
188 greg 1.1
189     if (curact == NULL)
190     return(0);
191     if (curact->fun == NULL) {
192     for (n = 0; (1L<<n) & curact->an; n++)
193     ;
194     return(n);
195     }
196     return(nekids(curact->fun) - 1);
197     }
198    
199    
200     double
201 greg 2.16 argument(int n) /* return nth argument for active function */
202 greg 1.1 {
203 greg 2.16 ACTIVATION *actp = curact;
204 greg 2.30 EPNODE *ep;
205 greg 1.1 double aval;
206    
207 greg 2.19 if (!actp | (--n < 0)) {
208 greg 1.1 eputs("Bad call to argument!\n");
209     quit(1);
210     }
211 greg 2.20 if ((n < AFLAGSIZ) & actp->an >> n) /* already computed? */
212 greg 1.1 return(actp->ap[n]);
213    
214 greg 2.19 if (!actp->fun || !(ep = ekid(actp->fun, n+1))) {
215 greg 1.1 eputs(actp->name);
216     eputs(": too few arguments\n");
217     quit(1);
218     }
219 greg 2.19 curact = actp->prev; /* previous context */
220 greg 1.1 aval = evalue(ep); /* compute argument */
221 greg 2.20 curact = actp; /* put back calling context */
222     if (n < ALISTSIZ) { /* save value if room */
223 greg 1.1 actp->ap[n] = aval;
224     actp->an |= 1L<<n;
225     }
226     return(aval);
227     }
228    
229    
230     VARDEF *
231 greg 2.16 argf(int n) /* return function def for nth argument */
232 greg 1.1 {
233 greg 2.16 ACTIVATION *actp;
234     EPNODE *ep;
235 greg 1.1
236     for (actp = curact; actp != NULL; actp = actp->prev) {
237    
238     if (n <= 0)
239     break;
240    
241     if (actp->fun == NULL)
242     goto badarg;
243    
244     if ((ep = ekid(actp->fun, n)) == NULL) {
245     eputs(actp->name);
246     eputs(": too few arguments\n");
247     quit(1);
248     }
249     if (ep->type == VAR)
250     return(ep->v.ln); /* found it */
251    
252     if (ep->type != ARG)
253     goto badarg;
254    
255     n = ep->v.chan; /* try previous context */
256     }
257     eputs("Bad call to argf!\n");
258     quit(1);
259    
260     badarg:
261     eputs(actp->name);
262     eputs(": argument not a function\n");
263     quit(1);
264 schorsch 2.11 return NULL; /* pro forma return */
265 greg 1.1 }
266    
267    
268     char *
269 greg 2.16 argfun(int n) /* return function name for nth argument */
270 greg 1.1 {
271     return(argf(n)->name);
272     }
273    
274    
275     double
276 greg 2.16 efunc(EPNODE *ep) /* evaluate a function */
277 greg 1.1 {
278     ACTIVATION act;
279     double alist[ALISTSIZ];
280     double rval;
281 greg 2.16 VARDEF *dp;
282 greg 1.1 /* push environment */
283     dp = resolve(ep->v.kid);
284     act.name = dp->name;
285     act.prev = curact;
286     act.ap = alist;
287     act.an = 0;
288     act.fun = ep;
289     curact = &act;
290    
291     if (dp->def == NULL || dp->def->v.kid->type != FUNC)
292     rval = libfunc(act.name, dp);
293     else
294     rval = evalue(dp->def->v.kid->sibling);
295    
296     curact = act.prev; /* pop environment */
297     return(rval);
298     }
299    
300    
301 greg 2.30 double
302     eargument( /* evaluate an argument */
303     EPNODE *ep
304     )
305     {
306 greg 2.31 if ((ep->v.chan <= AFLAGSIZ) & curact->an >> (ep->v.chan-1))
307     return(curact->ap[ep->v.chan-1]);
308 greg 2.30
309     return(argument(ep->v.chan));
310     }
311    
312    
313 greg 1.1 LIBR *
314 greg 2.16 liblookup(char *fname) /* look up a library function */
315 greg 1.1 {
316     int upper, lower;
317 greg 2.16 int cm, i;
318 greg 1.1
319     lower = 0;
320     upper = cm = libsize;
321    
322     while ((i = (lower + upper) >> 1) != cm) {
323     cm = strcmp(fname, library[i].fname);
324     if (cm > 0)
325     lower = i;
326     else if (cm < 0)
327     upper = i;
328     else
329     return(&library[i]);
330     cm = i;
331     }
332     return(NULL);
333     }
334    
335    
336     /*
337     * The following routines are for internal use:
338     */
339    
340    
341     static double
342 greg 2.16 libfunc( /* execute library function */
343     char *fname,
344     VARDEF *vp
345     )
346 greg 1.1 {
347 greg 2.16 LIBR *lp;
348 greg 1.1 double d;
349     int lasterrno;
350    
351 greg 2.3 if (vp != NULL)
352     lp = vp->lib;
353     else
354     lp = liblookup(fname);
355     if (lp == NULL) {
356 greg 1.1 eputs(fname);
357     eputs(": undefined function\n");
358     quit(1);
359     }
360     lasterrno = errno;
361     errno = 0;
362 greg 2.3 d = (*lp->f)(lp->fname);
363 greg 2.15 #ifdef isnan
364 greg 2.18 if (errno == 0) {
365 greg 1.9 if (isnan(d))
366     errno = EDOM;
367     else if (isinf(d))
368     errno = ERANGE;
369 greg 2.18 }
370 greg 1.1 #endif
371 greg 2.28 if ((errno == EDOM) | (errno == ERANGE)) {
372 greg 1.1 wputs(fname);
373 greg 1.8 if (errno == EDOM)
374     wputs(": domain error\n");
375     else if (errno == ERANGE)
376     wputs(": range error\n");
377     else
378     wputs(": error in call\n");
379 greg 1.1 return(0.0);
380     }
381     errno = lasterrno;
382     return(d);
383     }
384    
385    
386     /*
387     * Library functions:
388     */
389    
390    
391     static double
392 greg 2.13 l_if(char *nm) /* if(cond, then, else) conditional expression */
393 greg 1.1 /* cond evaluates true if greater than zero */
394     {
395     if (argument(1) > 0.0)
396     return(argument(2));
397     else
398     return(argument(3));
399     }
400    
401    
402     static double
403 greg 2.13 l_select(char *nm) /* return argument #(A1+1) */
404 greg 1.1 {
405 greg 2.23 int narg = nargum();
406     double a1 = argument(1);
407     int n = (int)(a1 + .5);
408 greg 1.1
409 greg 2.28 if ((a1 < -.5) | (n >= narg)) {
410 greg 1.1 errno = EDOM;
411     return(0.0);
412     }
413 greg 2.23 if (!n) /* asking max index? */
414     return(narg-1);
415 greg 1.1 return(argument(n+1));
416     }
417    
418    
419     static double
420 greg 2.21 l_max(char *nm) /* general maximum function */
421     {
422     int n = nargum();
423 greg 2.24 double vmax = argument(1);
424 greg 2.21
425 greg 2.27 while (n > 1) {
426     double v = argument(n--);
427 greg 2.21 if (vmax < v)
428     vmax = v;
429     }
430     return(vmax);
431     }
432    
433    
434     static double
435     l_min(char *nm) /* general minimum function */
436     {
437     int n = nargum();
438 greg 2.24 double vmin = argument(1);
439 greg 2.21
440 greg 2.27 while (n > 1) {
441     double v = argument(n--);
442 greg 2.21 if (vmin > v)
443     vmin = v;
444     }
445     return(vmin);
446     }
447    
448    
449     static double
450 greg 2.13 l_rand(char *nm) /* random function between 0 and 1 */
451 greg 1.1 {
452     double x;
453    
454     x = argument(1);
455     x *= 1.0/(1.0 + x*x) + 2.71828182845904;
456     x += .785398163397447 - floor(x);
457     x = 1e5 / x;
458     return(x - floor(x));
459     }
460    
461    
462     static double
463 greg 2.13 l_floor(char *nm) /* return largest integer not greater than arg1 */
464 greg 1.1 {
465     return(floor(argument(1)));
466     }
467    
468    
469     static double
470 greg 2.13 l_ceil(char *nm) /* return smallest integer not less than arg1 */
471 greg 1.1 {
472     return(ceil(argument(1)));
473     }
474    
475    
476     static double
477 greg 2.13 l_sqrt(char *nm)
478 greg 1.1 {
479     return(sqrt(argument(1)));
480     }
481    
482    
483     static double
484 greg 2.13 l_sin(char *nm)
485 greg 1.1 {
486     return(sin(argument(1)));
487     }
488    
489    
490     static double
491 greg 2.13 l_cos(char *nm)
492 greg 1.1 {
493     return(cos(argument(1)));
494     }
495    
496    
497     static double
498 greg 2.13 l_tan(char *nm)
499 greg 1.1 {
500     return(tan(argument(1)));
501     }
502    
503    
504     static double
505 greg 2.13 l_asin(char *nm)
506 greg 1.1 {
507     return(asin(argument(1)));
508     }
509    
510    
511     static double
512 greg 2.13 l_acos(char *nm)
513 greg 1.1 {
514     return(acos(argument(1)));
515     }
516    
517    
518     static double
519 greg 2.13 l_atan(char *nm)
520 greg 1.1 {
521     return(atan(argument(1)));
522     }
523    
524    
525     static double
526 greg 2.13 l_atan2(char *nm)
527 greg 1.1 {
528     return(atan2(argument(1), argument(2)));
529     }
530    
531    
532     static double
533 greg 2.13 l_exp(char *nm)
534 greg 1.1 {
535     return(exp(argument(1)));
536     }
537    
538    
539     static double
540 greg 2.13 l_log(char *nm)
541 greg 1.1 {
542     return(log(argument(1)));
543     }
544    
545    
546     static double
547 greg 2.13 l_log10(char *nm)
548 greg 1.1 {
549     return(log10(argument(1)));
550     }