// Copyright 2007 David Hilvert <dhilvert@auricle.dyndns.org>, 
//                              <dhilvert@ugcs.caltech.edu>

/*  This file is part of the Anti-Lamenessing Engine.

    The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with the Anti-Lamenessing Engine; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef __ale_fixed_h__
#define __ale_fixed_h__

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include "ale_math.h"

#define FIXED16 4
#define FIXED32 5

#define DEBUG_FIXED_POINT 0

/*
 * Define a fixed point data type.
 */

class ale_fixed_16 {
public:
	typedef short bits_t;
	typedef int mulbits_t;
	static bits_t posinf() {
		return 32767;
	}
	static bits_t neginf() {
		return -32766;
	}
	static bits_t nan() {
		return -32767;
	}
	static bits_t rint(double d) {
		return (bits_t) lrint(d);
	}
};

class ale_fixed_16_calc {
public:
	typedef int bits_t;
	typedef int mulbits_t;
	static bits_t posinf() {
		return 2147483647;
	}
	static bits_t neginf() {
		return -2147483646;
	}
	static bits_t nan() {
		return -2147483647;
	}
	static bits_t rint(double d) {
		return (bits_t) lrint(d);
	}
};

#if ALE_COLORS == FIXED16
class ale_fixed_16_accum {
public:
	typedef int bits_t;
	typedef long long mulbits_t;
	static bits_t posinf() {
		return 2147483647;
	}
	static bits_t neginf() {
		return -2147483646;
	}
	static bits_t nan() {
		return -2147483647;
	}
	static bits_t rint(double d) {
		return (bits_t) lrint(d);
	}
};
#endif

#if ALE_COLORS == FIXED32 || ALE_COORDINATES == FIXED32
class ale_fixed_32 {
public:
	typedef int bits_t;
	typedef long long mulbits_t;
	static bits_t posinf() {
		return 2147483647;
	}
	static bits_t neginf() {
		return -2147483646;
	}
	static bits_t nan() {
		return -2147483647;
	}
	static bits_t rint(double d) {
		return (bits_t) lrint(d);
	}
};
#endif

#if ALE_COLORS == FIXED32
class ale_fixed_32_accum {
public:
	typedef long long bits_t;
	typedef long long mulbits_t;
	static bits_t posinf() {
		return 9223372036854775807LL;
	}
	static bits_t neginf() {
		return -9223372036854775806LL;
	}
	static bits_t nan() {
		return -9223372036854775807LL;
	}
	static bits_t rint(double d) {
		return (bits_t) llrint(d);
	}
};
#endif

#define ALE_FIXED_NAN (fixed_type::nan())
#define ALE_FIXED_POSINF (fixed_type::posinf())
#define ALE_FIXED_NEGINF (fixed_type::neginf())

template<class fixed_type, unsigned int N>
class ale_fixed {
	static int casting_disabled;

public:

	typedef typename fixed_type::bits_t bits_t;
	typedef typename fixed_type::mulbits_t mulbits_t;
	
	bits_t bits;

	/*
	 * Bit-conversion facilities.
	 */

	static ale_fixed bits_to_fixed(bits_t b) {
		ale_fixed result;
		result.bits = b;
		return result;
	}

	static bits_t fixed_to_bits(ale_fixed f) {

		if (f.bits >= 1 << N)
			return ((1 << N) - 1);

		return f.bits;
	}


	/*
	 * Constructors.
	 */
	ale_fixed() {
		bits = 0;
	}

	ale_fixed(const ale_fixed &f) {
		bits = f.bits;
	}

	ale_fixed& operator=(const ale_fixed &f) {
		bits = f.bits;
		
		return (*this);
	}

	/*
	 * Disable casting
	 */

	static void disable_casting() {
		casting_disabled = 1;
	}

	/*
	 * Enable casting
	 */

	static void enable_casting() {
		casting_disabled = 0;
	}

	/*
	 * Casting status.
	 */

	static int casting_status() {
		return !casting_disabled;
	}

	/*
	 * Cast to ordinary numbers
	 */

