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 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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: calfunc.c,v 2.30 2024/02/26 18:16:35 greg Exp $";
3 #endif
4 /*
5 * calfunc.c - routines for calcomp using functions.
6 *
7 * 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 #include "copyright.h"
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <math.h>
20
21 #include "rterror.h"
22 #include "calcomp.h"
23
24 /* bits in argument flag (better be right!) */
25 #define AFLAGSIZ (8*sizeof(unsigned long))
26 #define ALISTSIZ 10 /* maximum saved argument list */
27
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 static double libfunc(char *fname, VARDEF *vp);
39
40 #ifndef MAXLIB
41 #define MAXLIB 64 /* maximum number of library functions */
42 #endif
43
44 static double l_if(char *), l_select(char *);
45 static double l_min(char *), l_max(char *);
46 static double l_rand(char *);
47 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
53 /* functions must be listed alphabetically */
54 static LIBR library[MAXLIB] = {
55 { "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 { "max", 1, ':', l_max },
67 { "min", 1, ':', l_min },
68 { "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 };
74
75 static int libsize = 18;
76
77 #define resolve(ep) ((ep)->type==VAR?(ep)->v.ln:argf((ep)->v.chan))
78
79
80 int
81 fundefined( /* return # of req'd arguments for function */
82 char *fname
83 )
84 {
85 LIBR *lp;
86 VARDEF *vp;
87
88 if ((vp = varlookup(fname)) != NULL && vp->def != NULL
89 && vp->def->v.kid->type == FUNC)
90 return(nekids(vp->def->v.kid) - 1);
91 lp = vp != NULL ? vp->lib : liblookup(fname);
92 if (lp == NULL)
93 return(0);
94 return(lp->nargs);
95 }
96
97
98 double
99 funvalue( /* return a function value to the user */
100 char *fname,
101 int n,
102 double *a
103 )
104 {
105 ACTIVATION act;
106 VARDEF *vp;
107 double rval;
108 /* push environment */
109 act.name = fname;
110 act.prev = curact;
111 act.ap = a;
112 if (n < AFLAGSIZ)
113 act.an = (1L<<n)-1;
114 else {
115 act.an = ~0;
116 if (n > AFLAGSIZ)
117 wputs("Excess arguments in funvalue()\n");
118 }
119 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 void
134 funset( /* set a library function */
135 char *fname,
136 int nargs,
137 int assign,
138 double (*fptr)(char *)
139 )
140 {
141 int oldlibsize = libsize;
142 char *cp;
143 LIBR *lp;
144 /* check for context */
145 for (cp = fname; *cp; cp++)
146 ;
147 if (cp == fname)
148 return;
149 while (cp[-1] == CNTXMARK) {
150 *--cp = '\0';
151 if (cp == fname) return;
152 }
153 if ((lp = liblookup(fname)) == NULL) { /* insert */
154 if (fptr == NULL)
155 return; /* nothing! */
156 if (libsize >= MAXLIB) {
157 eputs("Too many library functons!\n");
158 quit(1);
159 }
160 for (lp = &library[libsize]; lp > library; lp--)
161 if (strcmp(lp[-1].fname, fname) > 0)
162 lp[0] = lp[-1];
163 else
164 break;
165 libsize++;
166 }
167 if (fptr == NULL) { /* delete */
168 while (lp < &library[libsize-1]) {
169 lp[0] = lp[1];
170 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 if (libsize != oldlibsize)
180 libupdate(fname); /* relink library */
181 }
182
183
184 int
185 nargum(void) /* return number of available arguments */
186 {
187 int n;
188
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 argument(int n) /* return nth argument for active function */
202 {
203 ACTIVATION *actp = curact;
204 EPNODE *ep;
205 double aval;
206
207 if (!actp | (--n < 0)) {
208 eputs("Bad call to argument!\n");
209 quit(1);
210 }
211 if ((n < AFLAGSIZ) & actp->an >> n) /* already computed? */
212 return(actp->ap[n]);
213
214 if (!actp->fun || !(ep = ekid(actp->fun, n+1))) {
215 eputs(actp->name);
216 eputs(": too few arguments\n");
217 quit(1);
218 }
219 curact = actp->prev; /* previous context */
220 aval = evalue(ep); /* compute argument */
221 curact = actp; /* put back calling context */
222 if (n < ALISTSIZ) { /* save value if room */
223 actp->ap[n] = aval;
224 actp->an |= 1L<<n;
225 }
226 return(aval);
227 }
228
229
230 VARDEF *
231 argf(int n) /* return function def for nth argument */
232 {
233 ACTIVATION *actp;
234 EPNODE *ep;
235
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 return NULL; /* pro forma return */
265 }
266
267
268 char *
269 argfun(int n) /* return function name for nth argument */
270 {
271 return(argf(n)->name);
272 }
273
274
275 double
276 efunc(EPNODE *ep) /* evaluate a function */
277 {
278 ACTIVATION act;
279 double alist[ALISTSIZ];
280 double rval;
281 VARDEF *dp;
282 /* 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 double
302 eargument( /* evaluate an argument */
303 EPNODE *ep
304 )
305 {
306 if ((ep->v.chan <= AFLAGSIZ) & curact->an >> (ep->v.chan-1))
307 return(curact->ap[ep->v.chan-1]);
308
309 return(argument(ep->v.chan));
310 }
311
312
313 LIBR *
314 liblookup(char *fname) /* look up a library function */
315 {
316 int upper, lower;
317 int cm, i;
318
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 libfunc( /* execute library function */
343 char *fname,
344 VARDEF *vp
345 )
346 {
347 LIBR *lp;
348 double d;
349 int lasterrno;
350
351 if (vp != NULL)
352 lp = vp->lib;
353 else
354 lp = liblookup(fname);
355 if (lp == NULL) {
356 eputs(fname);
357 eputs(": undefined function\n");
358 quit(1);
359 }
360 lasterrno = errno;
361 errno = 0;
362 d = (*lp->f)(lp->fname);
363 #ifdef isnan
364 if (errno == 0) {
365 if (isnan(d))
366 errno = EDOM;
367 else if (isinf(d))
368 errno = ERANGE;
369 }
370 #endif
371 if ((errno == EDOM) | (errno == ERANGE)) {
372 wputs(fname);
373 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 return(0.0);
380 }
381 errno = lasterrno;
382 return(d);
383 }
384
385
386 /*
387 * Library functions:
388 */
389
390
391 static double
392 l_if(char *nm) /* if(cond, then, else) conditional expression */
393 /* 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 l_select(char *nm) /* return argument #(A1+1) */
404 {
405 int narg = nargum();
406 double a1 = argument(1);
407 int n = (int)(a1 + .5);
408
409 if ((a1 < -.5) | (n >= narg)) {
410 errno = EDOM;
411 return(0.0);
412 }
413 if (!n) /* asking max index? */
414 return(narg-1);
415 return(argument(n+1));
416 }
417
418
419 static double
420 l_max(char *nm) /* general maximum function */
421 {
422 int n = nargum();
423 double vmax = argument(1);
424
425 while (n > 1) {
426 double v = argument(n--);
427 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 double vmin = argument(1);
439
440 while (n > 1) {
441 double v = argument(n--);
442 if (vmin > v)
443 vmin = v;
444 }
445 return(vmin);
446 }
447
448
449 static double
450 l_rand(char *nm) /* random function between 0 and 1 */
451 {
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 l_floor(char *nm) /* return largest integer not greater than arg1 */
464 {
465 return(floor(argument(1)));
466 }
467
468
469 static double
470 l_ceil(char *nm) /* return smallest integer not less than arg1 */
471 {
472 return(ceil(argument(1)));
473 }
474
475
476 static double
477 l_sqrt(char *nm)
478 {
479 return(sqrt(argument(1)));
480 }
481
482
483 static double
484 l_sin(char *nm)
485 {
486 return(sin(argument(1)));
487 }
488
489
490 static double
491 l_cos(char *nm)
492 {
493 return(cos(argument(1)));
494 }
495
496
497 static double
498 l_tan(char *nm)
499 {
500 return(tan(argument(1)));
501 }
502
503
504 static double
505 l_asin(char *nm)
506 {
507 return(asin(argument(1)));
508 }
509
510
511 static double
512 l_acos(char *nm)
513 {
514 return(acos(argument(1)));
515 }
516
517
518 static double
519 l_atan(char *nm)
520 {
521 return(atan(argument(1)));
522 }
523
524
525 static double
526 l_atan2(char *nm)
527 {
528 return(atan2(argument(1), argument(2)));
529 }
530
531
532 static double
533 l_exp(char *nm)
534 {
535 return(exp(argument(1)));
536 }
537
538
539 static double
540 l_log(char *nm)
541 {
542 return(log(argument(1)));
543 }
544
545
546 static double
547 l_log10(char *nm)
548 {
549 return(log10(argument(1)));
550 }