diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/mathfunc.c | 482 | ||||
-rw-r--r-- | Src/Modules/mathfunc.mdd | 3 | ||||
-rw-r--r-- | Src/math.c | 52 |
3 files changed, 513 insertions, 24 deletions
diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c new file mode 100644 index 000000000..770894ce8 --- /dev/null +++ b/Src/Modules/mathfunc.c @@ -0,0 +1,482 @@ +/* + * mathfunc.c - basic mathematical functions for use in math evaluations + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1999 Peter Stephenson + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Peter Stephenson or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Peter Stephenson and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Peter Stephenson and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Peter Stephenson and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "mathfunc.mdh" +#include "mathfunc.pro" + +#include <math.h> + +enum { +MF_ABS, +MF_ACOS, +MF_ACOSH, +MF_ASIN, +MF_ASINH, +MF_ATAN, +MF_ATANH, +MF_CBRT, +MF_CEIL, +MF_COPYSIGN, +MF_COS, +MF_COSH, +MF_DREM, +MF_ERF, +MF_ERFC, +MF_EXP, +MF_EXPM1, +MF_FABS, +MF_FLOAT, +MF_FLOOR, +MF_FMOD, +MF_GAMMA, +MF_HYPOT, +MF_ILOGB, +MF_INT, +MF_J0, +MF_J1, +MF_JN, +MF_LDEXP, +MF_LGAMMA, +MF_LOG, +MF_LOG10, +MF_LOG1P, +MF_LOGB, +MF_NEXTAFTER, +MF_RINT, +MF_SCALB, +MF_SIGNGAM, +MF_SIN, +MF_SINH, +MF_SQRT, +MF_TAN, +MF_TANH, +MF_Y0, +MF_Y1, +MF_YN, +}; + +/* + * also to do, but differently argument or returned: abs (no type + * conversion), atan2. + */ + +/* Flags for bounds. Note these must start at 1, not 0. */ + +enum { + BF_POS = 1, /* must be positive */ + BF_NONNEG = 2, /* must be non-negative */ + BF_FRAC = 3, /* must be -1 <= x <= 1 */ + BF_GE1 = 4, /* must be >= 1 */ + BF_FRACO = 5, /* must be in open range -1 < x < 1 */ + BF_INTPOS = 6, /* must be non-integer or positive */ + BF_GTRM1 = 7, /* must be > -1 */ + BF_NONZ = 8, /* must be nonzero */ + BF_POS2 = 9 /* second argument must be positive */ +}; + +#define BFLAG(x) ((x) << 8) + +/* + * Flags for type of function: unlike the above, these must + * be individually bit-testable. + */ + +enum { + TF_NOCONV = 1, /* don't convert to float */ + TF_INT1 = 2, /* first argument is integer */ + TF_INT2 = 4, /* second argument is integer */ + TF_NOASS = 8 /* don't assign result as double */ +}; + +#define TFLAG(x) ((x) << 16) + + +static struct mathfunc mftab[] = { + NUMMATHFUNC("abs", math_func, 1, 1, MF_ABS | BFLAG(BF_FRAC) | + TFLAG(TF_NOCONV|TF_NOASS)), + NUMMATHFUNC("acos", math_func, 1, 1, MF_ACOS | BFLAG(BF_FRAC)), + NUMMATHFUNC("acosh", math_func, 1, 1, MF_ACOSH | BFLAG(BF_GE1)), + NUMMATHFUNC("asin", math_func, 1, 1, MF_ASIN | BFLAG(BF_FRAC)), + NUMMATHFUNC("asinh", math_func, 1, 1, MF_ASINH), + NUMMATHFUNC("atan", math_func, 1, 2, MF_ATAN), + NUMMATHFUNC("atanh", math_func, 1, 1, MF_ATANH | BFLAG(BF_FRACO)), + NUMMATHFUNC("cbrt", math_func, 1, 1, MF_CBRT), + NUMMATHFUNC("ceil", math_func, 1, 1, MF_CEIL), + NUMMATHFUNC("copysign", math_func, 2, 2, MF_COPYSIGN), + NUMMATHFUNC("cos", math_func, 1, 1, MF_COS), + NUMMATHFUNC("cosh", math_func, 1, 1, MF_COSH), + NUMMATHFUNC("drem", math_func, 2, 2, MF_DREM), + NUMMATHFUNC("erf", math_func, 1, 1, MF_ERF), + NUMMATHFUNC("erfc", math_func, 1, 1, MF_ERFC), + NUMMATHFUNC("exp", math_func, 1, 1, MF_EXP), + NUMMATHFUNC("expm1", math_func, 1, 1, MF_EXPM1), + NUMMATHFUNC("fabs", math_func, 1, 1, MF_FABS), + NUMMATHFUNC("float", math_func, 1, 1, MF_FLOAT), + NUMMATHFUNC("floor", math_func, 1, 1, MF_FLOOR), + NUMMATHFUNC("fmod", math_func, 2, 2, MF_FMOD), + NUMMATHFUNC("gamma", math_func, 1, 1, MF_GAMMA | BFLAG(BF_INTPOS)), + NUMMATHFUNC("hypot", math_func, 2, 2, MF_HYPOT), + NUMMATHFUNC("ilogb", math_func, 1, 1, MF_ILOGB | BFLAG(BF_NONZ) | + TFLAG(TF_NOASS)), + NUMMATHFUNC("int", math_func, 1, 1, MF_INT | TFLAG(TF_NOASS)), + NUMMATHFUNC("j0", math_func, 1, 1, MF_J0), + NUMMATHFUNC("j1", math_func, 1, 1, MF_J1), + NUMMATHFUNC("jn", math_func, 2, 2, MF_JN | TFLAG(TF_INT1)), + NUMMATHFUNC("ldexp", math_func, 2, 2, MF_LDEXP | TFLAG(TF_INT2)), + NUMMATHFUNC("lgamma", math_func, 1, 1, MF_LGAMMA | BFLAG(BF_INTPOS)), + NUMMATHFUNC("log", math_func, 1, 1, MF_LOG | BFLAG(BF_POS)), + NUMMATHFUNC("log10", math_func, 1, 1, MF_LOG10 | BFLAG(BF_POS)), + NUMMATHFUNC("log1p", math_func, 1, 1, MF_LOG1P | BFLAG(BF_GTRM1)), + NUMMATHFUNC("logb", math_func, 1, 1, MF_LOGB | BFLAG(BF_NONZ)), + NUMMATHFUNC("nextafter", math_func, 2, 2, MF_NEXTAFTER), + NUMMATHFUNC("rint", math_func, 1, 1, MF_RINT), + NUMMATHFUNC("scalb", math_func, 2, 2, MF_SCALB | TFLAG(TF_INT2)), + NUMMATHFUNC("signgam", math_func, 0, 0, MF_SIGNGAM | TFLAG(TF_NOASS)), + NUMMATHFUNC("sin", math_func, 1, 1, MF_SIN), + NUMMATHFUNC("sinh", math_func, 1, 1, MF_SINH), + NUMMATHFUNC("sqrt", math_func, 1, 1, MF_SQRT | BFLAG(BF_NONNEG)), + NUMMATHFUNC("tan", math_func, 1, 1, MF_TAN), + NUMMATHFUNC("tanh", math_func, 1, 1, MF_TANH), + NUMMATHFUNC("y0", math_func, 1, 1, MF_Y0 | BFLAG(BF_POS)), + NUMMATHFUNC("y1", math_func, 1, 1, MF_Y1 | BFLAG(BF_POS)), + NUMMATHFUNC("yn", math_func, 2, 2, MF_YN | BFLAG(BF_POS2) | TFLAG(TF_INT1)) +}; + +/**/ +static mnumber +math_func(char *name, int argc, mnumber *argv, int id) +{ + mnumber ret; + double argd = 0, argd2 = 0, retd = 0; + int argi = 0; + + if (argc && !(id & TFLAG(TF_NOCONV))) { + if (id & TFLAG(TF_INT1)) + argi = (argv->type == MN_FLOAT) ? (zlong)argv->u.d : argv->u.l; + else + argd = (argv->type == MN_INTEGER) ? (double)argv->u.l : argv->u.d; + if (argc > 1) { + if (id & TFLAG(TF_INT2)) + argi = (argv[1].type == MN_FLOAT) ? (zlong)argv[1].u.d : + argv[1].u.l; + else + argd2 = (argv[1].type == MN_INTEGER) ? (double)argv[1].u.l : + argv[1].u.d; + } + } + + ret.type = MN_FLOAT; + ret.u.d = 0; + + if (errflag) + return ret; + + if (id & 0xff00) { + int rtst = 0; + + switch ((id >> 8) & 0xff) { + case BF_POS: + rtst = (argd <= 0.0); + break; + + case BF_NONNEG: + rtst = (argd < 0.0); + break; + + case BF_FRAC: + rtst = (fabs(argd) > 1.0); + break; + + case BF_GE1: + rtst = (argd < 1.0); + break; + + case BF_FRACO: + rtst = (fabs(argd) >= 1.0); + break; + + case BF_INTPOS: + rtst = (argd <= 0 && (double)(zlong)argd == argd); + break; + + case BF_GTRM1: + rtst = (argd <= -1); + break; + + case BF_POS2: + rtst = (argd2 <= 0.0); + break; + } + + if (rtst) { + zerr("math: argument to %s out of range", name, 0); + return ret; + } + } + + switch (id & 0xff) { + case MF_ABS: + ret.type = argv->type; + if (argv->type == MN_INTEGER) + ret.u.l = (argv->u.l < 0) ? - argv->u.l : argv->u.l; + else + ret.u.d = fabs(argv->u.d); + break; + + case MF_ACOS: + retd = acos(argd); + break; + + case MF_ACOSH: + retd = acosh(argd); + break; + + case MF_ASIN: + retd = asin(argd); + break; + + case MF_ASINH: + retd = asinh(argd); + break; + + case MF_ATAN: + if (argc == 2) + retd = atan2(argd, argd2); + else + retd = atan(argd); + break; + + case MF_ATANH: + retd = atanh(argd); + break; + + case MF_CBRT: + retd = cbrt(argd); + break; + + case MF_CEIL: + retd = ceil(argd); + break; + + case MF_COPYSIGN: + retd = copysign(argd, argd2); + break; + + case MF_COS: + retd = cos(argd); + break; + + case MF_COSH: + retd = cosh(argd); + break; + + case MF_DREM: + retd = drem(argd, argd2); + break; + + case MF_ERF: + retd = erf(argd); + break; + + case MF_ERFC: + retd = erfc(argd); + break; + + case MF_EXP: + retd = exp(argd); + break; + + case MF_EXPM1: + retd = expm1(argd); + break; + + case MF_FABS: + retd = fabs(argd); + break; + + case MF_FLOAT: + retd = argd; + break; + + case MF_FLOOR: + retd = floor(argd); + break; + + case MF_FMOD: + retd = fmod(argd, argd2); + break; + + case MF_GAMMA: + retd = gamma(argd); + break; + + case MF_HYPOT: + retd = hypot(argd, argd2); + break; + + case MF_ILOGB: + ret.type = MN_INTEGER; + ret.u.l = ilogb(argd); + break; + + case MF_INT: + ret.type = MN_INTEGER; + ret.u.l = (zlong)argd; + break; + + case MF_J0: + retd = j0(argd); + break; + + case MF_J1: + retd = j1(argd); + break; + + case MF_JN: + retd = jn(argi, argd2); + break; + + case MF_LDEXP: + retd = ldexp(argd, argi); + break; + + case MF_LGAMMA: + retd = lgamma(argd); + break; + + case MF_LOG: + retd = log(argd); + break; + + case MF_LOG10: + retd = log10(argd); + break; + + case MF_LOG1P: + retd = log1p(argd); + break; + + case MF_LOGB: + retd = logb(argd); + break; + + case MF_NEXTAFTER: + retd = nextafter(argd, argd2); + break; + + case MF_RINT: + retd = rint(argd); + break; + + case MF_SCALB: + retd = scalb(argd, argi); + break; + + case MF_SIGNGAM: + ret.type = MN_INTEGER; + ret.u.l = signgam; + break; + + case MF_SIN: + retd = sin(argd); + break; + + case MF_SINH: + retd = sinh(argd); + break; + + case MF_SQRT: + retd = sqrt(argd); + break; + + case MF_TAN: + retd = tan(argd); + break; + + case MF_TANH: + retd = tanh(argd); + break; + + case MF_Y0: + retd = y0(argd); + break; + + case MF_Y1: + retd = y1(argd); + break; + + case MF_YN: + retd = yn(argi, argd2); + break; + +#ifdef DEBUG + default: + fprintf(stderr, "BUG: mathfunc type not handled: %d", id); + break; +#endif + } + + if (!(id & TFLAG(TF_NOASS))) + ret.u.d = retd; + + return ret; +} + +/**/ +int +setup_mathfunc(Module m) +{ + return 0; +} + +/**/ +int +boot_mathfunc(Module m) +{ + return !addmathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); +} + +#ifdef MODULE + +/**/ +int +cleanup_mathfunc(Module m) +{ + deletemathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); + return 0; +} + +/**/ +int +finish_mathfunc(Module m) +{ + return 0; +} + +#endif diff --git a/Src/Modules/mathfunc.mdd b/Src/Modules/mathfunc.mdd new file mode 100644 index 000000000..33a861f77 --- /dev/null +++ b/Src/Modules/mathfunc.mdd @@ -0,0 +1,3 @@ +autobins="mathfunc" + +objects="mathfunc.o" diff --git a/Src/math.c b/Src/math.c index 836e0c671..9edfeb651 100644 --- a/Src/math.c +++ b/Src/math.c @@ -161,7 +161,7 @@ static int prec[TOKCOUNT] = 0, 16, 0 }; -#define TOPPREC 16 +#define TOPPREC 17 #define ARGPREC (TOPPREC-1) static int type[TOKCOUNT] = @@ -498,31 +498,35 @@ callmathfunc(char *o) mnumber *argv = NULL, *q; LinkList l = newlinklist(); LinkNode node; - char *p; - - if (*a) { - for (p = a; *a; a++) { - if (*a == '\\' && a[1]) - a++; - else if (*a == ',') { - *a = '\0'; - addlinknode(l, p); - argc++; - p = a + 1; - } + + while (iblank(*a)) + a++; + while (*a) { + if (*a) { + argc++; + q = (mnumber *)zhalloc(sizeof(mnumber)); + *q = mathevall(a, ARGPREC, &a); + addlinknode(l, q); + if (errflag || mtok != COMMA) + break; + a++; } - addlinknode(l, p); - argc++; } - if (argc >= f->minargs && (f->maxargs < 0 || argc <= f->maxargs)) { - if (argc) { - q = argv = (mnumber *) zhalloc(argc * sizeof(mnumber)); - for (node = firstnode(l); node; incnode(node)) - *q++ = matheval((char *) getdata(node)); - } - return f->nfunc(n, argc, argv, f->funcid); - } else - zerr("wrong number of argument: %s", o, 0); + if (*a && !errflag) + zerr("bad math expression: illegal character: %c", + NULL, *a); + if (!errflag) { + if (argc >= f->minargs && (f->maxargs < 0 || + argc <= f->maxargs)) { + if (argc) { + q = argv = (mnumber *)zhalloc(argc * sizeof(mnumber)); + for (node = firstnode(l); node; incnode(node)) + *q++ = *(mnumber *)getdata(node); + } + return f->nfunc(n, argc, argv, f->funcid); + } else + zerr("wrong number of arguments: %s", o, 0); + } } } else zerr("unknown function: %s", n, 0); |