	operator double() const {
#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		assert(!casting_disabled);
		if (bits == ALE_FIXED_NAN) {
			double zero = 0;
			double nan = zero / zero;
			assert (isnan(nan));
			return nan;
		} else if (bits == ALE_FIXED_NEGINF) {
			double zero = 0;
			double negone = -1;
			double neginf = negone / zero;
			assert (isinf(neginf));
			assert (neginf < 0);
			return neginf;
		} else if (bits == ALE_FIXED_POSINF) {
			double zero = 0;
			double posone = +1;
			double posinf = posone / zero;
			assert (isinf(posinf));
			assert (posinf > 0);
			return posinf;
		}
#endif

		return (((double) bits) / (1 << N));
	}

	operator float() const {
#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		assert(!casting_disabled);
		if (bits == ALE_FIXED_NAN) {
			float zero = 0;
			float nan = zero / zero;
			assert (isnan(nan));
			return nan;
		} else if (bits == ALE_FIXED_NEGINF) {
			float zero = 0;
			float negone = -1;
			float neginf = negone / zero;
			assert (isinf(neginf));
			assert (neginf < 0);
			return neginf;
		} else if (bits == ALE_FIXED_POSINF) {
			float zero = 0;
			float posone = +1;
			float posinf = posone / zero;
			assert (isinf(posinf));
			assert (posinf > 0);
			return posinf;
		}
#endif

		return (((float) bits) / (1 << N));
	}

	operator int() const {
#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		assert (bits != ALE_FIXED_NAN);
		assert (bits != ALE_FIXED_POSINF);
		assert (bits != ALE_FIXED_NEGINF);
#endif

		return bits / (1 << N);
	}

	operator unsigned int() const {
#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		assert (bits != ALE_FIXED_NAN);
		assert (bits != ALE_FIXED_POSINF);
		assert (bits != ALE_FIXED_NEGINF);
		assert (bits >= 0);
#endif

		return (unsigned int) operator int();
	}

#if 0
	template<class fixed_type_2, unsigned int M>
	operator ale_fixed<fixed_type_2, M>() const {
		ale_fixed<fixed_type_2, M> result;

		if (bits == ALE_FIXED_NAN) {
			result.bits = fixed_type_2::nan();
			return result;
		}

		if (bits == ALE_FIXED_POSINF) {
			result.bits = fixed_type_2::posinf();
			return result;
		}

		if (bits == ALE_FIXED_NEGINF) {
			result.bits = fixed_type_2::neginf();
			return result;
		}

		if (sizeof(ale_fixed<fixed_type_2,M>) > sizeof(ale_fixed<fixed_type,N>)) {
			typedef typename fixed_type_2::bits_t bits_t_calc;

			bits_t_calc type_result;

			if (M >= N)
				type_result = bits << (bits_t_calc) ((int) M - (int) N);
			else
				type_result = bits / ((bits_t_calc) 1 << (bits_t_calc) ((int) N - (int) M));

			result.bits = type_result;

		} else {
			typedef bits_t bits_t_calc;

			bits_t_calc type_result;

			if (M >= N)
				type_result = bits << (bits_t_calc) ((int) M - (int) N);
			else
				type_result = bits / ((bits_t_calc) 1 << (bits_t_calc) ((int) N - (int) M));

			if (type_result > fixed_type_2::posinf())
				result.bits = fixed_type_2::posinf();
			else if (type_result < fixed_type_2::neginf())
				result.bits = fixed_type_2::neginf();
			else
				result.bits = type_result;
		}

		return result;
	}
#endif

	/*
	 * Cast from ordinary numbers
	 */

	template<class fixed_type_2, unsigned int M>
	ale_fixed(const ale_fixed<fixed_type_2,M> &d) {

		/*
		 * XXX: this shouldn't be necessary.
		 */

		bits = 0;

		if (d.bits == fixed_type_2::nan()) {
			bits = ALE_FIXED_NAN;
			return;
		}

		if (bits == fixed_type_2::posinf()) {
			bits = ALE_FIXED_POSINF;
			return;
		}

		if (bits == fixed_type_2::neginf()) {
			bits = ALE_FIXED_NEGINF;
			return;
		}

		if (sizeof(ale_fixed<fixed_type,N>) > sizeof(ale_fixed<fixed_type_2,M>)) {
			if (N >= M)
				bits = d.bits << (bits_t) ((int) N - (int) M);
			else
				bits = d.bits / ((bits_t) 1 << (bits_t) ((int) M - (int) N));
		} else {
			typedef typename ale_fixed<fixed_type_2,M>::bits_t bits_t_calc;

			bits_t_calc type_result;

			if (N >= M)
				type_result = d.bits << (bits_t_calc) ((int) N - (int) M);
			else
				type_result = d.bits / ((bits_t_calc) 1 << (bits_t_calc) ((int) M - (int) N));

			if (type_result > ALE_FIXED_POSINF)
				bits = ALE_FIXED_POSINF;
			else if (type_result < ALE_FIXED_NEGINF)
				bits = ALE_FIXED_NEGINF;
			else
				bits = type_result;
		}
	}

