#ifndef __SYSMATH_H
#define __SYSMATH_H

#include <math.h>

#pragma warning(disable:4244)
#pragma warning(disable:4305)

#ifdef __ICL // intel compiler warning
	#pragma warning(disable:181)  // argument is incompatible with corresponding format string conversion
	#pragma warning(disable:175)  // subscript out of range
#endif

#define __TYPES_READY

struct Matrix;
struct Vector;

#define FALSE 0
#define TRUE  1
#define NULL 	0


#ifndef __WINDOWS_H
#ifndef _WINDOWS_
typedef short int	          WORD;
#endif
#endif
typedef unsigned short int	UWORD;
typedef long 								LONG;
typedef unsigned long				ULONG;
typedef int                 Bool;
typedef float								SReal;
typedef double							LReal;
typedef void*								Hndl;
typedef int									INT;
typedef unsigned int 				UINT;
typedef char								CHAR;
typedef unsigned char				UCHAR;

#ifndef MAXLONG
	#define MAXLONG						0x7fffffff  
#endif
#ifndef MINLONG
	#define MINLONG						(-0x7fffffff) // explicitely not 0x80000000
#endif
#ifndef MAXULONG
	#define MAXULONG					0xffffffff  
#endif
#ifndef MAXWORD
	#define MAXWORD						32767L
#endif
#ifndef MAXUWORD
	#define MAXUWORD					65535L
#endif

typedef float								Real;
#define MAXREAL							( 9.0e18)
#define MINREAL							(-9.0e18)

#define NOTOK								(-1)

#define pi		3.1415926535897932384626433832795
#define pi2		6.283185307179586476925286766559
#define pi05	1.5707963267948966192313216916398

inline Real  FMin(Real a,  Real b) { if (a<b) return a; return b; }
inline LReal FMin(LReal a, LReal b) { if (a<b) return a; return b; }
inline LONG  LMin(LONG a,  LONG b) { if (a<b) return a; return b; }

inline Real  FMax(Real a, Real b) { if (a<b) return b; return a; }
inline LReal FMax(LReal a, LReal b) { if (a<b) return b; return a; }
inline LONG  LMax(LONG a, LONG b) { if (a<b) return b; return a; }

inline Real  FCut(Real  a,Real b,Real c) { if (a<b) return b; if (a>c) return c; return a; }
inline LReal FCut(LReal a,Real b,Real c) { if (a<b) return b; if (a>c) return c; return a; }
inline LONG  LCut(LONG  a,LONG b,LONG c) { if (a<b) return b; if (a>c) return c; return a; }
template <class A> inline A TCut(A a,A b,A c) { if (a<b) return b; if (a>c) return c; return a; }

#ifndef __ICL

	inline LONG FtoL(float r)
	{
		LONG exp = (*(ULONG*)&r >> 23) & 0xFF,res;
		if (exp<0x7F)	return 0;
		if (exp>0x9e) res=MAXLONG;
		else res = ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(0x9e-exp);
		if (*(ULONG*)&r & 0x80000000) res=-res;
		return res;
	}

	#define Abs(a)			(((a)<0)?-(a):(a))

	#define Sin(r) 		(Real(sin 	(double(r))))
	#define Cos(r) 		(Real(cos 	(double(r))))
	#define Tan(r) 		(Real(tan 	(double(r))))
	#define ATan(r) 	(Real(atan	(double(r))))
	#define Exp(r)		(Real(exp 	(double(r))))
	#define Ln(r) 		(Real(log 	(double(r))))
	#define Ln10(r) 	(Real(log10	(double(r))))
	#define Sqrt(r)		(Real(sqrt	(double(r))))
	#define Floor(r)	(Real(floor	(double(r))))
	#define Ceil(r)		(Real(ceil	(double(r))))
	#define Pow(r,s)	(Real(pow		(double(r),double(s))))
	#define Cosh(r)		(Real(cosh	(double(r))))
	#define Sinh(r)		(Real(sinh	(double(r))))
	#define Tanh(r)		(Real(tanh	(double(r))))
	#define FMod(r,s)	(Real(fmod	(double(r),double(s))))

	inline Real ASin(Real val)
	{
		if(val>=1.0) return pi05;
		else if(val<=-1.0) return -pi05;
		return asin((double)val);
	}

	inline Real ACos(Real val)
	{
		if(val>=1.0) return 0.0;
		else if(val<=-1.0) return pi;
		return acos((double)val);
	}

	inline LONG LFloor(Real r)
	{
		LONG exp = (*(ULONG*)&r >> 23) & 0xFF;
		exp-=0x7f;

		if (*(ULONG*)&r & 0x80000000)
		{
			if (exp<0) return -1;
			if (exp>31) return MINLONG;

			LONG res = (0x7FFFFF)>>exp;
			LONG sub = ((*(ULONG*)&r)&res)!=0;
			res = ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp);
			return -res-sub;
		}

		if (exp<0) return 0;
		if (exp>31) return MAXLONG;
		return ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp);
	}

	inline LONG LCeil(Real r)
	{
		LONG exp = (*(ULONG*)&r >> 23) & 0xFF;
		exp-=0x7f;

		if (!(*(ULONG*)&r & 0x80000000))
		{
			if (exp<0) return 1;
			if (exp>31) return MAXLONG;

			LONG res = (0x7FFFFF)>>exp;
			LONG sub = ((*(ULONG*)&r)&res)!=0;
			res = ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp);
			return res+sub;
		}

		if (exp<0) return 0;
		if (exp>31) return MINLONG;
		return -LONG(ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp));
	}

