// Copyright 2007 David Hilvert , // /* 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 #include #include #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 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 operator ale_fixed() const { ale_fixed 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) > sizeof(ale_fixed)) { 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 ale_fixed(const ale_fixed &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) > sizeof(ale_fixed)) { 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::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 \ return_value operator op(double a, const ale_fixed &f) { \ ale_fixed g(a); \ return g.operator op(f); \ } \ \ template \ return_value operator op(int a, const ale_fixed &f) { \ return (ale_fixed) a op f; \ } \ \ template \ return_value operator op(unsigned int a, const ale_fixed &f) { \ return (ale_fixed) a op f; \ } \ #define STDARGS ale_fixed 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 ale_fixed fabs(ale_fixed f) { if (f < ale_fixed()) return -f; return f; } template ale_fixed pow(ale_fixed 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 ale_fixed sqrt(ale_fixed f) { ale_fixed guess = f; typedef typename ale_fixed::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 ale_fixed pow(ale_fixed f, ale_fixed d) { if (d == 2) return f * f; if (d == 1) return f; if (d == 0) return ale_fixed(1); return pow((double) f, (double) d); } template ale_fixed pow(ale_fixed f, int d) { if (d == 2) return f * f; if (d == 1) return f; if (d == 0) return ale_fixed(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 ale_fixed pow(ale_fixed f, unsigned int d) { if (d == 2) return f * f; if (d == 1) return f; if (d == 0) return ale_fixed(1); return pow(f, d / 2) * pow(f, d - d / 2); } template ale_fixed floor(ale_fixed 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 result; result.bits = (f.bits & ~((1 << N) - 1)); /* * XXX: This isn't exactly right. */ if (f.bits < 0) result.bits -= 1; return result; } template ale_fixed lrintf(ale_fixed 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 result = floor(f); if (f.bits - result.bits >= (1 << N - 1)) result.bits += (1 << N); return result; } template ale_fixed ceil(ale_fixed f) { return -floor(-f); } template int ale_isinf(ale_fixed f) { return (f.bits == ALE_FIXED_NEGINF || f.bits == ALE_FIXED_POSINF); } template int ale_isnan(ale_fixed f) { return (f.bits == ALE_FIXED_NAN); } template int finite(ale_fixed f) { return (f.bits < ALE_FIXED_POSINF && f.bits > ALE_FIXED_NEGINF); } template ale_fixed convert_precision(ale_fixed m) { /* * XXX: Checks should be added that precision is not * lost from most-significant bits. */ if (N != M) assert (0); ale_fixed n; n.bits = m.bits << (N - M); return n; } template int ale_fixed::casting_disabled = 0; #undef FIXED16 #undef FIXED32 #endif