/***** Autogenerated from runmath.in; changes will be overwritten *****/

#line 1 "runtimebase.in"
/*****
 * runtimebase.in
 * Andy Hammerlindl  2009/07/28
 *
 * Common declarations needed for all code-generating .in files.
 *
 *****/


#line 1 "runmath.in"
/*****
 * runmath.in
 *
 * Runtime functions for math operations.
 *
 *****/

#line 1 "runtimebase.in"
#include "stack.h"
#include "types.h"
#include "builtin.h"
#include "entry.h"
#include "errormsg.h"
#include "array.h"
#include "triple.h"
#include "callable.h"

using vm::stack;
using vm::error;
using vm::array;
using vm::callable;
using types::formal;
using types::function;
using camp::triple;

#define PRIMITIVE(name,Name,asyName) using types::prim##Name;
#include <primitives.h>
#undef PRIMITIVE

typedef double real;

void unused(void *);

namespace run {
array *copyArray(array *a);
array *copyArray2(array *a);
array *copyArray3(array *a);

double *copyArrayC(const array *a, size_t dim=0);
double *copyArray2C(const array *a, bool square=true, size_t dim2=0);

triple *copyTripleArrayC(const array *a, size_t dim=0);
triple *copyTripleArray2C(const array *a, bool square=true, size_t dim2=0);
double *copyTripleArray2Components(array *a, bool square=true, size_t dim2=0);
}

function *realRealFunction();

#define CURRENTPEN processData().currentpen

#line 12 "runmath.in"
#include "mathop.h"
#include "path.h"

using namespace camp;

typedef array realarray;
typedef array pairarray;

using types::realArray;
using types::pairArray;

using run::integeroverflow;
using vm::frame;

const char *invalidargument="invalid argument";

// Return the factorial of a non-negative integer using a lookup table.
Int factorial(Int n)
{
  static Int *table;
  static Int size=0;
  if(size == 0) {
    Int f=1;
    size=2;
    while(f <= Int_MAX/size)
      f *= (size++);
    table=new Int[size];
    table[0]=f=1;
    for(Int i=1; i < size; ++i) {
      f *= i;
      table[i]=f;
    }
  }
  if(n >= size) integeroverflow(0);
  return table[n];
}

static inline Int Round(double x) 
{
  return Int(x+((x >= 0) ? 0.5 : -0.5));
}

inline Int sgn(double x) 
{
  return (x > 0.0 ? 1 : (x < 0.0 ? -1 : 0));
}

// Autogenerated routines:



