lpmoo-1.2/etc/
lpmoo-1.2/mudlib/
lpmoo-1.2/mudlib/etc/
lpmoo-1.2/mudlib/include/
lpmoo-1.2/mudlib/include/moo/
lpmoo-1.2/mudlib/lpc/
lpmoo-1.2/mudlib/std/auto/
lpmoo-1.2/mudlib/std/bfuns/
/*
 * NAME:	math.c
 * DESCRIPTION:	mathematics library
 */

# include <math.h>
# include <dgd/float.h>

/*
 * NAME:	abs()
 * DESCRIPTION:	return integer absolute value
 */
static
int abs(int num)
{ return (num < 0 ? -num : num); }

/*
 * NAME:	sqrt()
 * DESCRIPTION:	return floating point square root
 */
static
float sqrt(float x)
{
  mixed *split;
  float f, y, z;
  int n;

  if (x == 0.0)
    return 0.0;

  if (x < 0.0)
    error("Square root of negative number");

  split = frexp(x);
  f = split[0];
  n = split[1];

  y = 0.4173102246 + 0.5901604053 * f;
  z = y + f / y;
  y = 0.25 * z + f / z;
  z = 0.5 * (y + f / y);
  if (n & 1)
    {
      ++n;
      z *= SQRT05;
    }

  return ldexp(z, n / 2);
}

/*
 * NAME:	sin_cos()
 * DESCRIPTION:	compute sine or cosine
 */
private
float sin_cos(float x, float y, float sgn)
{
  float f, g, r, xn, *tmp;

  tmp = modf(ONEOPI * y + 0.5);
  xn  = tmp[1];

  tmp = modf(0.5 * xn);
  if ((int) (2.0 * tmp[0]) & 1 == 1)
    sgn = -sgn;

  r = (x < 0.0 ? -x : x);
  if (r != y)
    xn -= 0.5;
  f = sgn * ((r - xn * 3.1416015625) - xn * -8.90891020676153736e-6);

  if (f < ROOTEPS && f > -ROOTEPS)
    return f;

  g = f * f;
  r = (((((((0.272047909578888462e-14 * g +
	     -0.764291780689104677e-12) * g +
	    0.160589364903715891e-9) * g +
	   -0.250521067982745845e-7) * g +
	  0.275573192101527561e-5) * g +
	 -0.198412698412018405e-3) * g +
	0.833333333333316503e-2) * g +
       -0.166666666666666651e0) * g;

  return f + f * r;
}

/*
 * NAME:	sin()
 * DESCRIPTION:	return sine of argument
 */
static
float sin(float x)
{
  if (x < 0.0)
    return sin_cos(x, -x, -1.0);
  else
    return sin_cos(x, x, 1.0);
}

/*
 * NAME:	cos()
 * DESCRIPTION:	return cosine of argument
 */
static
float cos(float x)
{
  return sin_cos(x, fabs(x) + PIO2, 1.0);
}

/*
 * NAME:	tan_cot()
 * DESCRIPTION:	compute tangent or cotangent
 */
private
float tan_cot(float x, int flag)
{
  float f, g, p, q, *tmp;
  int n;

  f = x < 0.0 ? -x : x;
  if (x < 0.0)
    tmp = modf(x * ONEOPIO2 - 0.5);
  else
    tmp = modf(x * ONEOPIO2 + 0.5);
  g = tmp[1];

  tmp = modf(0.5 * g);
  p   = tmp[1];
  n   = (int) (2.0 * tmp[0]);

  f = (x - g * 1.57080078125) - g * -4.45445510338076868e-6;
  if (f < ROOTEPS && f > -ROOTEPS)
    {
      p = f;
      q = 1.0;
    }
  else
    {
      g = f * f;
      p = ((-0.178617073422544267e-4 * g +
	    0.342488782358905900e-2) * g +
	   -0.133383500064219607e0) * g * f + f;
      q = (((0.498194339937865123e-6 * g +
	     -0.311815319070100273e-3) * g +
	    0.256638322894401129e-1) * g +
	   -0.466716833397552942e0) * g + 1.0;
    }

  if (flag == 0)
    {
      if (n == 0)
	return p / q;
      else
	return -q / p;
    }
  else
    {
      if (n == 0)
	return q / p;
      else
	return -p / q;
    }
}

/*
 * NAME:	tan()
 * DESCRIPTION:	compute tangent of argument
 */
static
float tan(float x)
{
  return tan_cot(x, 0);
}

/*
 * NAME:	cotan()
 * DESCRIPTION:	compute cotangent of argument
 */