	ale_fixed(double d) {
#if DEBUG_FIXED_POINT
		/* 
		 * Removed due to a tendency to trigger unpredictably.
		 */
		assert(!casting_disabled);
#endif

		if (isnan(d)) {
			bits = ALE_FIXED_NAN;
		} else if (isinf(d) && d > 0) {
			bits = ALE_FIXED_POSINF;
		} else if (isinf(d) && d < 0) {
			bits = ALE_FIXED_NEGINF;
		} else {
			bits = (bits_t) fixed_type::rint(d * (1 << N));

#if DEBUG_FIXED_POINT
			/*
			 * Removed for performance reasons.
			 */

			assert((double) *this > (d - (double) 1 / (1 << N)));
			assert((double) *this < (d + (double) 1 / (1 << N)));

			assert(bits < ALE_FIXED_POSINF);
			assert(bits > ALE_FIXED_NEGINF);
#endif
		}
	}

	ale_fixed(int d) {
		bits = (bits_t) d << N;
#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		assert((d >= 0 && bits >> N == d)
		    || (d < 0 && (-bits) >> N == -d));

		assert (bits < ALE_FIXED_POSINF);
		assert (bits > ALE_FIXED_NEGINF);
#endif
	}

	ale_fixed(unsigned int d) {
		bits = (bits_t) d << N;

		assert((unsigned int) (bits >> N) == d);

		assert (bits < ALE_FIXED_POSINF);
		assert (bits > ALE_FIXED_NEGINF);
	}

	/*
	 * Operators.
	 */

	ale_fixed operator-() const {

		ale_fixed result;

		if (bits == ALE_FIXED_NAN || bits == 0)
			return *this;
		else if (bits == ALE_FIXED_POSINF)
			result.bits = ALE_FIXED_NEGINF;
		else if (bits == ALE_FIXED_NEGINF)
			result.bits = ALE_FIXED_POSINF;
		else
			result.bits = -bits;

		return result;
	}

	ale_fixed unexceptional_negation() const {
		ale_fixed result;

		result.bits = -bits;

		return result;
	}

	ale_fixed operator+(ale_fixed f) const {
		ale_fixed result;

#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN
		 || (bits == ALE_FIXED_POSINF && f.bits == ALE_FIXED_NEGINF)
		 || (bits == ALE_FIXED_NEGINF && f.bits == ALE_FIXED_POSINF)) {
			result.bits = ALE_FIXED_NAN;
			return result;
		}
#endif

		bits_t bits_result = bits + f.bits;

#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		if (bits_result >= ALE_FIXED_POSINF
		 || bits == ALE_FIXED_POSINF || f.bits == ALE_FIXED_POSINF
		 || bits > 0 && f.bits > 0 && bits_result < 0) {
			result.bits = ALE_FIXED_POSINF;
			return result;
		} else if (bits_result <= ALE_FIXED_NEGINF
		      || bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_NEGINF
		      || bits < 0 && f.bits < 0 && bits_result > 0) {
			result.bits = ALE_FIXED_NEGINF;
			return result;
		}
#endif

		result.bits = bits_result;

		return result;
	}

	ale_fixed operator+(int i) const {
		return operator+(ale_fixed(i));
	}

	ale_fixed operator+(unsigned int i) const {
		return operator+(ale_fixed(i));
	}

	ale_fixed operator-(ale_fixed f) const {
		ale_fixed result;

#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN
		 || (bits == ALE_FIXED_POSINF && f.bits == ALE_FIXED_POSINF)
		 || (bits == ALE_FIXED_NEGINF && f.bits == ALE_FIXED_NEGINF)) {
			result.bits = ALE_FIXED_NAN;
			return result;
		}
#endif

		bits_t bits_result = bits - f.bits;

