|
1 // mathfunc.c - basic mathematical functions for use in math evaluations |
|
2 // |
|
3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. |
|
4 // |
|
5 /* |
|
6 * This file is part of zsh, the Z shell. |
|
7 * |
|
8 * Copyright (c) 1999 Peter Stephenson |
|
9 * All rights reserved. |
|
10 * |
|
11 * Permission is hereby granted, without written agreement and without |
|
12 * license or royalty fees, to use, copy, modify, and distribute this |
|
13 * software and to distribute modified versions of this software for any |
|
14 * purpose, provided that the above copyright notice and the following |
|
15 * two paragraphs appear in all copies of this software. |
|
16 * |
|
17 * In no event shall Peter Stephenson or the Zsh Development Group be liable |
|
18 * to any party for direct, indirect, special, incidental, or consequential |
|
19 * damages arising out of the use of this software and its documentation, |
|
20 * even if Peter Stephenson and the Zsh Development Group have been advised of |
|
21 * the possibility of such damage. |
|
22 * |
|
23 * Peter Stephenson and the Zsh Development Group specifically disclaim any |
|
24 * warranties, including, but not limited to, the implied warranties of |
|
25 * merchantability and fitness for a particular purpose. The software |
|
26 * provided hereunder is on an "as is" basis, and Peter Stephenson and the |
|
27 * Zsh Development Group have no obligation to provide maintenance, |
|
28 * support, updates, enhancements, or modifications. |
|
29 * |
|
30 */ |
|
31 #include "mathfunc.mdh" |
|
32 #include "mathfunc.pro" |
|
33 |
|
34 #include <math.h> |
|
35 |
|
36 #ifdef __SYMBIAN32__ |
|
37 #ifdef __WINSCW__ |
|
38 #pragma warn_unusedarg off |
|
39 #endif//__WINSCW__ |
|
40 #endif//__SYMBIAN32__ |
|
41 |
|
42 enum { |
|
43 MF_ABS, |
|
44 MF_ACOS, |
|
45 MF_ACOSH, |
|
46 MF_ASIN, |
|
47 MF_ASINH, |
|
48 MF_ATAN, |
|
49 MF_ATANH, |
|
50 MF_CBRT, |
|
51 MF_CEIL, |
|
52 MF_COPYSIGN, |
|
53 MF_COS, |
|
54 MF_COSH, |
|
55 MF_ERF, |
|
56 MF_ERFC, |
|
57 MF_EXP, |
|
58 MF_EXPM1, |
|
59 MF_FABS, |
|
60 MF_FLOAT, |
|
61 MF_FLOOR, |
|
62 MF_FMOD, |
|
63 MF_GAMMA, |
|
64 MF_HYPOT, |
|
65 MF_ILOGB, |
|
66 MF_INT, |
|
67 MF_J0, |
|
68 MF_J1, |
|
69 MF_JN, |
|
70 MF_LDEXP, |
|
71 MF_LGAMMA, |
|
72 MF_LOG, |
|
73 MF_LOG10, |
|
74 MF_LOG1P, |
|
75 MF_LOGB, |
|
76 MF_NEXTAFTER, |
|
77 MF_RINT, |
|
78 MF_SCALB, |
|
79 #ifdef HAVE_SIGNGAM |
|
80 MF_SIGNGAM, |
|
81 #endif |
|
82 MF_SIN, |
|
83 MF_SINH, |
|
84 MF_SQRT, |
|
85 MF_TAN, |
|
86 MF_TANH, |
|
87 MF_Y0, |
|
88 MF_Y1, |
|
89 MF_YN |
|
90 }; |
|
91 |
|
92 /* also functions taking a string argument */ |
|
93 |
|
94 enum { |
|
95 MS_RAND48 |
|
96 }; |
|
97 |
|
98 /* |
|
99 * also to do, but differently argument or returned: abs (no type |
|
100 * conversion), atan2. |
|
101 */ |
|
102 |
|
103 /* Flags for bounds. Note these must start at 1, not 0. */ |
|
104 |
|
105 enum { |
|
106 BF_POS = 1, /* must be positive */ |
|
107 BF_NONNEG = 2, /* must be non-negative */ |
|
108 BF_FRAC = 3, /* must be -1 <= x <= 1 */ |
|
109 BF_GE1 = 4, /* must be >= 1 */ |
|
110 BF_FRACO = 5, /* must be in open range -1 < x < 1 */ |
|
111 BF_INTPOS = 6, /* must be non-integer or positive */ |
|
112 BF_GTRM1 = 7, /* must be > -1 */ |
|
113 BF_NONZ = 8, /* must be nonzero */ |
|
114 BF_POS2 = 9 /* second argument must be positive */ |
|
115 }; |
|
116 |
|
117 #define BFLAG(x) ((x) << 8) |
|
118 |
|
119 /* |
|
120 * Flags for type of function: unlike the above, these must |
|
121 * be individually bit-testable. |
|
122 */ |
|
123 |
|
124 enum { |
|
125 TF_NOCONV = 1, /* don't convert to float */ |
|
126 TF_INT1 = 2, /* first argument is integer */ |
|
127 TF_INT2 = 4, /* second argument is integer */ |
|
128 TF_NOASS = 8 /* don't assign result as double */ |
|
129 }; |
|
130 |
|
131 #define TFLAG(x) ((x) << 16) |
|
132 |
|
133 |
|
134 static struct mathfunc mftab[] = { |
|
135 /* Functions taking string arguments */ |
|
136 #ifdef HAVE_ERAND48 |
|
137 /* here to avoid comma hassle */ |
|
138 STRMATHFUNC("rand48", math_string, MS_RAND48), |
|
139 #endif |
|
140 |
|
141 NUMMATHFUNC("abs", math_func, 1, 1, MF_ABS | BFLAG(BF_FRAC) | |
|
142 TFLAG(TF_NOCONV|TF_NOASS)), |
|
143 NUMMATHFUNC("acos", math_func, 1, 1, MF_ACOS | BFLAG(BF_FRAC)), |
|
144 NUMMATHFUNC("acosh", math_func, 1, 1, MF_ACOSH | BFLAG(BF_GE1)), |
|
145 NUMMATHFUNC("asin", math_func, 1, 1, MF_ASIN | BFLAG(BF_FRAC)), |
|
146 NUMMATHFUNC("asinh", math_func, 1, 1, MF_ASINH), |
|
147 NUMMATHFUNC("atan", math_func, 1, 2, MF_ATAN), |
|
148 NUMMATHFUNC("atanh", math_func, 1, 1, MF_ATANH | BFLAG(BF_FRACO)), |
|
149 NUMMATHFUNC("cbrt", math_func, 1, 1, MF_CBRT), |
|
150 NUMMATHFUNC("ceil", math_func, 1, 1, MF_CEIL), |
|
151 NUMMATHFUNC("copysign", math_func, 2, 2, MF_COPYSIGN), |
|
152 NUMMATHFUNC("cos", math_func, 1, 1, MF_COS), |
|
153 NUMMATHFUNC("cosh", math_func, 1, 1, MF_COSH), |
|
154 NUMMATHFUNC("erf", math_func, 1, 1, MF_ERF), |
|
155 NUMMATHFUNC("erfc", math_func, 1, 1, MF_ERFC), |
|
156 NUMMATHFUNC("exp", math_func, 1, 1, MF_EXP), |
|
157 NUMMATHFUNC("expm1", math_func, 1, 1, MF_EXPM1), |
|
158 NUMMATHFUNC("fabs", math_func, 1, 1, MF_FABS), |
|
159 NUMMATHFUNC("float", math_func, 1, 1, MF_FLOAT), |
|
160 NUMMATHFUNC("floor", math_func, 1, 1, MF_FLOOR), |
|
161 NUMMATHFUNC("fmod", math_func, 2, 2, MF_FMOD), |
|
162 NUMMATHFUNC("gamma", math_func, 1, 1, MF_GAMMA | BFLAG(BF_INTPOS)), |
|
163 NUMMATHFUNC("hypot", math_func, 2, 2, MF_HYPOT), |
|
164 NUMMATHFUNC("ilogb", math_func, 1, 1, MF_ILOGB | BFLAG(BF_NONZ) | |
|
165 TFLAG(TF_NOASS)), |
|
166 NUMMATHFUNC("int", math_func, 1, 1, MF_INT | TFLAG(TF_NOASS)), |
|
167 NUMMATHFUNC("j0", math_func, 1, 1, MF_J0), |
|
168 NUMMATHFUNC("j1", math_func, 1, 1, MF_J1), |
|
169 NUMMATHFUNC("jn", math_func, 2, 2, MF_JN | TFLAG(TF_INT1)), |
|
170 NUMMATHFUNC("ldexp", math_func, 2, 2, MF_LDEXP | TFLAG(TF_INT2)), |
|
171 NUMMATHFUNC("lgamma", math_func, 1, 1, MF_LGAMMA | BFLAG(BF_INTPOS)), |
|
172 NUMMATHFUNC("log", math_func, 1, 1, MF_LOG | BFLAG(BF_POS)), |
|
173 NUMMATHFUNC("log10", math_func, 1, 1, MF_LOG10 | BFLAG(BF_POS)), |
|
174 NUMMATHFUNC("log1p", math_func, 1, 1, MF_LOG1P | BFLAG(BF_GTRM1)), |
|
175 NUMMATHFUNC("logb", math_func, 1, 1, MF_LOGB | BFLAG(BF_NONZ)), |
|
176 NUMMATHFUNC("nextafter", math_func, 2, 2, MF_NEXTAFTER), |
|
177 NUMMATHFUNC("rint", math_func, 1, 1, MF_RINT), |
|
178 NUMMATHFUNC("scalb", math_func, 2, 2, MF_SCALB | TFLAG(TF_INT2)), |
|
179 #ifdef HAVE_SIGNGAM |
|
180 NUMMATHFUNC("signgam", math_func, 0, 0, MF_SIGNGAM | TFLAG(TF_NOASS)), |
|
181 #endif |
|
182 NUMMATHFUNC("sin", math_func, 1, 1, MF_SIN), |
|
183 NUMMATHFUNC("sinh", math_func, 1, 1, MF_SINH), |
|
184 NUMMATHFUNC("sqrt", math_func, 1, 1, MF_SQRT | BFLAG(BF_NONNEG)), |
|
185 NUMMATHFUNC("tan", math_func, 1, 1, MF_TAN), |
|
186 NUMMATHFUNC("tanh", math_func, 1, 1, MF_TANH), |
|
187 NUMMATHFUNC("y0", math_func, 1, 1, MF_Y0 | BFLAG(BF_POS)), |
|
188 NUMMATHFUNC("y1", math_func, 1, 1, MF_Y1 | BFLAG(BF_POS)), |
|
189 NUMMATHFUNC("yn", math_func, 2, 2, MF_YN | BFLAG(BF_POS2) | TFLAG(TF_INT1)) |
|
190 }; |
|
191 |
|
192 /**/ |
|
193 static mnumber |
|
194 math_func(char *name, int argc, mnumber *argv, int id) |
|
195 { |
|
196 mnumber ret; |
|
197 |
|
198 double argd = 0, argd2 = 0, retd = 0; |
|
199 int argi = 0; |
|
200 |
|
201 if (argc && !(id & TFLAG(TF_NOCONV))) { |
|
202 if (id & TFLAG(TF_INT1)) |
|
203 argi = (argv->type == MN_FLOAT) ? (zlong)argv->u.d : argv->u.l; |
|
204 else |
|
205 argd = (argv->type == MN_INTEGER) ? (double)argv->u.l : argv->u.d; |
|
206 if (argc > 1) { |
|
207 if (id & TFLAG(TF_INT2)) |
|
208 argi = (argv[1].type == MN_FLOAT) ? (zlong)argv[1].u.d : |
|
209 argv[1].u.l; |
|
210 else |
|
211 argd2 = (argv[1].type == MN_INTEGER) ? (double)argv[1].u.l : |
|
212 argv[1].u.d; |
|
213 } |
|
214 } |
|
215 |
|
216 ret.type = MN_FLOAT; |
|
217 ret.u.d = 0; |
|
218 |
|
219 if (errflag) |
|
220 return ret; |
|
221 |
|
222 if (id & 0xff00) { |
|
223 int rtst = 0; |
|
224 |
|
225 switch ((id >> 8) & 0xff) { |
|
226 case BF_POS: |
|
227 rtst = (argd <= 0.0); |
|
228 break; |
|
229 |
|
230 case BF_NONNEG: |
|
231 rtst = (argd < 0.0); |
|
232 break; |
|
233 |
|
234 case BF_FRAC: |
|
235 rtst = (fabs(argd) > 1.0); |
|
236 break; |
|
237 |
|
238 case BF_GE1: |
|
239 rtst = (argd < 1.0); |
|
240 break; |
|
241 |
|
242 case BF_FRACO: |
|
243 rtst = (fabs(argd) >= 1.0); |
|
244 break; |
|
245 |
|
246 case BF_INTPOS: |
|
247 rtst = (argd <= 0 && (double)(zlong)argd == argd); |
|
248 break; |
|
249 |
|
250 case BF_GTRM1: |
|
251 rtst = (argd <= -1); |
|
252 break; |
|
253 |
|
254 case BF_POS2: |
|
255 rtst = (argd2 <= 0.0); |
|
256 break; |
|
257 } |
|
258 |
|
259 if (rtst) { |
|
260 zerr("math: argument to %s out of range", name, 0); |
|
261 return ret; |
|
262 } |
|
263 } |
|
264 |
|
265 switch (id & 0xff) { |
|
266 case MF_ABS: |
|
267 ret.type = argv->type; |
|
268 if (argv->type == MN_INTEGER) |
|
269 ret.u.l = (argv->u.l < 0) ? - argv->u.l : argv->u.l; |
|
270 else |
|
271 ret.u.d = fabs(argv->u.d); |
|
272 break; |
|
273 |
|
274 case MF_ACOS: |
|
275 retd = acos(argd); |
|
276 break; |
|
277 |
|
278 case MF_ACOSH: |
|
279 retd = acosh(argd); |
|
280 break; |
|
281 |
|
282 case MF_ASIN: |
|
283 retd = asin(argd); |
|
284 break; |
|
285 |
|
286 case MF_ASINH: |
|
287 retd = asinh(argd); |
|
288 break; |
|
289 |
|
290 case MF_ATAN: |
|
291 if (argc == 2) |
|
292 retd = atan2(argd, argd2); |
|
293 else |
|
294 retd = atan(argd); |
|
295 break; |
|
296 |
|
297 case MF_ATANH: |
|
298 retd = atanh(argd); |
|
299 break; |
|
300 |
|
301 case MF_CBRT: |
|
302 retd = cbrt(argd); |
|
303 break; |
|
304 |
|
305 case MF_CEIL: |
|
306 retd = ceil(argd); |
|
307 break; |
|
308 |
|
309 case MF_COPYSIGN: |
|
310 retd = copysign(argd, argd2); |
|
311 break; |
|
312 |
|
313 case MF_COS: |
|
314 retd = cos(argd); |
|
315 break; |
|
316 |
|
317 case MF_COSH: |
|
318 retd = cosh(argd); |
|
319 break; |
|
320 |
|
321 case MF_ERF: |
|
322 retd = erf(argd); |
|
323 break; |
|
324 |
|
325 case MF_ERFC: |
|
326 retd = erfc(argd); |
|
327 break; |
|
328 |
|
329 case MF_EXP: |
|
330 retd = exp(argd); |
|
331 break; |
|
332 |
|
333 case MF_EXPM1: |
|
334 retd = expm1(argd); |
|
335 break; |
|
336 |
|
337 case MF_FABS: |
|
338 retd = fabs(argd); |
|
339 break; |
|
340 |
|
341 case MF_FLOAT: |
|
342 retd = argd; |
|
343 break; |
|
344 |
|
345 case MF_FLOOR: |
|
346 retd = floor(argd); |
|
347 break; |
|
348 |
|
349 case MF_FMOD: |
|
350 retd = fmod(argd, argd2); |
|
351 break; |
|
352 |
|
353 case MF_GAMMA: |
|
354 retd = gamma(argd); |
|
355 break; |
|
356 |
|
357 case MF_HYPOT: |
|
358 retd = hypot(argd, argd2); |
|
359 break; |
|
360 |
|
361 case MF_ILOGB: |
|
362 ret.type = MN_INTEGER; |
|
363 ret.u.l = ilogb(argd); |
|
364 break; |
|
365 |
|
366 case MF_INT: |
|
367 ret.type = MN_INTEGER; |
|
368 ret.u.l = (zlong)argd; |
|
369 break; |
|
370 |
|
371 case MF_J0: |
|
372 retd = j0(argd); |
|
373 break; |
|
374 |
|
375 case MF_J1: |
|
376 retd = j1(argd); |
|
377 break; |
|
378 |
|
379 case MF_JN: |
|
380 retd = jn(argi, argd2); |
|
381 break; |
|
382 |
|
383 case MF_LDEXP: |
|
384 retd = ldexp(argd, argi); |
|
385 break; |
|
386 |
|
387 case MF_LGAMMA: |
|
388 retd = lgamma(argd); |
|
389 break; |
|
390 |
|
391 case MF_LOG: |
|
392 retd = log(argd); |
|
393 break; |
|
394 |
|
395 case MF_LOG10: |
|
396 retd = log10(argd); |
|
397 break; |
|
398 |
|
399 case MF_LOG1P: |
|
400 retd = log1p(argd); |
|
401 break; |
|
402 |
|
403 case MF_LOGB: |
|
404 retd = logb(argd); |
|
405 break; |
|
406 |
|
407 case MF_NEXTAFTER: |
|
408 retd = nextafter(argd, argd2); |
|
409 break; |
|
410 |
|
411 case MF_RINT: |
|
412 retd = rint(argd); |
|
413 break; |
|
414 |
|
415 case MF_SCALB: |
|
416 retd = scalb(argd, argi); |
|
417 break; |
|
418 |
|
419 #ifdef HAVE_SIGNGAM |
|
420 case MF_SIGNGAM: |
|
421 ret.type = MN_INTEGER; |
|
422 ret.u.l = signgam; |
|
423 break; |
|
424 #endif |
|
425 |
|
426 case MF_SIN: |
|
427 retd = sin(argd); |
|
428 break; |
|
429 |
|
430 case MF_SINH: |
|
431 retd = sinh(argd); |
|
432 break; |
|
433 |
|
434 case MF_SQRT: |
|
435 retd = sqrt(argd); |
|
436 break; |
|
437 |
|
438 case MF_TAN: |
|
439 retd = tan(argd); |
|
440 break; |
|
441 |
|
442 case MF_TANH: |
|
443 retd = tanh(argd); |
|
444 break; |
|
445 |
|
446 case MF_Y0: |
|
447 retd = y0(argd); |
|
448 break; |
|
449 |
|
450 case MF_Y1: |
|
451 retd = y1(argd); |
|
452 break; |
|
453 |
|
454 case MF_YN: |
|
455 retd = yn(argi, argd2); |
|
456 break; |
|
457 |
|
458 #ifdef DEBUG |
|
459 default: |
|
460 fprintf(stderr, "BUG: mathfunc type not handled: %d", id); |
|
461 break; |
|
462 #endif |
|
463 } |
|
464 |
|
465 if (!(id & TFLAG(TF_NOASS))) |
|
466 ret.u.d = retd; |
|
467 return ret; |
|
468 } |
|
469 |
|
470 /**/ |
|
471 static mnumber |
|
472 math_string(UNUSED(char *name), char *arg, int id) |
|
473 { |
|
474 mnumber ret = zero_mnumber; |
|
475 char *send; |
|
476 /* |
|
477 * Post-process the string argument, which is just passed verbatim. |
|
478 * Not clear if any other functions that use math_string() will |
|
479 * want this, but assume so for now. |
|
480 */ |
|
481 while (iblank(*arg)) |
|
482 arg++; |
|
483 send = arg + strlen(arg); |
|
484 while (send > arg && iblank(send[-1])) |
|
485 send--; |
|
486 *send = '\0'; |
|
487 |
|
488 switch (id) |
|
489 { |
|
490 #ifdef HAVE_ERAND48 |
|
491 case MS_RAND48: |
|
492 { |
|
493 static unsigned short seedbuf[3]; |
|
494 static int seedbuf_init; |
|
495 unsigned short tmp_seedbuf[3], *seedbufptr; |
|
496 int do_init = 1; |
|
497 |
|
498 if (*arg) { |
|
499 /* Seed is contained in parameter named by arg */ |
|
500 char *seedstr; |
|
501 seedbufptr = tmp_seedbuf; |
|
502 if ((seedstr = getsparam(arg)) && strlen(seedstr) >= 12) { |
|
503 int i, j; |
|
504 do_init = 0; |
|
505 /* |
|
506 * Decode three sets of four hex digits corresponding |
|
507 * to each unsigned short. |
|
508 */ |
|
509 for (i = 0; i < 3 && !do_init; i++) { |
|
510 unsigned short *seedptr = seedbufptr + i; |
|
511 *seedptr = 0; |
|
512 for (j = 0; j < 4; j++) { |
|
513 if (*seedstr >= '0' && *seedstr <= '9') |
|
514 *seedptr += *seedstr - '0'; |
|
515 else if (tolower(*seedstr) >= 'a' && |
|
516 tolower(*seedstr) <= 'f') |
|
517 *seedptr += tolower(*seedstr) - 'a' + 10; |
|
518 else { |
|
519 do_init = 1; |
|
520 break; |
|
521 } |
|
522 seedstr++; |
|
523 if (j < 3) |
|
524 *seedptr *= 16; |
|
525 } |
|
526 } |
|
527 } |
|
528 else if (errflag) |
|
529 break; |
|
530 } |
|
531 else |
|
532 { |
|
533 /* Use default seed: must be initialised. */ |
|
534 seedbufptr = seedbuf; |
|
535 if (!seedbuf_init) |
|
536 seedbuf_init = 1; |
|
537 else |
|
538 do_init = 1; |
|
539 } |
|
540 if (do_init) { |
|
541 seedbufptr[0] = (unsigned short)rand(); |
|
542 seedbufptr[1] = (unsigned short)rand(); |
|
543 seedbufptr[2] = (unsigned short)rand(); |
|
544 } |
|
545 ret.type = MN_FLOAT; |
|
546 ret.u.d = 0;//erand48(seedbufptr); //KARTHIK |
|
547 |
|
548 if (*arg) |
|
549 { |
|
550 char outbuf[13]; |
|
551 sprintf(outbuf, "%04x%04x%04x", (int)seedbufptr[0], |
|
552 (int)seedbufptr[1], (int)seedbufptr[2]); |
|
553 setsparam(arg, ztrdup(outbuf)); |
|
554 } |
|
555 } |
|
556 break; |
|
557 #endif |
|
558 } |
|
559 |
|
560 return ret; |
|
561 } |
|
562 |
|
563 |
|
564 /**/ |
|
565 int |
|
566 setup_(UNUSED(Module m)) |
|
567 { |
|
568 return 0; |
|
569 } |
|
570 |
|
571 /**/ |
|
572 int |
|
573 boot_(Module m) |
|
574 { |
|
575 return !addmathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); |
|
576 } |
|
577 |
|
578 /**/ |
|
579 int |
|
580 cleanup_(Module m) |
|
581 { |
|
582 deletemathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); |
|
583 return 0; |
|
584 } |
|
585 |
|
586 /**/ |
|
587 int |
|
588 finish_(UNUSED(Module m)) |
|
589 { |
|
590 return 0; |
|
591 } |