static
float cotan(float x)
{
  if (x < (1.0 / FLT_MAX) && x > -(1.0 / FLT_MAX))
    return x < 0.0 ? -FLT_MAX : FLT_MAX;

  return tan_cot(x, 1);
}

/*
 * NAME:	copysign()
 * DESCRIPTION:	return first argument with sign of second
 */
static
float copysign(float x, float y)
{
  return ((x < 0.0 && y < 0.0) || (x > 0.0 && y > 0.0)) ? x : -x;
}

# define small	1.0e-9
# define big	1.0e+18

/*
 * NAME:	atan2()
 * DESCRIPTION:	return arctangent of y/x
 */
static
float atan2(float y, float x)
{
  float t, z, signy, signx, hi, lo;
  int k, m;

  signy = copysign(1.0, y);
  signx = copysign(1.0, x);

  if (x == 1.0)
    t = y = copysign(y, 1.0);
  else
    {
      if (y == 0.0)
	return (signx == 1.0) ? y : copysign(PI, signy);

      if (x == 0.0)
	return copysign(PIO2, signy);

      x = copysign(x, 1.0);
      y = copysign(y, 1.0);

      if ((m = (k = frexp(y)[1]) - frexp(x)[1]) > 60)
	t = big + big;
      else if (m < -80)
	t = y / x;
      else
	{
	  t = y / x;
	  y = ldexp(y, -k);
	  x = ldexp(x, -k);
	}
    }

  /* begin argument reduction */

  if (t < 2.4375)
    {
      /* truncate 4(t+1/16) to integer for branching */

      k = (int) (4.0 * (t + 0.0625));
      switch (k)
	{
	case 0:  /* t is in [0, 7/16] */
	case 1:
	  if (t < small)
	    return copysign((signx > 0.0) ? t : PI - t, signy);
	  hi = lo = 0.0;
	  break;

	case 2:  /* t is in [7/16, 11/16] */
	  hi = 4.6364760900080609352e-1;
	  lo = 4.6249969567426939759e-18;
	  z = x + x;
	  t = ((y + y) - x) / (z + y);
	  break;

	case 3:  /* t is in [11/16, 19/16] */
	case 4:
	  hi = PIO4;
	  lo = 0.0;
	  t = (y - x) / (x + y);
	  break;

	default:  /* t is in [19/16, 39/16] */
	  hi = 9.8279372324732905408e-1;
	  lo = -2.4407677060164810007e-17;
	  z = y - x;
	  y = y + y + y;
	  t = x + x;
	  t = ((z + z) - x) / (t + y);
	  break;
	}
    }
  else  /* t >= 2.4375 */
    {
      hi = PIO2;
      lo = 0.0;

      if (t <= big)  /* t is in [2.4375, big] */
	t = -x / y;
      else  /* t is in [big, INF] */
	t = 0.0;
    }

  /* compute atan(t) for t in [-0.4375, 0.4375] */
  z = t * t;
  z = t * (z * (3.3333333333333942106e-1 + z *
		(-1.9999999999979536924e-1 + z *
		 (1.4285714278004377209e-1 + z *
		  (-1.1111110579344973814e-1 + z *
		   (9.0908906105474668324e-2 + z *
		    (-7.6919217767468239799e-2 + z *
		     (6.6614695906082474486e-2 + z *
		      (-5.8358371008508623523e-2 + z *
		       (4.9850617156082015213e-2 + z *
			(-3.6700606902093604877e-2 + z *
			 1.6438029044759730479e-2)))))))))));
  z = lo - z;
  z += t;
  z += hi;

  return copysign((signx > 0.0) ? z : PI - z, signy);
}

# undef small
# undef big

/*
 * NAME:	atan()
 * DESCRIPTION:	return arctangent of argument
 */
static
float atan(float x)
{
  return atan2(x, 1.0);
}

/* The following functions were borrowed from The Pattern (author: Dworkin) */

private
float poly(float x, float *coef)
{
  int i;
  float y;

  for (i = sizeof(coef) - 1, y = coef[i]; i > 0; )
    y = y * x + coef[--i];

  return y;
}

private
float poly2(float x, float *coef1, float *coef2)
{
  int i;
  float y, z;

  for (i = sizeof(coef1) - 1, y = coef1[i]; i > 0; )
    y = y * x + coef1[--i];

  for (i = sizeof(coef2) - 1, z = x + coef2[i]; i > 0; )
    z = z * x + coef2[--i];

  return y / z;
}

