- Main Page
- Classes
- Files

# fixed.hpp

Go to the documentation of this file.

    00001
    00004 #ifndef FIXED_HPP_
    00005 #define FIXED_HPP_
    00006
    00007 #include <cassert>
    00008 #include <cmath>
    00009 #include <iomanip>
    00010 #include <ios>
    00011 #include <istream>
    00012 #include <locale>
    00013 #include <ostream>
    00014 #include <sstream>
    00015 #include <stdexcept>
    00016 #include <string>
    00017
    00018 #include "ioflags.hpp"
    00019
    00024 template<class T, int N>
    00025 class fixed
    00026 {
    00027 public:
    00028     typedef T value_type;
    00029
    00030     static value_type const places = N;
    00031     static value_type const places10;
    00032
    00034     fixed() : value_() {}
    00035
    00039     fixed(value_type integer, value_type fraction);
    00040
    00042     fixed(value_type integer);
    00043
    00045     fixed(double value)
    00046     : value_(static_cast<value_type>(value * places10 + (value < 0 ? -0.5 : 0.5)))
    00047     {}
    00048
    00051     std::string as_string() const;
    00056     template<class Char, class Traits>
    00057     bool read(std::basic_istream<Char, Traits>& strm);
    00059     double as_long_double() const { return static_cast<long double>(value()) / places10; }
    00061     double as_double() const { return static_cast<double>(value()) / places10; }
    00063     float as_float() const { return static_cast<float>(value()) / places10; }
    00067     value_type round() const;
    00068
    00070     value_type integer() const { return value() / places10; }
    00072     value_type fraction() const;
    00073
    00075     fixed& operator+=(fixed f);
    00077     fixed& operator-=(fixed f);
    00079     fixed& operator*=(fixed f);
    00081     fixed& operator/=(fixed f);
    00082
    00084     void negate();
    00085
    00087     fixed& operator++();
    00089     fixed operator++(int);
    00091     fixed& operator--();
    00093     fixed operator--(int);
    00094
    00096     value_type value()    const { return value_; }
    00097 private:
    00099     value_type reduce(value_type frac);
    00100     value_type value_;
    00101 };
    00102
    00103 template<class T, int N>
    00104 typename fixed<T,N>::value_type const fixed<T,N>::places10 = static_cast<typename fixed<T,N>::value_type>(std::pow(10.0, double(places)));
    00105
    00106 // Construct a fixed value from an integer part and a fraction part
    00107 template<class T, int N>
    00108 fixed<T,N>::fixed(value_type integer, value_type fraction)
    00109 {
    00110   if (fraction < T())
    00111     throw std::invalid_argument("negative fraction not allowed");
    00112   fraction = reduce(fraction);
    00113   if (integer < T())
    00114     value_ = integer * places10 - fraction;
    00115   else
    00116     value_ = integer * places10 + fraction;
    00117 }
    00118
    00119 // Construct a fixed value from an integer part with no fraction
    00120 template<class T, int N>
    00121 fixed<T,N>::fixed(value_type integer)
    00122 : value_(integer * places10)
    00123 {}
    00124
    00125 // Get the fraction part
    00126 template<class T, int N>
    00127 typename fixed<T,N>::value_type fixed<T,N>::fraction()
    00128 const
    00129 {
    00130   return std::abs(value()) % places10;
    00131 }
    00132
    00142 template<class T, int N>
    00143 typename fixed<T,N>::value_type fixed<T,N>::reduce(value_type frac)
    00144 {
    00145   // First scan for zero digits on the right.
    00146   value_type f(frac);
    00147   while (f >= places10*10 and f % 10 == 0)
    00148   {
    00149     f /= 10;
    00150   }
    00151
    00152   if (f >= places10*10)
    00153   {
    00154     int x(0);
    00155     // Loop ended because a non-zero digit was seen so Y* > 0.
    00156     // Discard the remaining digits, but keep track of the last
    00157     // digit to be processed (X).
    00158     while (f >= places10)
    00159     {
    00160       x = f % 10;
    00161       f /= 10;
    00162     }
    00163     // Round up if the last digit (X) is 5 or more
    00164     if (x >= 5)
    00165       ++f;
    00166     return f;
    00167   }
    00168   // Else all digits so far are zero. Check how many digits there were,
    00169   // that is, check whether G, and X at least are present.
    00170   else if (f >= places10)
    00171   {
    00172     // Yes, G and X are present. If X == 5, implement banker's rounding.
    00173     // Otherwise, round to nearest.
    00174     int x(f % 10);
    00175     f /= 10;
    00176     assert(f < places10);
    00177     if (x == 5)
    00178     {
    00179       // Yes, so implement banker's rounding.
    00180       if (f % 2 != 0)
    00181         ++f;
    00182       return f;
    00183     }
    00184     else if (x < 5)
    00185     {
    00186       // Round down.
    00187       return f;
    00188     }
    00189     else
    00190     {
    00191       // Round up.
    00192       return f + 1;
    00193     }
    00194   }
    00195   // Not enough digits, so nothing to round.
    00196   assert(frac < places10);
    00197   return frac;
    00198 }
    00199
    00200 // Round off to nearest integer.
    00201 template<class T, int N>
    00202 typename fixed<T,N>::value_type fixed<T,N>::round()
    00203 const
    00204 {
    00205   const value_type frac(fraction());
    00206   int adjust(value() < 0 ? -1 : +1);
    00207   if (frac > places10/2)
    00208     return integer()+adjust;
    00209   else if (frac < places10/2)
    00210     return integer();
    00211   else if (integer() % 2 == 0)
    00212     return integer();
    00213   else
    00214     return integer()+adjust;
    00215 }
    00216
    00217 // Convert to a string using fixed-point notation.
    00218 template<class T, int N>
    00219 std::string fixed<T,N>::as_string()
    00220 const
    00221 {
    00222   std::ostringstream out;
    00223   out << integer() << '.'
    00224       << std::setfill('0') << std::setw(places) << fraction();
    00225   return out.str();
    00226 }
    00227
    00228 template<class T, int N>
    00229 fixed<T,N>& fixed<T,N>::operator+=(fixed f)
    00230 {
    00231   value_ += f.value();
    00232   return *this;
    00233 }
    00234
    00235 template<class T, int N>
    00236 fixed<T,N>& fixed<T,N>::operator-=(fixed f)
    00237 {
    00238   value_ -= f.value();
    00239   return *this;
    00240 }
    00241
    00242 template<class T, int N>
    00243 fixed<T,N>& fixed<T,N>::operator*=(fixed f)
    00244 {
    00245   value_ = (value_ * f.value()) / places10;
    00246   return *this;
    00247 }
    00248
    00249 template<class T, int N>
    00250 fixed<T,N>& fixed<T,N>::operator/=(fixed f)
    00251 {
    00252   value_ = (value_ * places10) / f.value();
    00253   return *this;
    00254 }
    00255
    00256 template<class T, int N>
    00257 void fixed<T,N>::negate()
    00258 {
    00259   value_ = -value_;
    00260 }
    00261
    00262 template<class T, int N>
    00263 fixed<T,N>& fixed<T,N>::operator++()
    00264 {
    00265   value_ += places10;
    00266   return *this;
    00267 }
    00268
    00269 template<class T, int N>
    00270 fixed<T,N> fixed<T,N>::operator++(int)
    00271 {
    00272   fixed result(*this);
    00273   ++*this;
    00274   return result;
    00275 }
    00276
    00277 template<class T, int N>
    00278 fixed<T,N>& fixed<T,N>::operator--()
    00279 {
    00280   value_ -= places10;
    00281   return *this;
    00282 }
    00283
    00284 template<class T, int N>
    00285 fixed<T,N> fixed<T,N>::operator--(int)
    00286 {
    00287   fixed result(*this);
    00288   --*this;
    00289   return result;
    00290 }
    00291
    00292 template<class T, int N>
    00293 template<class Char, class Traits>
    00294 bool fixed<T,N>::read(std::basic_istream<Char, Traits>& strm)
    00295 {
    00296   ioflags flags(strm);
    00297
    00298   value_type integer;
    00299   char decimal;
    00300   if (not (strm >> integer))
    00301     return false;
    00302   strm.unsetf(std::ios_base::skipws);
    00303   if (not (strm >> decimal) or decimal != '.')
    00304   {
    00305     // Just an integer is fine. Push back the non-decimal character,
    00306     // if there is one, and reset the stream flags to show that
    00307     // reading the fixed value succeeded.
    00308     strm.unget();
    00309     strm.clear(strm.rdstate() & ~strm.failbit);
    00310     value_ = integer * places10;
    00311     return true;
    00312   }
    00313   else
    00314   {
    00315     value_type fraction(0);
    00316     char c;
    00317     int p(0);
    00318     // Read one extra place for round-off.
    00319     for (;
    00320           p != places+1 and strm >> c and std::isdigit(c, strm.getloc());
    00321           ++p)
    00322     {
    00323       fraction = fraction * 10 + (c - '0');
    00324     }
    00325     // Pad out to the requisite number of decimal places.
    00326     for (; p < places; ++p)
    00327       fraction = fraction * 10;
    00328     // If the loop terminated because the maximum number of decimal
    00329     // places were read, keep reading the stream to discard excees digits.
    00330     while (strm and std::isdigit(c, strm.getloc()))
    00331       strm >> c;
    00332     // Push back the last, non-digit character read from the stream.
    00333     // If the stream reached EOF, unget() is harmless.
    00334     strm.unget();
    00335     // Clear failbit because even if reading a character or whatever
    00336     // failed, reading the fixed value did not.
    00337     strm.clear(strm.rdstate() & ~strm.failbit);
    00338     fraction = reduce(fraction);
    00339     if (integer < 0)
    00340       value_ = integer * places10 - fraction;
    00341     else
    00342       value_ = integer * places10 + fraction;
    00343   }
    00344   return true;
    00345 }
    00346
    00348 template<class T, int N, class Char, class Traits>
    00349 std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& strm, fixed<T,N>& f)
    00350 {
    00351   if (not f.read(strm))
    00352     strm.setstate(strm.failbit);
    00353   return strm;
    00354 }
    00355
    00357 template<class T, int N, class Char, class Traits>
    00358 std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& strm, fixed<T,N> f)
    00359 {
    00360   strm << f.as_string();
    00361   return strm;
    00362 }
    00363
    00365 template<class T, int N>
    00366 fixed<T,N> operator+(fixed<T,N> a, fixed<T,N> b)
    00367 {
    00368   a += b;
    00369   return a;
    00370 }
    00371
    00373 template<class T, int N>
    00374 fixed<T,N> operator-(fixed<T,N> a, fixed<T,N> b)
    00375 {
    00376   a -= b;
    00377   return a;
    00378 }
    00379
    00381 template<class T, int N>
    00382 fixed<T,N> operator*(fixed<T,N> a, fixed<T,N> b)
    00383 {
    00384   a *= b;
    00385   return a;
    00386 }
    00387
    00389 template<class T, int N>
    00390 fixed<T,N> operator/(fixed<T,N> a, fixed<T,N> b)
    00391 {
    00392   a /= b;
    00393   return a;
    00394 }
    00395
    00397 template<class T, int N>
    00398 fixed<T,N> operator-(fixed<T,N> a)
    00399 {
    00400   a.negate();
    00401   return a;
    00402 }
    00403
    00405 template<class T, int N>
    00406 bool operator==(fixed<T,N> a, fixed<T,N> b)
    00407 {
    00408   return a.value() == b.value();
    00409 }
    00411 template<class T, int N>
    00412 bool operator==(T a, fixed<T,N> b)
    00413 {
    00414   return a == b.value();
    00415 }
    00417 template<class T, int N>
    00418 bool operator==(fixed<T,N> a, T b)
    00419 {
    00420   return a.value() == b;
    00421 }
    00422
    00424 template<class T, int N>
    00425 bool operator!=(fixed<T,N> a, fixed<T,N> b)
    00426 {
    00427   return not (a == b);
    00428 }
    00430 template<class T, int N>
    00431 bool operator!=(T a, fixed<T,N> b)
    00432 {
    00433   return not (a == b);
    00434 }
    00436 template<class T, int N>
    00437 bool operator!=(fixed<T,N> a, T b)
    00438 {
    00439   return not (a == b);
    00440 }
    00441
    00443 template<class T, int N>
    00444 bool operator<(fixed<T,N> a, fixed<T,N> b)
    00445 {
    00446   return a.value() < b.value();
    00447 }
    00449 template<class T, int N>
    00450 bool operator<(T a, fixed<T,N> b)
    00451 {
    00452   return a < b.value();
    00453 }
    00455 template<class T, int N>
    00456 bool operator<(fixed<T,N> a, T b)
    00457 {
    00458   return a.value() < b;
    00459 }
    00460
    00462 template<class T, int N>
    00463 bool operator>(fixed<T,N> a, fixed<T,N> b)
    00464 {
    00465   return b < a;
    00466 }
    00468 template<class T, int N>
    00469 bool operator>(T a, fixed<T,N> b)
    00470 {
    00471   return b < a;
    00472 }
    00474 template<class T, int N>
    00475 bool operator>(fixed<T,N> a, T b)
    00476 {
    00477   return b < a;
    00478 }
    00479
    00481 template<class T, int N>
    00482 bool operator<=(fixed<T,N> a, fixed<T,N> b)
    00483 {
    00484   return not (b < a);
    00485 }
    00487 template<class T, int N>
    00488 bool operator<=(T a, fixed<T,N> b)
    00489 {
    00490   return not (b < a);
    00491 }
    00493 template<class T, int N>
    00494 bool operator<=(fixed<T,N> a, T b)
    00495 {
    00496   return not (b < a);
    00497 }
    00498
    00500 template<class T, int N>
    00501 bool operator>=(fixed<T,N> a, fixed<T,N> b)
    00502 {
    00503   return not (a < b);
    00504 }
    00506 template<class T, int N>
    00507 bool operator>=(T a, fixed<T,N> b)
    00508 {
    00509   return not (a < b);
    00510 }
    00512 template<class T, int N>
    00513 bool operator>=(fixed<T,N> a, T b)
    00514 {
    00515   return not (a < b);
    00516 }
    00517
    00518 #endif