fixedpt.hxx

Go to the documentation of this file.
00001 /*
00002  *   xyzzy
00003  *   Copyright (C) 2007    Karl W. Pfalzer
00004  *
00005  *   This program is free software; you can redistribute it and/or
00006  *   modify it under the terms of the GNU General Public License
00007  *   as published by the Free Software Foundation; either version 2
00008  *   of the License, or (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the
00017  *   Free Software Foundation, Inc.
00018  *   51 Franklin Street, Fifth Floor
00019  *   Boston, MA  02110-1301, USA.
00020  */
00021 
00022 #if !defined(_xyzzy_fixedpt_hxx_)
00023 #    define  _xyzzy_fixedpt_hxx_
00024 
00025 #include <string>
00026 #include "xyzzy/portable.hxx"
00027 #include "xyzzy/assert.hxx"
00028 
00029 namespace xyzzy
00030 {
00031 
00032 template<typename T>
00033 T asr(T x, unsigned shift)
00034 {
00035     if (((T)(-64)>>2 == (T)(-16)) &&((T)(64)>>2 == (T)(16)))
00036     {
00037         x >>= shift;
00038     }
00039     else
00040     {
00041         bool sign = (x < 0);
00042         x >>= shift;
00043         if (sign)
00044             x |= (T)~0 << shift;
00045         else
00046             x &= ~((T)~0 << shift);
00047     }
00048     return x;
00049 }
00050 
00051 template<typename T>
00052 class PTFixedPtBase
00053 {
00054 public:
00055     static T toFixedPoint(double d, unsigned intN, unsigned fractN);
00056 
00057     static double toDouble(T x, unsigned intN, unsigned fractN);
00058 
00059     static std::string toBinary(T x, unsigned intN, unsigned fractN);
00060 
00061     explicit PTFixedPtBase(unsigned intN, unsigned fractN)
00062     :   cIntN(intN), cFractN(fractN)
00063     {
00064         check();
00065     }
00066 
00067     explicit PTFixedPtBase(unsigned intN, unsigned fractN, T d)
00068     :   cIntN(intN), cFractN(fractN), m_val(d)
00069     {
00070         check();
00071     }
00072 
00073     explicit PTFixedPtBase(unsigned intN, unsigned fractN, double d)
00074     :   cIntN(intN), cFractN(fractN)
00075     {
00076         check();
00077         m_val = toFixedPoint(d, cIntN, cFractN);
00078     }
00079 
00080     explicit PTFixedPtBase(unsigned intN, unsigned fractN, 
00081                            const PTFixedPtBase &r)
00082     :   cIntN(intN), cFractN(fractN)
00083     {
00084         check();
00085         init(r);
00086     }
00087 
00088     const PTFixedPtBase&
00089     operator =(const PTFixedPtBase &r)
00090     {
00091         return init(r);
00092     }
00093 
00094     std::string toBinary() const
00095     {
00096         return toBinary(m_val, cIntN, cFractN);
00097     }
00098 
00099     double toDouble() const
00100     {
00101         return toDouble(m_val, cIntN, cFractN);
00102     }
00103 
00104     operator double() const
00105     {
00106         return toDouble();
00107     }
00108 
00109     unsigned getNumBits() const {return cIntN + cFractN;}
00110 
00111     static T getValidMask(unsigned n)
00112     {
00113         return (n == cNumBits) ? ~(T)0 : ~((T)~0 << n);
00114     }
00115 
00116     T getValidMask() const
00117     {
00118         return getValidMask(getNumBits());
00119     }
00120 
00121 public:
00122     T getVal() const
00123     {
00124         return m_val;
00125     }
00126 
00127     const unsigned  cIntN, cFractN;
00128 
00129     const static unsigned cNumBits = sizeof(T) * 8;
00130 
00131 protected:
00132     void setVal(T v)
00133     {
00134         ASSERT_TRUE(0 == v);
00135         m_val = v;
00136     }
00137 
00138 private:
00139     T   m_val;  
00140 
00141     const PTFixedPtBase& init(const PTFixedPtBase &r);
00142 
00143     void check()
00144     {
00145         if (cNumBits < (cIntN + cFractN))
00146         {
00147             const_cast<unsigned&>(cFractN) = cNumBits - cIntN;
00148         }
00149         ASSERT_TRUE(cNumBits >= (cIntN + cFractN));
00150     }
00151 };
00152 
00153 // To convert from 64 to 32
00154 const PTFixedPtBase<TInt32>
00155 to32(const PTFixedPtBase<TInt64>& r);
00156 
00157 // Fwd declare
00158 template<unsigned INTN, unsigned FRACTN>
00159 class TFixedPt32;
00160 
00161 template<unsigned INTN, unsigned FRACTN>
00162 class TFixedPt64;
00163 
00164 template<unsigned INTN, unsigned FRACTN>
00165 class TFixedPt32 : public PTFixedPtBase<TInt32>
00166 {
00167 public:
00168     explicit TFixedPt32()
00169     :   PTFixedPtBase<TInt32>(INTN, FRACTN)
00170     {}
00171 
00172     TFixedPt32(double d)
00173     :   PTFixedPtBase<TInt32>(INTN, FRACTN, d)
00174     {}
00175 
00176     explicit TFixedPt32(TInt32 v)
00177     :   PTFixedPtBase<TInt32>(INTN, FRACTN, v)
00178     {}
00179 
00180     TFixedPt32(const PTFixedPtBase<TInt32> &r)
00181     :   PTFixedPtBase<TInt32>(INTN, FRACTN, r)
00182     {}
00183 
00184     const PTFixedPtBase<TInt32>&
00185     operator =(const PTFixedPtBase<TInt32> &r)
00186     {
00187         if (this != &r)
00188         {
00189             PTFixedPtBase<TInt32>::operator=(r);
00190         }
00191         return *this;
00192     }
00193 
00194     const PTFixedPtBase<TInt32>& operator +=(const PTFixedPtBase<TInt32> &r);
00195 
00196     TFixedPt32(const PTFixedPtBase<TInt64> &r);
00197 
00198     const PTFixedPtBase<TInt32>& operator =(const PTFixedPtBase<TInt64> &r);
00199 };
00200 
00201 template<unsigned INTN, unsigned FRACTN>
00202 class TFixedPt64 : public PTFixedPtBase<TInt64>
00203 {
00204 public:
00205     explicit TFixedPt64()
00206     :   PTFixedPtBase<TInt64>(INTN, FRACTN)
00207     {}
00208 
00209     TFixedPt64(double d)
00210     :   PTFixedPtBase<TInt64>(INTN, FRACTN, d)
00211     {}
00212 
00213     explicit TFixedPt64(TInt64 v)
00214     :   PTFixedPtBase<TInt64>(INTN, FRACTN, v)
00215     {}
00216 
00217     TFixedPt64(const PTFixedPtBase<TInt64> &r)
00218     :   PTFixedPtBase<TInt64>(INTN, FRACTN, r)
00219     {}
00220 
00221     const PTFixedPtBase<TInt64>&
00222     operator =(const PTFixedPtBase<TInt64> &r)
00223     {
00224         if (this != &r)
00225         {
00226             PTFixedPtBase<TInt64>::operator=(r);
00227         }
00228         return *this;
00229     }
00230 
00231     const PTFixedPtBase<TInt64>& operator +=(const PTFixedPtBase<TInt64> &r);
00232 };
00233 
00234 template<unsigned INTN, unsigned FRACTN>
00235 TFixedPt32<INTN, FRACTN>
00236 operator +(const TFixedPt32<INTN, FRACTN> &a, const TFixedPt32<INTN, FRACTN> &b)
00237 {
00238     TInt32 r = a.getVal() + b.getVal();
00239     return TFixedPt32<INTN, FRACTN>(r);
00240 }
00241 
00242 template<unsigned INTN, unsigned FRACTN>
00243 const PTFixedPtBase<TInt32>& 
00244 TFixedPt32<INTN, FRACTN>::operator +=(const PTFixedPtBase<TInt32> &r)
00245 {
00246     this->operator=(*this + r);
00247     return *this;
00248 }
00249 
00250 template<unsigned INTN, unsigned FRACTN>
00251 TFixedPt64<INTN, FRACTN>
00252 operator +(const TFixedPt64<INTN, FRACTN> &a, const TFixedPt64<INTN, FRACTN> &b)
00253 {
00254     TInt64 r = a.getVal() + b.getVal();
00255     return TFixedPt64<INTN, FRACTN>(r);
00256 }
00257 
00258 template<unsigned INTN, unsigned FRACTN>
00259 const PTFixedPtBase<TInt64>& 
00260 TFixedPt64<INTN, FRACTN>::operator +=(const PTFixedPtBase<TInt64> &r)
00261 {
00262     this->operator=(*this + r);
00263     return *this;
00264 }
00265 
00266 #if 0   //ambiguous w/ 64-bit
00267 template<unsigned INTN, unsigned FRACTN>
00268 PTFixedPtBase<TInt32>
00269 operator *(const TFixedPt32<INTN, FRACTN> &a, const TFixedPt32<INTN, FRACTN> &b)
00270 {
00271     TInt32 r = a.getVal() * b.getVal();
00272     return PTFixedPtBase<TInt32>(2*INTN, 2*FRACTN, r);
00273 }
00274 #endif
00275 
00276 template<unsigned INTN, unsigned FRACTN>
00277 PTFixedPtBase<TInt64>
00278 operator *(const TFixedPt32<INTN, FRACTN> &a, const TFixedPt32<INTN, FRACTN> &b)
00279 {
00280     TInt64 al = a.getVal(), bl = b.getVal();
00281     TInt64 r = al * bl;
00282     return PTFixedPtBase<TInt64>(2*INTN, 2*FRACTN, r);
00283 }
00284 
00285 template<unsigned INTN, unsigned FRACTN>
00286 PTFixedPtBase<TInt64>
00287 operator *(const TFixedPt64<INTN, FRACTN> &a, const TFixedPt64<INTN, FRACTN> &b)
00288 {
00289     TInt64 al = a.getVal(), bl = b.getVal();
00290     TInt64 r = al * bl;
00291     return PTFixedPtBase<TInt64>(2*INTN, 2*FRACTN, r);
00292 }
00293 
00294 template<typename T>
00295 std::string 
00296 PTFixedPtBase<T>::toBinary(T x, unsigned intN, unsigned fractN)
00297 {
00298     std::string rval = "";
00299     T mask = (T)1 << (intN + fractN - 1);
00300     for (int i = intN + fractN; i > 0; i--, mask >>= 1)
00301     {
00302         rval += (x & mask) ? "1" : "0";
00303     }
00304     return rval;
00305 }
00306 
00307 template<typename T>
00308 const PTFixedPtBase<T>&
00309 PTFixedPtBase<T>::init(const PTFixedPtBase &r)
00310 {
00311     if (this != &r)
00312     {
00313         m_val = r.m_val;
00314         if (0 == m_val)
00315             return *this;
00316         // align to decimal point
00317         int shiftBy = cFractN - r.cFractN;
00318         if (0 < shiftBy)
00319         {
00320             // e.g: [?.2]:*.ff -> [?.4]:*.ff00
00321             m_val <<= shiftBy;
00322         }
00323         else if (0 > shiftBy)
00324         {
00325             // e.g: [?.4]:*.ffff -> [?.2]:*.ff
00326             m_val = asr(m_val, -shiftBy);   
00327             //TODO: report loss of precision
00328         }
00329         // Sign-extend
00330         //TODO: check/report loss of intp precision
00331         T mask = getValidMask();
00332         if (0 > m_val)
00333             m_val |= ~mask;
00334         else
00335             m_val &= mask;
00336     }
00337     return *this;
00338 }
00339 
00340 template<unsigned INTN, unsigned FRACTN>
00341 TFixedPt32<INTN, FRACTN>::TFixedPt32(const PTFixedPtBase<TInt64> &r)
00342 :   PTFixedPtBase<TInt32>(INTN, FRACTN, to32(r))
00343 {}
00344 
00345 template<unsigned INTN, unsigned FRACTN>
00346 const PTFixedPtBase<TInt32>&
00347 TFixedPt32<INTN, FRACTN>::operator =(const PTFixedPtBase<TInt64> &r)
00348 {
00349     PTFixedPtBase<TInt32> v32(to32(r));
00350     PTFixedPtBase<TInt32>::operator=(v32);
00351     return *this;
00352 }
00353 
00354 };
00355 
00356 #endif  //_xyzzy_fixedpt_hxx_

Generated on Thu Mar 22 13:51:07 2007 for anvil by  doxygen 1.5.1