/* sin, cos, etc, for S-Lang */
/* 

   Copyright (C) 1993 John E. Davis (davis@amy.tch.harvard.edu)
   All rights reserved.

   This file is part of S-Lang.

   S-Lang is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY.  No author or distributor accepts responsibility to
   anyone for the consequences of using it or for whether it serves any
   particular purpose or works at all, unless he says so in writing.
   Refer to the S-Lang General Public License for full details.

   Everyone is granted permission to copy, modify and redistribute
   S-Lang, but only under the conditions described in the S-Lang General
   Public License.  A copy of this license is supposed to have been given
   to you along with S-Lang so you can know your rights and
   responsibilities.  It should be in a file named COPYING.  Among other
   things, the copyright notice and this notice must be preserved on all
   copies.

*/

#include <math.h>
#include "slang.h"
#include "_slang.h"

#ifndef FLOAT_TYPE 
#define FLOAT_TYPE 5
#endif

static float dmath1(double (*f) (double))
{
   float x; 
   int dum1, dum2;
   if (SLang_pop_float(&x, &dum1, &dum2)) return(0.0);
   
   return (float) (*f)((double) x);
}

static float dmath2(double (*f) (double, double))
{
   float x, y; 
   int dum1, dum2;
   if (SLang_pop_float(&y, &dum1, &dum2)
       || SLang_pop_float(&x, &dum1, &dum2)) return (0.0);

   return (float) (*f)((double) x, (double) y);
}



float math_cos	() { return (float) dmath1(cos); }
float math_sin	() { return (float) dmath1(sin); }
float math_tan	() { return (float) dmath1(tan); }
float math_atan	() { return (float) dmath1(atan); }
float math_acos	() { return (float) dmath1(acos); }
float math_asin	() { return (float) dmath1(asin); }
float math_exp	() { return (float) dmath1(exp); }
float math_log	() { return (float) dmath1(log); }
float math_sqrt	() { return (float) dmath1(sqrt); }
float math_log10() { return (float) dmath1(log10); }
float math_pow()   { return (float) dmath2(pow); }

/* usage here is a1 a2 ... an n x ==> a1x^n + a2 x ^(n - 1) + ... + an */
float math_poly()
{
   int n;
   int dum1, dum2;
   double xn = 1.0, sum = 0.0;
   float an, x;
   
   if ((SLang_pop_float(&x, &dum1, &dum2))
       || (SLang_pop_integer(&n))) return(0.0);
   
   while (n-- > 0)
     {
	if (SLang_pop_float(&an, &dum1, &dum2)) break;
	(void) dum1; (void) dum2;
	sum += an * xn;
	xn = xn * x;
     }
   return((float) sum);
}


float Const_E =  2.7182818;
float Const_Pi = 3.1415926;

static float slmath_do_float(void)
{
   float f = 0.0;
   unsigned char type;
   SLang_Object_Type obj;
   

   if (SLang_pop(&obj)) return(f);

   type = obj.type >> 8;
   if (type == INT_TYPE)
     {
	f = (float) (int) obj.value;
     }
   else if (type == FLOAT_TYPE)
     {
	f = * (float *) &obj.value;
     }
   else if (type == STRING_TYPE)
     {
	/* Should check for parse error here but later. */
	f = atof((char *) obj.value);
	if ((obj.type & 0xFF) == LANG_DATA) FREE(obj.value);
     }
   else SLang_Error = TYPE_MISMATCH;
   return f;
}

static SLang_Name_Type slmath_table[] =
{
   MAKE_INTRINSIC(".polynom", math_poly, FLOAT_TYPE, 0),
   /* Usage:
       a b .. c n x polynom  =y
      This computes:
       ax^n + bx^(n - 1) + ... c = y  */
   MAKE_INTRINSIC(".sin", math_sin, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".cos", math_cos, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".tan", math_tan, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".atan", math_atan, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".acos", math_acos, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".asin", math_asin, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".exp", math_exp, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".log", math_log, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".sqrt", math_sqrt, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".log10", math_log10, FLOAT_TYPE, 0),
   MAKE_INTRINSIC(".pow", math_pow, FLOAT_TYPE, 0),
   MAKE_VARIABLE(".E", &Const_E, FLOAT_TYPE, 1),
   MAKE_VARIABLE(".PI", &Const_Pi, FLOAT_TYPE, 1),
   MAKE_INTRINSIC(".float",  slmath_do_float, FLOAT_TYPE, 0),
   /* Convert from integer or string representation to floating point.  
      For example, "12.34" float returns 12.34 to stack.
      as another example, consider:
      1 2 /   ==>  0  since 1 and 2 are integers
      1 2 float / ==> 0.5 since float converts 2 to 2.0 and floating point 
      division is used.
      */
   SLANG_END_TABLE
};

int init_SLmath()
{
   return SLang_add_table(slmath_table, "_Math");
}