#else

	#define FtoL(x)		LONG(x)

	inline Real  Abs( Real f) { return fabs(f); }
	inline LReal Abs(LReal f) { return fabs(f); }
	template <class X> inline X Abs(X f) { if (f<0) return -f; return f; }

	inline Real Sin(Real r)  { return sin(r); }
	inline Real Cos(Real r)  { return cos(r); }
	inline Real Tan(Real r)  { return tan(r); }
	inline Real ATan(Real r) { return atan(r); }
	inline Real Exp(Real r)  { return exp(r); }
	inline Real Ln(Real r)   { return log(r); }
	inline Real Ln10(Real r) { return log10(r); }
	inline Real Sqrt(Real r) { return sqrt(r); }
	inline Real Floor(Real r){ return floor(r); }
	inline Real Ceil(Real r) { return ceil(r); }
	inline Real Cosh(Real r) { return cosh(r); }
	inline Real Sinh(Real r) { return sinh(r); }
	inline Real Tanh(Real r) { return tanh(r); }
	inline Real Pow(Real r,Real s)  { return pow(r,s); }
	inline Real FMod(Real r,Real s) { return fmod(r,s); }
	inline Real ASin(Real val) { if(val>=1.0) return pi05; else if(val<=-1.0) return -pi05; return asin(val); }
	inline Real ACos(Real val) { if(val>=1.0) return 0.0; else if(val<=-1.0) return pi; return acos(val); }

	inline LReal Sin(LReal r)  { return sin(r); }
	inline LReal Cos(LReal r)  { return cos(r); }
	inline LReal Tan(LReal r)  { return tan(r); }
	inline LReal ATan(LReal r) { return atan(r); }
	inline LReal Exp(LReal r)  { return exp(r); }
	inline LReal Ln(LReal r)   { return log(r); }
	inline LReal Ln10(LReal r) { return log10(r); }
	inline LReal Sqrt(LReal r) { return sqrt(r); }
	inline LReal Floor(LReal r){ return floor(r); }
	inline LReal Ceil(LReal r) { return ceil(r); }
	inline LReal Cosh(LReal r) { return cosh(r); }
	inline LReal Sinh(LReal r) { return sinh(r); }
	inline LReal Tanh(LReal r) { return tanh(r); }
	inline LReal Pow(LReal r,LReal s)  { return pow(r,s); }
	inline LReal FMod(LReal r,LReal s) { return fmod(r,s); }
	inline LReal ASin(LReal val) { if(val>=1.0) return pi05; else if(val<=-1.0) return -pi05; return asin(val); }
	inline LReal ACos(LReal val) { if(val>=1.0) return 0.0; else if(val<=-1.0) return pi; return acos(val); }

	inline LONG LFloor(Real r)  { return LONG(Floor(r)); }
	inline LONG LCeil(Real r)   { return LONG(Ceil(r));  }
#endif

inline LONG LFloor(LReal r) { return LONG(Floor(r)); }
inline LONG LCeil(LReal r)  { return LONG(Ceil(r));  }

inline Real  Rad(Real r)    { return ((r)*pi/180.0); }
inline LReal Rad(LReal r)   { return ((r)*pi/180.0); }
inline Real  Deg(Real r)    { return ((r)*180.0/pi); }
inline LReal Deg(LReal r)   { return ((r)*180.0/pi); }
inline void SinCos(Real w,Real &sn,Real &cn) { sn=Sin(w); cn=Cos(w); }

#define Mod(a,b)	((a)<0?((a)-(((a)-(b)+1)/(b))*(b)):(a)%(b))

inline LONG SAFELONG(Real x)
{
	if(x<=MINLONG)
		return MINLONG;
	else if(x>=MAXLONG)
		return MAXLONG;

	return FtoL(x);
}

#endif