#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		if (bits_result >= ALE_FIXED_POSINF
		 || bits == ALE_FIXED_POSINF || f.bits == ALE_FIXED_NEGINF
		 || bits > 0 && f.bits < 0 && bits_result < 0) {
			result.bits = ALE_FIXED_POSINF;
			return result;
		} else if (bits_result <= ALE_FIXED_NEGINF
		      || bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_POSINF
		      || bits < 0 && f.bits > 0 && bits_result > 0) {
			result.bits = ALE_FIXED_NEGINF;
			return result;
		}
#endif

		result.bits = bits_result;

		return result;
	}

	ale_fixed operator-(int i) const {
		return operator-(ale_fixed(i));
	}

	ale_fixed operator-(unsigned int i) const {
		return operator-(ale_fixed(i));
	}

	ale_fixed operator*(ale_fixed f) const {
		ale_fixed result;

#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN) {
			result.bits = ALE_FIXED_NAN;
			return result;
		}
#endif 
			

		mulbits_t mul_result = ((mulbits_t) bits * (mulbits_t) f.bits) / (1 << N);

#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		if (mul_result > (mulbits_t) ALE_FIXED_POSINF 
		 || mul_result < (mulbits_t) ALE_FIXED_NEGINF
		 || bits == ALE_FIXED_POSINF || f.bits == ALE_FIXED_POSINF
		 || bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_NEGINF) {
			if (mul_result > 0)
				result.bits = ALE_FIXED_POSINF;
			else if (mul_result < 0)
				result.bits = ALE_FIXED_NEGINF;
			else if (mul_result == 0)
				result.bits = ALE_FIXED_NAN;
			else
				assert(0);
			return result;
		}
#endif

		result.bits = mul_result;
		return result;
	}

	ale_fixed operator*(int i) const {
		return operator*(ale_fixed(i));
	}

	ale_fixed operator*(unsigned int i) const {
		return operator*(ale_fixed(i));
	}

	ale_fixed operator/(ale_fixed f) const {
		ale_fixed result;

		/*
		 * While this approach may not be suitable for all
		 * applications, it can be a convenient way to detect and
		 * manufacture non-finite values.
		 */
		if ((bits == 0 && f.bits == 0)
#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		 || bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN
		 || ((bits == ALE_FIXED_NEGINF || bits == ALE_FIXED_POSINF)
		  && (f.bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_POSINF))
#endif
		) {
			result.bits = ALE_FIXED_NAN;
			return result;
		} else if (f.bits == 0 && bits > 0) {
			result.bits = ALE_FIXED_POSINF;
			return result;
		} else if (f.bits == 0 && bits < 0) {
			result.bits = ALE_FIXED_NEGINF;
			return result;
		} 
		
#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		else if (f.bits == ALE_FIXED_POSINF || f.bits == ALE_FIXED_NEGINF) {
			result.bits = 0;
			return result;
		} 
#endif
			
		mulbits_t div_result = ((mulbits_t) bits << N) / f.bits;

#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

		if (div_result > (mulbits_t) ALE_FIXED_POSINF) {
			result.bits = ALE_FIXED_POSINF;
			return result;
		} else if (div_result < (mulbits_t) ALE_FIXED_NEGINF) {
			result.bits = ALE_FIXED_NEGINF;
			return result;
		}