namespace run {
#line 62 "runmath.in"
// real ^(real x, Int y);
void gen_runmath0(stack *Stack)
{
  Int y=vm::pop<Int>(Stack);
  real x=vm::pop<real>(Stack);
#line 63 "runmath.in"
  {Stack->push<real>(pow(x,y)); return;}
}

#line 67 "runmath.in"
// pair ^(pair z, Int y);
void gen_runmath1(stack *Stack)
{
  Int y=vm::pop<Int>(Stack);
  pair z=vm::pop<pair>(Stack);
#line 68 "runmath.in"
  {Stack->push<pair>(pow(z,y)); return;}
}

#line 72 "runmath.in"
// Int quotient(Int x, Int y);
void gen_runmath2(stack *Stack)
{
  Int y=vm::pop<Int>(Stack);
  Int x=vm::pop<Int>(Stack);
#line 73 "runmath.in" 
  if(y == 0) dividebyzero();
  if(y == -1) {Stack->push<Int>(Negate(x)); return;}
// Implementation-independent definition of integer division: round down
  {Stack->push<Int>((x-portableMod(x,y))/y); return;}
}

#line 80 "runmath.in"
// Int abs(Int x);
void gen_runmath3(stack *Stack)
{
  Int x=vm::pop<Int>(Stack);
#line 81 "runmath.in" 
  {Stack->push<Int>(Abs(x)); return;}
}

#line 85 "runmath.in"
// Int sgn(real x);
void gen_runmath4(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 86 "runmath.in" 
  {Stack->push<Int>(sgn(x)); return;}
}

#line 90 "runmath.in"
// Int rand();
void gen_runmath5(stack *Stack)
{
#line 91 "runmath.in" 
  {Stack->push<Int>(rand()); return;}
}

#line 95 "runmath.in"
// void srand(Int seed);
void gen_runmath6(stack *Stack)
{
  Int seed=vm::pop<Int>(Stack);
#line 96 "runmath.in" 
  srand(intcast(seed));
}

// a random number uniformly distributed in the interval [0,1]
#line 101 "runmath.in"
// real unitrand();
void gen_runmath7(stack *Stack)
{
#line 102 "runmath.in"                         
  {Stack->push<real>(((real) rand())/RAND_MAX); return;}
}

#line 106 "runmath.in"
// Int ceil(real x);
void gen_runmath8(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 107 "runmath.in" 
  {Stack->push<Int>(Intcast(ceil(x))); return;}
}

#line 111 "runmath.in"
// Int floor(real x);
void gen_runmath9(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 112 "runmath.in" 
  {Stack->push<Int>(Intcast(floor(x))); return;}
}

#line 116 "runmath.in"
// Int round(real x);
void gen_runmath10(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 117 "runmath.in" 
  if(validInt(x)) {Stack->push<Int>(Round(x)); return;}
  integeroverflow(0);
}

#line 122 "runmath.in"
// Int Ceil(real x);
void gen_runmath11(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 123 "runmath.in" 
  {Stack->push<Int>(Ceil(x)); return;}
}

#line 127 "runmath.in"
// Int Floor(real x);
void gen_runmath12(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 128 "runmath.in" 
  {Stack->push<Int>(Floor(x)); return;}
}

#line 132 "runmath.in"
// Int Round(real x);
void gen_runmath13(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 133 "runmath.in" 
  {Stack->push<Int>(Round(Intcap(x))); return;}
}

#line 137 "runmath.in"
// real fmod(real x, real y);
void gen_runmath14(stack *Stack)
{
  real y=vm::pop<real>(Stack);
  real x=vm::pop<real>(Stack);
#line 138 "runmath.in"
  if (y == 0.0) dividebyzero();
  {Stack->push<real>(fmod(x,y)); return;}
}

#line 143 "runmath.in"
// real atan2(real y, real x);
void gen_runmath15(stack *Stack)
{
  real x=vm::pop<real>(Stack);
  real y=vm::pop<real>(Stack);
#line 144 "runmath.in" 
  {Stack->push<real>(atan2(y,x)); return;}
}

#line 148 "runmath.in"
// real hypot(real x, real y);
void gen_runmath16(stack *Stack)
{
  real y=vm::pop<real>(Stack);
  real x=vm::pop<real>(Stack);
#line 149 "runmath.in" 
  {Stack->push<real>(hypot(x,y)); return;}
}

#line 153 "runmath.in"
// real remainder(real x, real y);
void gen_runmath17(stack *Stack)
{
  real y=vm::pop<real>(Stack);
  real x=vm::pop<real>(Stack);
#line 154 "runmath.in" 
  {Stack->push<real>(remainder(x,y)); return;}
}

#line 158 "runmath.in"
// real J(Int n, real x);
void gen_runmath18(stack *Stack)
{
  real x=vm::pop<real>(Stack);
  Int n=vm::pop<Int>(Stack);
#line 159 "runmath.in"
  {Stack->push<real>(jn(n,x)); return;}
}

#line 163 "runmath.in"
// real Y(Int n, real x);
void gen_runmath19(stack *Stack)
{
  real x=vm::pop<real>(Stack);
  Int n=vm::pop<Int>(Stack);
#line 164 "runmath.in"
  {Stack->push<real>(yn(n,x)); return;}
}

#line 168 "runmath.in"
// real erf(real x);
void gen_runmath20(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 169 "runmath.in"
  {Stack->push<real>(erf(x)); return;}
}

#line 173 "runmath.in"
// real erfc(real x);
void gen_runmath21(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 174 "runmath.in"
  {Stack->push<real>(erfc(x)); return;}
}

#line 178 "runmath.in"
// Int factorial(Int n);
void gen_runmath22(stack *Stack)
{
  Int n=vm::pop<Int>(Stack);
#line 179 "runmath.in"
  if(n < 0) error(invalidargument);
  {Stack->push<Int>(factorial(n)); return;}
}

#line 183 "runmath.in"
// Int choose(Int n, Int k);
void gen_runmath23(stack *Stack)
{
  Int k=vm::pop<Int>(Stack);
  Int n=vm::pop<Int>(Stack);
#line 184 "runmath.in"
  if(n < 0 || k < 0 || k > n) error(invalidargument);
  Int f=1;
  Int r=n-k;
  for(Int i=n; i > r; --i) {
    if(f > Int_MAX/i) integeroverflow(0);
    f=(f*i)/(n-i+1);
  }
  {Stack->push<Int>(f); return;}
}

#line 194 "runmath.in"
// real gamma(real x);
void gen_runmath24(stack *Stack)
{
  real x=vm::pop<real>(Stack);
#line 195 "runmath.in"
#ifdef HAVE_TGAMMA
  {Stack->push<real>(tgamma(x)); return;}
#else
  real lg = lgamma(x);
  {Stack->push<real>(signgam*exp(lg)); return;}
#endif
}

#line 204 "runmath.in"
// realarray* quadraticroots(real a, real b, real c);
void gen_runmath25(stack *Stack)
{
  real c=vm::pop<real>(Stack);
  real b=vm::pop<real>(Stack);
  real a=vm::pop<real>(Stack);
#line 205 "runmath.in"
  quadraticroots q(a,b,c);
  array *roots=new array(q.roots);
  if(q.roots >= 1) (*roots)[0]=q.t1;
  if(q.roots == 2) (*roots)[1]=q.t2;
  {Stack->push<realarray*>(roots); return;}
}

#line 213 "runmath.in"
// pairarray* quadraticroots(explicit pair a, explicit pair b, explicit pair c);
void gen_runmath26(stack *Stack)
{
  pair c=vm::pop<pair>(Stack);
  pair b=vm::pop<pair>(Stack);
  pair a=vm::pop<pair>(Stack);
#line 214 "runmath.in"
  Quadraticroots q(a,b,c);
  array *roots=new array(q.roots);
  if(q.roots >= 1) (*roots)[0]=q.z1;
  if(q.roots == 2) (*roots)[1]=q.z2;
  {Stack->push<pairarray*>(roots); return;}
}

#line 222 "runmath.in"
// realarray* cubicroots(real a, real b, real c, real d);
void gen_runmath27(stack *Stack)
{
  real d=vm::pop<real>(Stack);
  real c=vm::pop<real>(Stack);
  real b=vm::pop<real>(Stack);
  real a=vm::pop<real>(Stack);
#line 223 "runmath.in"
  cubicroots q(a,b,c,d);
  array *roots=new array(q.roots);
  if(q.roots >= 1) (*roots)[0]=q.t1;
  if(q.roots >= 2) (*roots)[1]=q.t2;
  if(q.roots == 3) (*roots)[2]=q.t3;
  {Stack->push<realarray*>(roots); return;}
}


// Logical operations
#line 234 "runmath.in"
// bool !(bool b);
void gen_runmath28(stack *Stack)
{
  bool b=vm::pop<bool>(Stack);
#line 235 "runmath.in"
  {Stack->push<bool>(!b); return;}
}

#line 240 "runmath.in"
void boolMemEq(stack *Stack)
{
  frame * b=vm::pop<frame *>(Stack);
  frame * a=vm::pop<frame *>(Stack);
#line 241 "runmath.in"
  {Stack->push<bool>(a == b); return;}
}

#line 245 "runmath.in"
void boolMemNeq(stack *Stack)
{
  frame * b=vm::pop<frame *>(Stack);
  frame * a=vm::pop<frame *>(Stack);
#line 246 "runmath.in"
  {Stack->push<bool>(a != b); return;}
}

#line 250 "runmath.in"
void boolFuncEq(stack *Stack)
{
  callable * b=vm::pop<callable *>(Stack);
  callable * a=vm::pop<callable *>(Stack);
#line 251 "runmath.in"
  {Stack->push<bool>(a->compare(b)); return;}
}

#line 255 "runmath.in"
void boolFuncNeq(stack *Stack)
{
  callable * b=vm::pop<callable *>(Stack);
  callable * a=vm::pop<callable *>(Stack);
#line 256 "runmath.in"
  {Stack->push<bool>(!(a->compare(b))); return;}
}


// Bit operations
#line 262 "runmath.in"
// Int AND(Int a, Int b);
void gen_runmath33(stack *Stack)
{
  Int b=vm::pop<Int>(Stack);
  Int a=vm::pop<Int>(Stack);
#line 263 "runmath.in"
  {Stack->push<Int>(a & b); return;}
}

#line 268 "runmath.in"
// Int OR(Int a, Int b);
void gen_runmath34(stack *Stack)
{
  Int b=vm::pop<Int>(Stack);
  Int a=vm::pop<Int>(Stack);
#line 269 "runmath.in"
  {Stack->push<Int>(a | b); return;}
}

#line 273 "runmath.in"
// Int XOR(Int a, Int b);
void gen_runmath35(stack *Stack)
{
  Int b=vm::pop<Int>(Stack);
  Int a=vm::pop<Int>(Stack);
#line 274 "runmath.in"
  {Stack->push<Int>(a ^ b); return;}
}

#line 278 "runmath.in"
// Int NOT(Int a);
void gen_runmath36(stack *Stack)
{
  Int a=vm::pop<Int>(Stack);
#line 279 "runmath.in"
  {Stack->push<Int>(~a); return;}
}

} // namespace run

