#ifndef __FIXED_H__
#define __FIXED_H__

template<int BP>  // BP + # of bits to the right of the binary point
class Fixed {

	public:
		Fixed() : g(0) {}
		Fixed(const Fixed& a) : g( a.g ) {}
		Fixed(float a) : g( int(a / (float)STEP()) ) {}
		Fixed(double a) : g( int(a / (double)STEP()) ) {}
		Fixed(int a) : g( a << BP ) {}
		Fixed(long a) : g( a << BP ) {}
		Fixed& operator =(const Fixed& a) { g= a.g; return *this; }
		Fixed& operator =(float a) { g= Fixed(a).g; return *this; }
		Fixed& operator =(double a) { g= Fixed(a).g; return *this; }
		Fixed& operator =(int a) { g= Fixed(a).g; return *this; }
		Fixed& operator =(long a) { g= Fixed(a).g; return *this; }

		operator float() { return g * (float)STEP(); }
		operator double() { return g * (double)STEP(); }
		operator int() { return g>>BP; }
		operator long() { return g>>BP; }

		Fixed operator +() const { return Fixed(RAW,g); }
		Fixed operator -() const { return Fixed(RAW,-g); }

		Fixed operator +(const Fixed& a) const { return Fixed(RAW, g + a.g); }
		Fixed operator -(const Fixed& a) const { return Fixed(RAW, g - a.g); }

		Fixed operator *(const Fixed& a) const { return Fixed(RAW,  (int)( ((long long)g * (long long)a.g ) >> BP)); }
		Fixed operator /(const Fixed& a) const { return Fixed(RAW, int( (((long long)g << BP2) / (long long)(a.g)) >> BP) ); }

		Fixed operator +(float a) const { return Fixed(RAW, g + Fixed(a).g); }
		Fixed operator -(float a) const { return Fixed(RAW, g - Fixed(a).g); }
		Fixed operator *(float a) const { return Fixed(RAW, (g>>BPhalf) * (Fixed(a).g>>BPhalf) ); }
		Fixed operator /(float a) const { return Fixed(RAW, int( (((long long)g << BP2) / (long long)(Fixed(a).g)) >> BP) ); }

		Fixed operator +(double a) const { return Fixed(RAW, g + Fixed(a).g); }
		Fixed operator -(double a) const { return Fixed(RAW, g - Fixed(a).g); }
		Fixed operator *(double a) const { return Fixed(RAW, (g>>BPhalf) * (Fixed(a).g>>BPhalf) ); }
		Fixed operator /(double a) const { return Fixed(RAW, int( (((long long)g << BP2) / (long long)(Fixed(a).g)) >> BP) ); }

		Fixed& operator +=(Fixed a) { return *this = *this + a; return *this; }
		Fixed& operator -=(Fixed a) { return *this = *this - a; return *this; }
		Fixed& operator *=(Fixed a) { return *this = *this * a; return *this; }
		Fixed& operator /=(Fixed a) { return *this = *this / a; return *this; }

		Fixed& operator +=(int a) { return *this = *this + (Fixed)a; return *this; }
		Fixed& operator -=(int a) { return *this = *this - (Fixed)a; return *this; }
		Fixed& operator *=(int a) { return *this = *this * (Fixed)a; return *this; }
		Fixed& operator /=(int a) { return *this = *this / (Fixed)a; return *this; }

		Fixed& operator +=(long a) { return *this = *this + (Fixed)a; return *this; }
		Fixed& operator -=(long a) { return *this = *this - (Fixed)a; return *this; }
		Fixed& operator *=(long a) { return *this = *this * (Fixed)a; return *this; }
		Fixed& operator /=(long a) { return *this = *this / (Fixed)a; return *this; }

		Fixed& operator +=(float a) { return *this = *this + a; return *this; }
		Fixed& operator -=(float a) { return *this = *this - a; return *this; }
		Fixed& operator *=(float a) { return *this = *this * a; return *this; }
		Fixed& operator /=(float a) { return *this = *this / a; return *this; }

		Fixed& operator +=(double a) { return *this = *this + a; return *this; }
		Fixed& operator -=(double a) { return *this = *this - a; return *this; }
		Fixed& operator *=(double a) { return *this = *this * a; return *this; }
		Fixed& operator /=(double a) { return *this = *this / a; return *this; }

		bool operator ==(const Fixed& a) const { return g == a.g; }
		bool operator !=(const Fixed& a) const { return g != a.g; }
		bool operator <=(const Fixed& a) const { return g <= a.g; }
		bool operator >=(const Fixed& a) const { return g >= a.g; }
		bool operator  <(const Fixed& a) const { return g  < a.g; }
		bool operator  >(const Fixed& a) const { return g  > a.g; }