static
float exp(float x)
{
  float n, xx, px;

  if (x > MAXLOG)
    error("Result too large");

  if (x < MINLOG)
    return 0.0;

  /* Express e**x = e**g 2**n
   *   = e**g e**( n loge(2) )
   *   = e**( g + n loge(2) )
   */
  n = floor(x * LOG2E + 0.5); /* floor() truncates toward -infinity. */
  x -= n * 6.9335937500000000000E-1;
  x += n * 2.1219444005469058277E-4;

  /* rational approximation for exponential
   * of the fractional part:
   * e**x - 1  =  2x P(x**2)/(Q(x**2) - P(x**2))
   */
  xx = x * x;
  px = x * poly(xx, ({ 1.00000000000000000000E0,
		       3.02996887658430129200E-2,
		       1.26183092834458542160E-4 }) );
  x = px / (poly(xx, ({ 2.00000000000000000005E0,
			2.27266044198352679519E-1,
			2.52453653553222894311E-3,
			3.00227947279887615146E-6 }) ) - px);

  return ldexp(ldexp(x, 1) + 1.0, (int) n);
}

/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
 * 1/sqrt(2) <= x < sqrt(2)
 */
# ifdef UNK
static double P[] = {
    4.58482948458143443514E-5,
    4.98531067254050724270E-1,
    6.56312093769992875930E0,
    2.97877425097986925891E1,
    6.06127134467767258030E1,
    5.67349287391754285487E1,
    1.98892446572874072159E1
};
static double Q[] = {
    /* 1.00000000000000000000E0, */
    1.50314182634250003249E1,
    8.27410449222435217021E1,
    2.20664384982121929218E2,
    3.07254189979530058263E2,
    2.14955586696422947765E2,
    5.96677339718622216300E1
};
# endif

/* Coefficients for log(x) = z + z**3 P(z)/Q(z),
 * where z = 2(x-1)/(x+1)
 * 1/sqrt(2) <= x < sqrt(2)
 */

# ifdef UNK
static double R[3] = {
    -7.89580278884799154124E-1,
    1.63866645699558079767E1,
    -6.41409952958715622951E1,
};
static double S[3] = {
    /* 1.00000000000000000000E0,*/
    -3.56722798256324312549E1,
    3.12093766372244180303E2,
    -7.69691943550460008604E2,
};
# endif

static
float log(float x)
{
  mixed *fe;
  int e;
  float y, z;

  /* Test for domain */
  if (x <= 0.0)
    {
      if (x == 0.0)
	error("Result too large");
      else
	error("Math argument");
    }

  /* separate mantissa from exponent */
  fe = frexp(x);
  x = fe[0];
  e = fe[1];

  if (e > 2 || e < -2)
    {
      /* logarithm using log(x) = z + z**3 P(z)/Q(z),
       * where z = 2(x-1)/x+1)
       */
      if (x < SQRTH)
	{
	  /* 2( 2x-1 )/( 2x+1 ) */
	  e -= 1;
	  z = x - 0.5;
	  y = ldexp(z, -1) + 0.5;
	}
      else
	{
	  /*  2 (x-1)/(x+1)   */
	  z = x - 0.5;
	  z -= 0.5;
	  y = ldexp(x, -1) + 0.5;
	}
      x = z / y;

      /* rational form */
      z = x * x;
      z = x + x * (z * poly2(z,
			     ({ -6.41409952958715622951E1,
				 1.63866645699558079767E1,
				-7.89580278884799154124E-1 }),
			     ({ -7.69691943550460008604E2,
				 3.12093766372244180303E2,
				-3.56722798256324312549E1 }) ));
    }
  else
    {
      /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
      if (x < SQRTH)
	{
	  e -= 1;
	  x = ldexp(x, 1) - 1.0; /*  2x - 1  */
	}
      else
	x = x - 1.0;

      /* rational form */
      z = x * x;
      y = x * (z * poly2(x,
			 ({ 1.98892446572874072159E1,
			    5.67349287391754285487E1,
			    6.06127134467767258030E1,
			    2.97877425097986925891E1,
			    6.56312093769992875930E0,
			    4.98531067254050724270E-1,
			    4.58482948458143443514E-5 }),
			 ({ 5.96677339718622216300E1,
			    2.14955586696422947765E2,
			    3.07254189979530058263E2,
			    2.20664384982121929218E2,
			    8.27410449222435217021E1,
			    1.50314182634250003249E1 }) ));
      y = y - ldexp(z, -1);   /*  y - 0.5 * z  */
      z = x + y;
    }

  /* recombine with exponent term */
  if (e != 0)
    {
      y = (float) e;
      z = z - y * 2.121944400546905827679e-4;
      z = z + y * 0.693359375;
    }

  return z;
}