namespace trans {

void gen_runmath_venv(venv &ve)
{
#line 62 "runmath.in"
  addFunc(ve, run::gen_runmath0, primReal(), "^", formal(primReal(), "x", false, false), formal(primInt(), "y", false, false));
#line 67 "runmath.in"
  addFunc(ve, run::gen_runmath1, primPair(), "^", formal(primPair(), "z", false, false), formal(primInt(), "y", false, false));
#line 72 "runmath.in"
  addFunc(ve, run::gen_runmath2, primInt(), "quotient", formal(primInt(), "x", false, false), formal(primInt(), "y", false, false));
#line 80 "runmath.in"
  addFunc(ve, run::gen_runmath3, primInt(), "abs", formal(primInt(), "x", false, false));
#line 85 "runmath.in"
  addFunc(ve, run::gen_runmath4, primInt(), "sgn", formal(primReal(), "x", false, false));
#line 90 "runmath.in"
  addFunc(ve, run::gen_runmath5, primInt(), "rand");
#line 95 "runmath.in"
  addFunc(ve, run::gen_runmath6, primVoid(), "srand", formal(primInt(), "seed", false, false));
#line 100 "runmath.in"
  addFunc(ve, run::gen_runmath7, primReal(), "unitrand");
#line 106 "runmath.in"
  addFunc(ve, run::gen_runmath8, primInt(), "ceil", formal(primReal(), "x", false, false));
#line 111 "runmath.in"
  addFunc(ve, run::gen_runmath9, primInt(), "floor", formal(primReal(), "x", false, false));
#line 116 "runmath.in"
  addFunc(ve, run::gen_runmath10, primInt(), "round", formal(primReal(), "x", false, false));
#line 122 "runmath.in"
  addFunc(ve, run::gen_runmath11, primInt(), "Ceil", formal(primReal(), "x", false, false));
#line 127 "runmath.in"
  addFunc(ve, run::gen_runmath12, primInt(), "Floor", formal(primReal(), "x", false, false));
#line 132 "runmath.in"
  addFunc(ve, run::gen_runmath13, primInt(), "Round", formal(primReal(), "x", false, false));
#line 137 "runmath.in"
  addFunc(ve, run::gen_runmath14, primReal(), "fmod", formal(primReal(), "x", false, false), formal(primReal(), "y", false, false));
#line 143 "runmath.in"
  addFunc(ve, run::gen_runmath15, primReal(), "atan2", formal(primReal(), "y", false, false), formal(primReal(), "x", false, false));
#line 148 "runmath.in"
  addFunc(ve, run::gen_runmath16, primReal(), "hypot", formal(primReal(), "x", false, false), formal(primReal(), "y", false, false));
#line 153 "runmath.in"
  addFunc(ve, run::gen_runmath17, primReal(), "remainder", formal(primReal(), "x", false, false), formal(primReal(), "y", false, false));
#line 158 "runmath.in"
  addFunc(ve, run::gen_runmath18, primReal(), "J", formal(primInt(), "n", false, false), formal(primReal(), "x", false, false));
#line 163 "runmath.in"
  addFunc(ve, run::gen_runmath19, primReal(), "Y", formal(primInt(), "n", false, false), formal(primReal(), "x", false, false));
#line 168 "runmath.in"
  addFunc(ve, run::gen_runmath20, primReal(), "erf", formal(primReal(), "x", false, false));
#line 173 "runmath.in"
  addFunc(ve, run::gen_runmath21, primReal(), "erfc", formal(primReal(), "x", false, false));
#line 178 "runmath.in"
  addFunc(ve, run::gen_runmath22, primInt(), "factorial", formal(primInt(), "n", false, false));
#line 183 "runmath.in"
  addFunc(ve, run::gen_runmath23, primInt(), "choose", formal(primInt(), "n", false, false), formal(primInt(), "k", false, false));
#line 194 "runmath.in"
  addFunc(ve, run::gen_runmath24, primReal(), "gamma", formal(primReal(), "x", false, false));
#line 204 "runmath.in"
  addFunc(ve, run::gen_runmath25, realArray(), "quadraticroots", formal(primReal(), "a", false, false), formal(primReal(), "b", false, false), formal(primReal(), "c", false, false));
#line 213 "runmath.in"
  addFunc(ve, run::gen_runmath26, pairArray(), "quadraticroots", formal(primPair(), "a", false, true), formal(primPair(), "b", false, true), formal(primPair(), "c", false, true));
#line 222 "runmath.in"
  addFunc(ve, run::gen_runmath27, realArray(), "cubicroots", formal(primReal(), "a", false, false), formal(primReal(), "b", false, false), formal(primReal(), "c", false, false), formal(primReal(), "d", false, false));
#line 232 "runmath.in"
  addFunc(ve, run::gen_runmath28, primBoolean(), "!", formal(primBoolean(), "b", false, false));
#line 240 "runmath.in"
  REGISTER_BLTIN(run::boolMemEq,"boolMemEq");
#line 245 "runmath.in"
  REGISTER_BLTIN(run::boolMemNeq,"boolMemNeq");
#line 250 "runmath.in"
  REGISTER_BLTIN(run::boolFuncEq,"boolFuncEq");
#line 255 "runmath.in"
  REGISTER_BLTIN(run::boolFuncNeq,"boolFuncNeq");
#line 260 "runmath.in"
  addFunc(ve, run::gen_runmath33, primInt(), "AND", formal(primInt(), "a", false, false), formal(primInt(), "b", false, false));
#line 268 "runmath.in"
  addFunc(ve, run::gen_runmath34, primInt(), "OR", formal(primInt(), "a", false, false), formal(primInt(), "b", false, false));
#line 273 "runmath.in"
  addFunc(ve, run::gen_runmath35, primInt(), "XOR", formal(primInt(), "a", false, false), formal(primInt(), "b", false, false));
#line 278 "runmath.in"
  addFunc(ve, run::gen_runmath36, primInt(), "NOT", formal(primInt(), "a", false, false));
}

} // namespace trans