#endif

		result.bits = (bits_t) div_result;
		return result;
	}

	ale_fixed operator/(int i) const {
		return operator/(ale_fixed(i));
	}

	ale_fixed operator/(unsigned int i) const {
		return operator/(ale_fixed(i));
	}

	ale_fixed &operator+=(ale_fixed f) {
		*this = *this + f;
		return *this;
	}

	ale_fixed &operator-=(ale_fixed f) {
		*this = *this - f;
		return *this;
	}

	ale_fixed &operator*=(ale_fixed f) {
		*this = *this * f;
		return *this;
	}

	ale_fixed &operator/=(ale_fixed f) {
		*this = *this / f;
		return *this;
	}

	int operator!=(ale_fixed f) const {
		if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
			return 1;

		if (bits == f.bits)
			return 0;

		return 1;
	}

	int operator==(ale_fixed f) const {
		return !(operator!=(f));
	}

	int operator<=(ale_fixed f) const {
		if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
			return 0;

		if (bits <= f.bits)
			return 1;

		return 0;
	}

	int operator>=(ale_fixed f) const {
		if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
			return 0;

		if (bits >= f.bits)
			return 1;

		return 0;
	}

	int operator>(ale_fixed f) const {
		if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
			return 0;

		if (bits > f.bits)
			return 1;

		return 0;
	}

	int operator<(ale_fixed f) const {
		if (bits == ALE_FIXED_NAN || f.bits == ALE_FIXED_NAN)
			return 0;

		if (bits < f.bits)
			return 1;

		return 0;
	}

	int operator>=(int d) const {
		return operator>=((ale_fixed) d);
	}

	int operator<=(int d) const {
		return operator<=((ale_fixed) d);
	}

	int operator==(int d) const {
		return operator==((ale_fixed) d);
	}

	int operator!=(int d) const {
		return operator!=((ale_fixed) d);
	}

	int operator>(int d) const {
		return operator>((ale_fixed) d);
	}

	int operator<(int d) const {
		return operator<((ale_fixed) d);
	}

	int operator>=(double d) const {
		return operator>=((ale_fixed) d);
	}

	int operator>=(float d) const {
		return operator>=((ale_fixed) d);
	}

	int operator<=(double d) const {
		return operator<=((ale_fixed) d);
	}

	int operator==(double d) const {
		return operator==((ale_fixed) d);
	}

	int operator!=(double d) const {
		return operator!=((ale_fixed) d);
	}

	int operator>(double d) const {
		return operator>((ale_fixed) d);
	}

	int operator<(double d) const {
		return operator<((ale_fixed) d);
	}

	int operator>=(unsigned int d) const {
		return operator>=((ale_fixed) d);
	}

	int operator<=(unsigned int d) const {
		return operator<=((ale_fixed) d);
	}

	int operator==(unsigned int d) const {
		return operator==((ale_fixed) d);
	}

	int operator!=(unsigned int d) const {
		return operator!=((ale_fixed) d);
	}

	int operator>(unsigned int d) const {
		return operator>((ale_fixed) d);
	}

	int operator<(unsigned int d) const {
		return operator<((ale_fixed) d);
	}

};

#define ALE_FIXED_INCORPORATE_OPERATOR(return_value, op)			\
template<class fixed_type, unsigned int N>					\
return_value operator op(double a, const ale_fixed<fixed_type, N> &f) {		\
	ale_fixed<fixed_type, N> g(a);					\
	return g.operator op(f);				\
}								\
								\
template<class fixed_type, unsigned int N>					\
return_value operator op(int a, const ale_fixed<fixed_type, N> &f) {		\
	return (ale_fixed<fixed_type, N>) a op f;					\
}								\
								\
template<class fixed_type, unsigned int N>					\
return_value operator op(unsigned int a, const ale_fixed<fixed_type, N> &f) {	\
	return (ale_fixed<fixed_type, N>) a op f;					\
}								\

#define STDARGS ale_fixed<fixed_type,N>

ALE_FIXED_INCORPORATE_OPERATOR(STDARGS, +);
ALE_FIXED_INCORPORATE_OPERATOR(STDARGS, -);
ALE_FIXED_INCORPORATE_OPERATOR(STDARGS, *);
ALE_FIXED_INCORPORATE_OPERATOR(STDARGS, /);
ALE_FIXED_INCORPORATE_OPERATOR(int, <=);
ALE_FIXED_INCORPORATE_OPERATOR(int, >=);
ALE_FIXED_INCORPORATE_OPERATOR(int, <);
ALE_FIXED_INCORPORATE_OPERATOR(int, >);
ALE_FIXED_INCORPORATE_OPERATOR(int, !=);
ALE_FIXED_INCORPORATE_OPERATOR(int, ==);

template<class fixed_type, unsigned int N>
ale_fixed<fixed_type, N> fabs(ale_fixed<fixed_type, N> f) {
	if (f < ale_fixed<fixed_type, N>())
		return -f;
	return f;
}

template<class fixed_type, unsigned int N>
ale_fixed<fixed_type, N> pow(ale_fixed<fixed_type, N> f, double d) {
	return pow((double) f, (double) d);
}

/*
 * sqrt() via the Babylonian method.
 *
 * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
 */

