openenvutils/commandshell/shell/src/modules/mathfunc.c
changeset 0 2e3d3ce01487
child 4 0fdb7f6b0309
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/openenvutils/commandshell/shell/src/modules/mathfunc.c	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,591 @@
+// mathfunc.c - basic mathematical functions for use in math evaluations
+//
+// © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
+//
+/*
+ * 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>
+
+#ifdef __SYMBIAN32__
+#ifdef __WINSCW__
+#pragma warn_unusedarg off
+#endif//__WINSCW__
+#endif//__SYMBIAN32__
+
+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_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,
+#ifdef HAVE_SIGNGAM
+MF_SIGNGAM,
+#endif
+MF_SIN,
+MF_SINH,
+MF_SQRT,
+MF_TAN,
+MF_TANH,
+MF_Y0,
+MF_Y1,
+MF_YN
+};
+
+/* also functions taking a string argument */
+
+enum {
+MS_RAND48
+};
+
+/*
+ * 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[] = {
+  /* Functions taking string arguments */
+#ifdef HAVE_ERAND48
+  /* here to avoid comma hassle */
+  STRMATHFUNC("rand48", math_string, MS_RAND48),
+#endif
+
+  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("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)),
+#ifdef HAVE_SIGNGAM
+  NUMMATHFUNC("signgam", math_func, 0, 0, MF_SIGNGAM | TFLAG(TF_NOASS)),
+#endif
+  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_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;
+
+#ifdef HAVE_SIGNGAM
+  case MF_SIGNGAM:
+      ret.type = MN_INTEGER;
+      ret.u.l = signgam; 
+      break;
+#endif
+
+  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;
+}
+
+/**/
+static mnumber
+math_string(UNUSED(char *name), char *arg, int id)
+{
+    mnumber ret = zero_mnumber;
+    char *send;
+    /*
+     * Post-process the string argument, which is just passed verbatim.
+     * Not clear if any other functions that use math_string() will
+     * want this, but assume so for now.
+     */
+    while (iblank(*arg))
+	arg++;
+    send = arg + strlen(arg);
+    while (send > arg && iblank(send[-1]))
+	send--;
+    *send = '\0';
+
+    switch (id)
+    {
+#ifdef HAVE_ERAND48
+    case MS_RAND48:
+	{
+	    static unsigned short seedbuf[3];
+	    static int seedbuf_init;
+	    unsigned short tmp_seedbuf[3], *seedbufptr;
+	    int do_init = 1;
+
+	    if (*arg) {
+		/* Seed is contained in parameter named by arg */
+		char *seedstr;
+		seedbufptr = tmp_seedbuf;
+		if ((seedstr = getsparam(arg)) && strlen(seedstr) >= 12) {
+		    int i, j;
+		    do_init = 0;
+		    /*
+		     * Decode three sets of four hex digits corresponding
+		     * to each unsigned short.
+		     */
+		    for (i = 0; i < 3 && !do_init; i++) {
+			unsigned short *seedptr = seedbufptr + i;
+			*seedptr = 0;
+			for (j = 0; j < 4; j++) {
+			    if (*seedstr >= '0' && *seedstr <= '9')
+				*seedptr += *seedstr - '0';
+			    else if (tolower(*seedstr) >= 'a' &&
+				     tolower(*seedstr) <= 'f')
+				*seedptr += tolower(*seedstr) - 'a' + 10;
+			    else {
+				do_init = 1;
+				break;
+			    }
+			    seedstr++;
+			    if (j < 3)
+				*seedptr *= 16;
+			}
+		    }
+		}
+		else if (errflag)
+		    break;
+	    }
+	    else
+	    {
+		/* Use default seed: must be initialised. */
+		seedbufptr = seedbuf;
+		if (!seedbuf_init)
+		    seedbuf_init = 1;
+		else
+		    do_init = 1;
+	    }
+	    if (do_init) {
+		seedbufptr[0] = (unsigned short)rand();
+		seedbufptr[1] = (unsigned short)rand();
+		seedbufptr[2] = (unsigned short)rand();
+	    }
+	    ret.type = MN_FLOAT;
+	    ret.u.d = 0;//erand48(seedbufptr); //KARTHIK
+
+	    if (*arg)
+	    {
+		char outbuf[13];
+		sprintf(outbuf, "%04x%04x%04x", (int)seedbufptr[0],
+			(int)seedbufptr[1], (int)seedbufptr[2]);
+		setsparam(arg, ztrdup(outbuf));
+	    }
+	}
+	break;
+#endif
+    }
+
+    return ret;
+}
+
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+    return 0;
+}
+
+/**/
+int
+boot_(Module m)
+{
+    return !addmathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab));
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+    deletemathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab));
+    return 0;
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+    return 0;
+}