		bool operator ==(float a) const { return g == Fixed(a).g; }
		bool operator !=(float a) const { return g != Fixed(a).g; }
		bool operator <=(float a) const { return g <= Fixed(a).g; }
		bool operator >=(float a) const { return g >= Fixed(a).g; }
		bool operator  <(float a) const { return g  < Fixed(a).g; }
		bool operator  >(float a) const { return g  > Fixed(a).g; }

		bool operator ==(double a) const { return g == Fixed(a).g; }
		bool operator !=(double a) const { return g != Fixed(a).g; }
		bool operator <=(double a) const { return g <= Fixed(a).g; }
		bool operator >=(double a) const { return g >= Fixed(a).g; }
		bool operator  <(double a) const { return g  < Fixed(a).g; }
		bool operator  >(double a) const { return g  > Fixed(a).g; }

	private:

		int	g; // the guts

		static const int BP2= BP*2;  // how many low bits are right of Binary Point
		static const int BPhalf= BP/2;  // how many low bits are right of Binary Point

		static double STEP() { return 1.0 / (1<<BP); }  // smallest step we can represent

		// for private construction via guts
		enum FixedRaw { RAW };
		Fixed(FixedRaw, int guts) : g(guts) {}
};

#if 0
inline Fixed operator +(float a, const Fixed& b) { return Fixed(a)+b; }
inline Fixed operator -(float a, const Fixed& b) { return Fixed(a)-b; }
inline Fixed operator *(float a, const Fixed& b) { return Fixed(a)*b; }
inline Fixed operator /(float a, const Fixed& b) { return Fixed(a)/b; }

inline bool operator ==(float a, const Fixed& b) { return Fixed(a) == b; }
inline bool operator !=(float a, const Fixed& b) { return Fixed(a) != b; }
inline bool operator <=(float a, const Fixed& b) { return Fixed(a) <= b; }
inline bool operator >=(float a, const Fixed& b) { return Fixed(a) >= b; }
inline bool operator  <(float a, const Fixed& b) { return Fixed(a)  < b; }
inline bool operator  >(float a, const Fixed& b) { return Fixed(a)  > b; }

inline Fixed operator +(double a, const Fixed& b) { return Fixed(a)+b; }
inline Fixed operator -(double a, const Fixed& b) { return Fixed(a)-b; }
inline Fixed operator *(double a, const Fixed& b) { return Fixed(a)*b; }
inline Fixed operator /(double a, const Fixed& b) { return Fixed(a)/b; }

inline bool operator ==(double a, const Fixed& b) { return Fixed(a) == b; }
inline bool operator !=(double a, const Fixed& b) { return Fixed(a) != b; }
inline bool operator <=(double a, const Fixed& b) { return Fixed(a) <= b; }
inline bool operator >=(double a, const Fixed& b) { return Fixed(a) >= b; }
inline bool operator  <(double a, const Fixed& b) { return Fixed(a)  < b; }
inline bool operator  >(double a, const Fixed& b) { return Fixed(a)  > b; }

int& operator +=(int& a, const Fixed& b) { a = (Fixed)a + b; return a; }
int& operator -=(int& a, const Fixed& b) { a = (Fixed)a - b; return a; }
int& operator *=(int& a, const Fixed& b) { a = (Fixed)a * b; return a; }
int& operator /=(int& a, const Fixed& b) { a = (Fixed)a / b; return a; }

long& operator +=(long& a, const Fixed& b) { a = (Fixed)a + b; return a; }
long& operator -=(long& a, const Fixed& b) { a = (Fixed)a - b; return a; }
long& operator *=(long& a, const Fixed& b) { a = (Fixed)a * b; return a; }
long& operator /=(long& a, const Fixed& b) { a = (Fixed)a / b; return a; }

float& operator +=(float& a, const Fixed& b) { a = a + b; return a; }
float& operator -=(float& a, const Fixed& b) { a = a - b; return a; }
float& operator *=(float& a, const Fixed& b) { a = a * b; return a; }
float& operator /=(float& a, const Fixed& b) { a = a / b; return a; }

double& operator +=(double& a, const Fixed& b) { a = a + b; return a; }
double& operator -=(double& a, const Fixed& b) { a = a - b; return a; }
double& operator *=(double& a, const Fixed& b) { a = a * b; return a; }
double& operator /=(double& a, const Fixed& b) { a = a / b; return a; }

#endif
#endif