/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
 * 1/sqrt(2) <= x < sqrt(2)
 */
# ifdef UNK
static double P[] = {
    4.58482948458143443514E-5,
    4.98531067254050724270E-1,
    6.56312093769992875930E0,
    2.97877425097986925891E1,
    6.06127134467767258030E1,
    5.67349287391754285487E1,
    1.98892446572874072159E1
};
static double Q[] = {
    /* 1.00000000000000000000E0, */
    1.50314182634250003249E1,
    8.27410449222435217021E1,
    2.20664384982121929218E2,
    3.07254189979530058263E2,
    2.14955586696422947765E2,
    5.96677339718622216300E1
};
# endif

static
float log10(float x)
{
  mixed *fe;
  int e;
  float w, y, z;

  /* Test for domain */
  if (x <= 0.0)
    {
      if (x == 0.0)
	error("Result too large");
      else
	error("Math argument");
    }

  /* separate mantissa from exponent */
  fe = frexp(x);
  x = fe[0];
  e = fe[1];

  /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
  if (x < SQRTH)
    {
      e -= 1;
      x = ldexp(x, 1) - 1.0; /*  2x - 1  */
    }
  else
    x = x - 1.0;

  /* rational form */
  z = x * x;
  y = x * (z * poly2(x,
		     ({ 1.98892446572874072159E1,
			5.67349287391754285487E1,
			6.06127134467767258030E1,
			2.97877425097986925891E1,
			6.56312093769992875930E0,
			4.98531067254050724270E-1,
		        4.58482948458143443514E-5 }),
		     ({ 5.96677339718622216300E1,
			2.14955586696422947765E2,
			3.07254189979530058263E2,
			2.20664384982121929218E2,
			8.27410449222435217021E1,
			1.50314182634250003249E1 }) ));
  y = y - ldexp(z, -1);   /*  y - 0.5 * x**2  */

  /* multiply log of fraction by log10(e)
   * and base 2 exponent by log10(2)
   */
  /* accumulate terms in order of size */
  z = (x + y) * 7.00731903251827651129E-4; /* L10EB */
  z += y * 4.3359375E-1; /* L10EA */
  z += x * 4.3359375E-1; /* L10EA */
  w = (float) e;
  z += w * 2.48745663981195213739E-4; /* L102B */
  z += w * 3.0078125E-1; /* L102A */

  return z;
}

# if 0
/*							sqrt.c
 *
 *	Square root
 *
 *
 *
 * SYNOPSIS:
 *
 * double x, y, sqrt();
 *
 * y = sqrt( x );
 *
 *
 *
 * DESCRIPTION:
 *
 * Returns the square root of x.
 *
 * Range reduction involves isolating the power of two of the
 * argument and using a polynomial approximation to obtain
 * a rough value for the square root.  Then Heron's iteration
 * is used three times to converge to an accurate value.
 *
 *
 *
 * ACCURACY:
 *
 *
 *                      Relative error:
 * arithmetic   domain     # trials      peak         rms
 *    DEC       0, 30        2000       2.1e-17     5.2e-18
 *    IEEE      0,1.7e308   30000       1.7e-16     6.3e-17
 *
 *
 * ERROR MESSAGES:
 *
 *   message         condition      value returned
 * sqrt domain        x < 0            0.0
 *
 */

/*
Cephes Math Library Release 2.1:  December, 1988
Copyright 1984, 1987, 1988 by Stephen L. Moshier
Direct inquiries to 30 Frost Street, Cambridge, MA 02140
*/


float sqrt(float x)
{
    float w;
    mixed *fe;
    int e;

    if (x <= 0.0) {
	if (x < 0.0) {
	    error("Domain error");
	}
	return 0.0;
    }

    w = x;
    /* separate exponent and significand */
    fe = frexp(x);
    x = fe[0];
    e = fe[1];

    /* approximate square root of number between 0.5 and 1
     * relative error of approximation = 7.47e-3
     */
    x = 4.173075996388649989089E-1 + 5.9016206709064458299663E-1 * x;

    /* adjust for odd powers of 2 */
    if (e & 1) {
	x *= 1.41421356237309504880;
    }

    /* re-insert exponent */
    x = ldexp(x, e / 2);

    /* Newton iterations: */
    x = 0.5 * (x + w / x);
    x = 0.5 * (x + w / x);
    x = 0.5 * (x + w / x);

    return x;
}
# endif