template<class fixed_type, unsigned int N>
ale_fixed<fixed_type, N> sqrt(ale_fixed<fixed_type, N> f) {
	ale_fixed<fixed_type, N> guess = f;

	typedef typename ale_fixed<fixed_type, N>::mulbits_t mulbits_t;

	for (int i = 0; i < 5; i++) {
		guess.bits >>= 1;

		if (guess.bits <= 0)
			return 0;

		mulbits_t sf = (mulbits_t) f.bits << (N - 2);
		guess.bits = guess.bits + sf / guess.bits;
	}

	return guess;
}

template<class fixed_type, unsigned int N>
ale_fixed<fixed_type, N> pow(ale_fixed<fixed_type, N> f, ale_fixed<fixed_type, N> d) {
	if (d == 2) 
		return f * f;

	if (d == 1) 
		return f;

	if (d == 0)
		return ale_fixed<fixed_type,N>(1);

	return pow((double) f, (double) d);
}

template<class fixed_type, unsigned int N>
ale_fixed<fixed_type, N> pow(ale_fixed<fixed_type, N> f, int d) {
	if (d == 2)
		return f * f;

	if (d == 1) 
		return f;

	if (d == 0)
		return ale_fixed<fixed_type, N>(1);

	if (d > 1)
		return pow(f, d / 2) * pow(f, d - d / 2);

	if (d < 0)
		return 1 / pow(f, -d);

	assert(0);
}

template<class fixed_type, unsigned int N>
ale_fixed<fixed_type, N> pow(ale_fixed<fixed_type, N> f, unsigned int d) {
	if (d == 2)
		return f * f;

	if (d == 1) 
		return f;

	if (d == 0)
		return ale_fixed<fixed_type, N>(1);

	return pow(f, d / 2) * pow(f, d - d / 2);
}

template<class fixed_type, unsigned int N>
ale_fixed<fixed_type, N> floor(ale_fixed<fixed_type, N> f) {

#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

	if (N == 0
	 || f.bits == ALE_FIXED_POSINF
	 || f.bits == ALE_FIXED_NEGINF
	 || f.bits == ALE_FIXED_NAN)
		return f;
#endif

	ale_fixed<fixed_type, N> result;

	result.bits = (f.bits & ~((1 << N) - 1));

	/*
	 * XXX: This isn't exactly right.
	 */
	if (f.bits < 0)
		result.bits -= 1;

	return result;
}

template<class fixed_type, unsigned int N>
ale_fixed<fixed_type, N> lrintf(ale_fixed<fixed_type, N> f) {

#if DEBUG_FIXED_POINT
		/*
		 * Removed for performance reasons.
		 */

	if (N == 0
	 || f.bits == ALE_FIXED_POSINF
	 || f.bits == ALE_FIXED_NEGINF
	 || f.bits == ALE_FIXED_NAN)
		return f;
#endif

	ale_fixed<fixed_type, N> result = floor(f);

	if (f.bits - result.bits >= (1 << N - 1))
		result.bits += (1 << N);

	return result;
}

template<class fixed_type, unsigned int N>
ale_fixed<fixed_type, N> ceil(ale_fixed<fixed_type, N> f) {
	return -floor(-f);
}

template<class fixed_type, unsigned int N>
int ale_isinf(ale_fixed<fixed_type, N> f) {
	return (f.bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_POSINF);
}

template<class fixed_type, unsigned int N>
int ale_isnan(ale_fixed<fixed_type, N> f) {
	return (f.bits == ALE_FIXED_NAN);
}

template<class fixed_type, unsigned int N>
int finite(ale_fixed<fixed_type, N> f) {
	return (f.bits < ALE_FIXED_POSINF && f.bits > ALE_FIXED_NEGINF);
}

template<class fixed_type, unsigned int N, unsigned int M>
ale_fixed<fixed_type, N> convert_precision(ale_fixed<fixed_type, M> m) {

	/*
	 * XXX: Checks should be added that precision is not
	 * lost from most-significant bits.
	 */

	if (N != M) 
		assert (0);
	
	ale_fixed<fixed_type, N> n;

	n.bits = m.bits << (N - M);

	return n;
}

template<class fixed_type, unsigned int N>
int ale_fixed<fixed_type, N>::casting_disabled = 0;

#undef FIXED16
#undef FIXED32

#endif
