00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00154 const PTFixedPtBase<TInt32>
00155 to32(const PTFixedPtBase<TInt64>& r);
00156
00157
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
00317 int shiftBy = cFractN - r.cFractN;
00318 if (0 < shiftBy)
00319 {
00320
00321 m_val <<= shiftBy;
00322 }
00323 else if (0 > shiftBy)
00324 {
00325
00326 m_val = asr(m_val, -shiftBy);
00327
00328 }
00329
00330
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_