/*****
* mathop.h
* Tom Prince 2005/3/18
*
* Defines some runtime functions used by the stack machine.
*
*****/
#ifndef MATHOP_H
#define MATHOP_H
#include <sstream>
#include "stack.h"
#include "mod.h"
#include "triple.h"
namespace run {
template <typename T>
struct less {
bool operator() (T x, T y, size_t=0) {return x < y;}
};
template <typename T>
struct lessequals {
bool operator() (T x, T y, size_t=0) {return x <= y;}
};
template <typename T>
struct equals {
bool operator() (T x, T y, size_t=0) {return x == y;}
};
template <typename T>
struct greaterequals {
bool operator() (T x, T y, size_t=0) {return x >= y;}
};
template <typename T>
struct greater {
bool operator() (T x, T y, size_t=0) {return x > y;}
};
template <typename T>
struct notequals {
bool operator() (T x, T y, size_t=0) {return x != y;}
};
template <typename T>
struct And {
bool operator() (T x, T y, size_t=0) {return x && y;}
};
template <typename T>
struct Or {
bool operator() (T x, T y, size_t=0) {return x || y;}
};
template <typename T>
struct Xor {
bool operator() (T x, T y, size_t=0) {return x ^ y;}
};
template <typename T>
struct plus {
T operator() (T x, T y, size_t=0) {return x+y;}
};
template <typename T>
struct minus {
T operator() (T x, T y, size_t=0) {return x-y;}
};
template <typename T>
struct times {
T operator() (T x, T y, size_t=0) {return x*y;}
};
template <>
struct times<camp::triple> {
camp::triple operator() (double x, camp::triple y, size_t=0) {return x*y;}
};
template <typename T>
struct timesR {
T operator () (T y, double x, size_t=0) {return x*y;}
};
extern void dividebyzero(size_t i=0);
extern void integeroverflow(size_t i=0);
template <typename T>
struct divide {
T operator() (T x, T y, size_t i=0) {
if(y == 0) dividebyzero(i);
return x/y;
}
};
template <>
struct divide<camp::triple> {
camp::triple operator() (camp::triple x, double y, size_t=0) {return x/y;}
};
inline bool validInt(double x) {
return x > (double) Int_MIN-0.5 && x < (double) Int_MAX+0.5;
}
inline void checkInt(double x, size_t i)
{
if(validInt(x)) return;
integeroverflow(i);
}
inline Int Intcast(double x)
{
if(validInt(x)) return (Int) x;
integeroverflow(0);
return 0;
}
template<>
struct plus<Int> {
Int operator() (Int x, Int y, size_t i=0) {
if((y > 0 && x > Int_MAX-y) || (y < 0 && x < Int_MIN-y))
integeroverflow(i);
return x+y;
}
};
template<>
struct minus<Int> {
Int operator() (Int x, Int y, size_t i=0) {
if((y < 0 && x > Int_MAX+y) || (y > 0 && x < Int_MIN+y))
integeroverflow(i);
return x-y;
}
};
template<>
struct times<Int> {
Int operator() (Int x, Int y, size_t i=0) {
if(y == 0) return 0;
if(y < 0) {y=-y; x=-x;}
if(y > Int_MAX || x > Int_MAX/y || x < Int_MIN/y)
integeroverflow(i);
return x*y;
}
};
template<>
struct divide<Int> {
double operator() (Int x, Int y, size_t i=0) {
if(y == 0) dividebyzero(i);
return ((double) x)/(double) y;
}
};
template <class T>
void Negate(vm::stack *s)
{
T a=vm::pop<T>(s);
s->push(-a);
}
inline Int Negate(Int x, size_t i=0) {
if(x < -Int_MAX) integeroverflow(i);
return -x;
}
template<>
inline void Negate<Int>(vm::stack *s)
{
s->push(Negate(vm::pop<Int>(s)));
}
inline double pow(double x, double y)
{
return ::pow(x,y);
}
template<class T>
T pow(T x, Int y)
{
if(y == 0) return 1.0;
if(x == 0.0 && y > 0) return 0.0;
if(y < 0) {y=-y; x=1/x;}
T r=1.0;
for(;;) {
if(y & 1) r *= x;
if((y >>= 1) == 0) return r;
x *= x;
}
}
template <typename T>
struct power {
T operator() (T x, T y, size_t=0) {return pow(x,y);}
};
template <>
struct power<Int> {
Int operator() (Int x, Int p, size_t i=0) {
if(p == 0) return 1;
Int sign=1;
if(x < 0) {
if(p % 2) sign=-1;
x=-x;
}
if(p > 0) {
if(x == 0) return 0;
Int r = 1;
for(;;) {
if(p & 1) {
if(r > Int_MAX/x) integeroverflow(i);
r *= x;
}
if((p >>= 1) == 0)
return sign*r;
if(x > Int_MAX/x) integeroverflow(i);
x *= x;
}
} else {
if(x == 1) return sign;
ostringstream buf;
if(i > 0) buf << "array element " << i << ": ";
buf << "Only 1 and -1 can be raised to negative exponents as integers.";
vm::error(buf);
return 0;
}
}
};
template <typename T>
struct mod {
T operator() (T x, T y, size_t i=0) {
if(y == 0) dividebyzero(i);
return portableMod(x,y);
}
};
template <>
struct mod<Int> {
Int operator() (Int x, Int y, size_t i=0) {
if(y == 0) dividebyzero(i);
return imod(x,y);
}
};
template <typename>
struct quotient {
Int operator() (Int x, Int y, size_t i=0) {
if(y == 0) dividebyzero(i);
if(y == -1) return Negate(x);
// Implementation-independent definition of integer division: round down
Int q=x/y;
if(!((x < 0)^(y < 0)) || y*q == x) return q;
return q-1;
}
};
template <typename T>
struct min {
T operator() (T x, T y, size_t=0) {return x < y ? x : y;}
};
template <typename T>
struct max {
T operator() (T x, T y, size_t=0) {return x > y ? x : y;}
};
template<class T>
inline T Min(T a, T b)
{
return (a < b) ? a : b;
}
template<class T>
inline T Max(T a, T b)
{
return (a > b) ? a : b;
}
template <typename T>
struct minbound {
camp::pair operator() (camp::pair z, camp::pair w) {
return camp::pair(Min(z.getx(),w.getx()),Min(z.gety(),w.gety()));
}
camp::triple operator() (camp::triple u, camp::triple v) {
return camp::triple(Min(u.getx(),v.getx()),Min(u.gety(),v.gety()),
Min(u.getz(),v.getz()));
}
};
template <typename T>
struct maxbound {
camp::pair operator() (camp::pair z, camp::pair w) {
return camp::pair(Max(z.getx(),w.getx()),Max(z.gety(),w.gety()));
}
camp::triple operator() (camp::triple u, camp::triple v) {
return camp::triple(Max(u.getx(),v.getx()),Max(u.gety(),v.gety()),
Max(u.getz(),v.getz()));
}
};
template <double (*func)(double)>
void realReal(vm::stack *s)
{
double x=vm::pop<double>(s);
s->push(func(x));
}
template <class T, template <class S> class op>
void binaryOp(vm::stack *s)
{
T b=vm::pop<T>(s);
T a=vm::pop<T>(s);
s->push(op<T>()(a,b));
}
template <class T>
void interp(vm::stack *s)
{
double t=vm::pop<double>(s);
T b=vm::pop<T>(s);
T a=vm::pop<T>(s);
s->push((1-t)*a+t*b);
}
} // namespace run
#endif //MATHOP_H