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 #include "power10.hpp"
00020 
00025 template<class T, int N>
00026 class fixed
00027 {
00028 public:
00029     typedef T value_type;                    
00030 
00031     static value_type const places = N;      
00032     static value_type const places10 = power10<N>::value;       
00033 
00035     fixed() : value_() {}
00036 
00042     fixed(value_type integer, value_type fraction);
00043 
00046     fixed(value_type integer);
00047 
00050     fixed(double value)
00051     : value_(static_cast<value_type>(value * places10 + (value < 0 ? -0.5 : 0.5)))
00052     {}
00053 
00056     std::string as_string() const;
00061     template<class Char, class Traits>
00062     bool read(std::basic_istream<Char, Traits>& strm);
00064     double as_long_double() const { return static_cast<long double>(value()) / places10; }
00066     double as_double() const { return static_cast<double>(value()) / places10; }
00068     float as_float() const { return static_cast<float>(value()) / places10; }
00072     value_type round() const;
00073 
00075     value_type integer() const { return value() / places10; }
00077     value_type fraction() const;
00078 
00081     fixed& operator+=(fixed f);
00084     fixed& operator-=(fixed f);
00087     fixed& operator*=(fixed f);
00090     fixed& operator*=(value_type v);
00093     fixed& operator/=(fixed f);
00096     fixed& operator/=(value_type v);
00097 
00099     void negate();
00100 
00102     fixed& operator++();
00104     fixed operator++(int);
00106     fixed& operator--();
00108     fixed operator--(int);
00109 
00111     value_type value()    const { return value_; }
00112 private:
00114     value_type reduce(value_type frac);
00115     value_type value_;
00116 };
00117 
00118 // Construct a fixed value from an integer part and a fraction part
00119 template<class T, int N>
00120 fixed<T,N>::fixed(value_type integer, value_type fraction)
00121 {
00122   if (fraction < T())
00123     throw std::invalid_argument("negative fraction not allowed");
00124   fraction = reduce(fraction);
00125   if (integer < T())
00126     value_ = integer * places10 - fraction;
00127   else
00128     value_ = integer * places10 + fraction;
00129 }
00130 
00131 // Construct a fixed value from an integer part with no fraction
00132 template<class T, int N>
00133 fixed<T,N>::fixed(value_type integer)
00134 : value_(integer * places10)
00135 {}
00136 
00137 // Get the fraction part
00138 template<class T, int N>
00139 typename fixed<T,N>::value_type fixed<T,N>::fraction()
00140 const
00141 {
00142   return std::abs(value()) % places10;
00143 }
00144 
00154 template<class T, int N>
00155 typename fixed<T,N>::value_type fixed<T,N>::reduce(value_type frac)
00156 {
00157   // First scan for zero digits on the right.
00158   value_type f(frac);
00159   while (f >= places10*10 and f % 10 == 0)
00160   {
00161     f /= 10;
00162   }
00163 
00164   if (f >= places10*10)
00165   {
00166     int x(0);
00167     // Loop ended because a non-zero digit was seen so Y* > 0.
00168     // Discard the remaining digits, but keep track of the last
00169     // digit to be processed (X).
00170     while (f >= places10)
00171     {
00172       x = f % 10;
00173       f /= 10;
00174     }
00175     // Round up if the last digit (X) is 5 or more
00176     if (x >= 5)
00177       ++f;
00178     return f;
00179   }
00180   // Else all digits so far are zero. Check how many digits there were,
00181   // that is, check whether G, and X at least are present.
00182   else if (f >= places10)
00183   {
00184     // Yes, G and X are present. If X == 5, implement banker's rounding.
00185     // Otherwise, round to nearest.
00186     int x(f % 10);
00187     f /= 10;
00188     assert(f < places10);
00189     if (x == 5)
00190     {
00191       // Yes, so implement banker's rounding.
00192       if (f % 2 != 0)
00193         ++f;
00194       return f;
00195     }
00196     else if (x < 5)
00197     {
00198       // Round down.
00199       return f;
00200     }
00201     else
00202     {
00203       // Round up.
00204       return f + 1;
00205     }
00206   }
00207   // Not enough digits, so nothing to round.
00208   assert(frac < places10);
00209   return frac;
00210 }
00211 
00212 // Round off to nearest integer.
00213 template<class T, int N>
00214 typename fixed<T,N>::value_type fixed<T,N>::round()
00215 const
00216 {
00217   const value_type frac(fraction());
00218   int adjust(value() < 0 ? -1 : +1);
00219   if (frac > places10/2)
00220     return integer()+adjust;
00221   else if (frac < places10/2)
00222     return integer();
00223   else if (integer() % 2 == 0)
00224     return integer();
00225   else
00226     return integer()+adjust;
00227 }
00228 
00229 // Convert to a string using fixed-point notation.
00230 template<class T, int N>
00231 std::string fixed<T,N>::as_string()
00232 const
00233 {
00234   std::ostringstream out;
00235   out << integer() << '.'
00236       << std::setfill('0') << std::setw(places) << fraction();
00237   return out.str();
00238 }
00239 
00240 template<class T, int N>
00241 fixed<T,N>& fixed<T,N>::operator+=(fixed f)
00242 {
00243   value_ += f.value();
00244   return *this;
00245 }
00246 
00247 template<class T, int N>
00248 fixed<T,N>& fixed<T,N>::operator-=(fixed f)
00249 {
00250   value_ -= f.value();
00251   return *this;
00252 }
00253 
00254 template<class T, int N>
00255 fixed<T,N>& fixed<T,N>::operator*=(fixed f)
00256 {
00257   value_ = (value_ * f.value()) / places10;
00258   return *this;
00259 }
00260 
00261 template<class T, int N>
00262 fixed<T,N>& fixed<T,N>::operator*=(value_type v)
00263 {
00264   value_ *= v;
00265   return *this;
00266 }
00267 
00268 template<class T, int N>
00269 fixed<T,N>& fixed<T,N>::operator/=(fixed f)
00270 {
00271   value_ = (value_ * places10) / f.value();
00272   return *this;
00273 }
00274 
00275 template<class T, int N>
00276 fixed<T,N>& fixed<T,N>::operator/=(value_type v)
00277 {
00278   value_ /= v;
00279   return *this;
00280 }
00281 
00282 template<class T, int N>
00283 void fixed<T,N>::negate()
00284 {
00285   value_ = -value_;
00286 }
00287 
00288 template<class T, int N>
00289 fixed<T,N>& fixed<T,N>::operator++()
00290 {
00291   value_ += places10;
00292   return *this;
00293 }
00294 
00295 template<class T, int N>
00296 fixed<T,N> fixed<T,N>::operator++(int)
00297 {
00298   fixed result(*this);
00299   ++*this;
00300   return result;
00301 }
00302 
00303 template<class T, int N>
00304 fixed<T,N>& fixed<T,N>::operator--()
00305 {
00306   value_ -= places10;
00307   return *this;
00308 }
00309 
00310 template<class T, int N>
00311 fixed<T,N> fixed<T,N>::operator--(int)
00312 {
00313   fixed result(*this);
00314   --*this;
00315   return result;
00316 }
00317 
00318 template<class T, int N>
00319 template<class Char, class Traits>
00320 bool fixed<T,N>::read(std::basic_istream<Char, Traits>& strm)
00321 {
00322   ioflags flags(strm);
00323 
00324   value_type integer;
00325   char decimal;
00326   if (not (strm >> integer))
00327     return false;
00328   strm.unsetf(std::ios_base::skipws);
00329   if (not (strm >> decimal) or decimal != '.')
00330   {
00331     // Just an integer is fine. Push back the non-decimal character,
00332     // if there is one, and reset the stream flags to show that
00333     // reading the fixed value succeeded.
00334     strm.unget();
00335     strm.clear(strm.rdstate() & ~strm.failbit);
00336     value_ = integer * places10;
00337     return true;
00338   }
00339   else
00340   {
00341     value_type fraction(0);
00342     char c;
00343     int p(0);
00344     // Read one extra place for round-off.
00345     for (;
00346           p != places+1 and strm >> c and std::isdigit(c, strm.getloc());
00347           ++p)
00348     {
00349       fraction = fraction * 10 + (c - '0');
00350     }
00351     // Pad out to the requisite number of decimal places.
00352     for (; p < places; ++p)
00353       fraction = fraction * 10;
00354     // If the loop terminated because the maximum number of decimal
00355     // places were read, keep reading the stream to discard excees digits.
00356     while (strm and std::isdigit(c, strm.getloc()))
00357       strm >> c;
00358     // Push back the last, non-digit character read from the stream.
00359     // If the stream reached EOF, unget() is harmless.
00360     strm.unget();
00361     // Clear failbit because even if reading a character or whatever
00362     // failed, reading the fixed value did not.
00363     strm.clear(strm.rdstate() & ~strm.failbit);
00364     fraction = reduce(fraction);
00365     if (integer < 0)
00366       value_ = integer * places10 - fraction;
00367     else
00368       value_ = integer * places10 + fraction;
00369   }
00370   return true;
00371 }
00372 
00376 template<class T, int N, class Char, class Traits>
00377 std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& strm, fixed<T,N>& f)
00378 {
00379   if (not f.read(strm))
00380     strm.setstate(strm.failbit);
00381   return strm;
00382 }
00383 
00387 template<class T, int N, class Char, class Traits>
00388 std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& strm, fixed<T,N> f)
00389 {
00390   strm << f.as_string();
00391   return strm;
00392 }
00393 
00397 template<class T, int N>
00398 fixed<T,N> operator+(fixed<T,N> a, fixed<T,N> b)
00399 {
00400   a += b;
00401   return a;
00402 }
00403 
00407 template<class T, int N>
00408 fixed<T,N> operator+(fixed<T,N> a, T b)
00409 {
00410   a += fixed<T,N>(b);
00411   return a;
00412 }
00413 
00417 template<class T, int N>
00418 fixed<T,N> operator+(T a, fixed<T,N> b)
00419 {
00420   b += a;
00421   return b;
00422 }
00423 
00427 template<class T, int N>
00428 fixed<T,N> operator-(fixed<T,N> a, fixed<T,N> b)
00429 {
00430   a -= b;
00431   return a;
00432 }
00433 
00437 template<class T, int N>
00438 fixed<T,N> operator-(fixed<T,N> a, T b)
00439 {
00440   a -= fixed<T,N>(b);
00441   return a;
00442 }
00443 
00447 template<class T, int N>
00448 fixed<T,N> operator-(T a, fixed<T,N> b)
00449 {
00450   b += -a;
00451   return -b;
00452 }
00453 
00457 template<class T, int N>
00458 fixed<T,N> operator*(fixed<T,N> a, fixed<T,N> b)
00459 {
00460   a *= b;
00461   return a;
00462 }
00463 
00467 template<class T, int N>
00468 fixed<T,N> operator*(fixed<T,N> a, T b)
00469 {
00470   a *= b;
00471   return a;
00472 }
00473 
00477 template<class T, int N>
00478 fixed<T,N> operator*(T a, fixed<T,N> b)
00479 {
00480   b *= a;
00481   return b;
00482 }
00483 
00487 template<class T, int N>
00488 fixed<T,N> operator/(fixed<T,N> a, fixed<T,N> b)
00489 {
00490   a /= b;
00491   return a;
00492 }
00493 
00497 template<class T, int N>
00498 fixed<T,N> operator/(fixed<T,N> a, T b)
00499 {
00500   a /= b;
00501   return a;
00502 }
00503 
00507 template<class T, int N>
00508 fixed<T,N> operator/(T a, fixed<T,N> b)
00509 {
00510   fixed<T,N> tmp(a);
00511   tmp /= b;
00512   return tmp;
00513 }
00514 
00517 template<class T, int N>
00518 fixed<T,N> operator-(fixed<T,N> a)
00519 {
00520   a.negate();
00521   return a;
00522 }
00523 
00527 template<class T, int N>
00528 bool operator==(fixed<T,N> a, fixed<T,N> b)
00529 {
00530   return a.value() == b.value();
00531 }
00535 template<class T, int N>
00536 bool operator==(T a, fixed<T,N> b)
00537 {
00538   return a == b.value();
00539 }
00543 template<class T, int N>
00544 bool operator==(fixed<T,N> a, T b)
00545 {
00546   return a.value() == b;
00547 }
00548 
00552 template<class T, int N>
00553 bool operator!=(fixed<T,N> a, fixed<T,N> b)
00554 {
00555   return not (a == b);
00556 }
00560 template<class T, int N>
00561 bool operator!=(T a, fixed<T,N> b)
00562 {
00563   return not (a == b);
00564 }
00568 template<class T, int N>
00569 bool operator!=(fixed<T,N> a, T b)
00570 {
00571   return not (a == b);
00572 }
00573 
00577 template<class T, int N>
00578 bool operator<(fixed<T,N> a, fixed<T,N> b)
00579 {
00580   return a.value() < b.value();
00581 }
00585 template<class T, int N>
00586 bool operator<(T a, fixed<T,N> b)
00587 {
00588   return a < b.value();
00589 }
00593 template<class T, int N>
00594 bool operator<(fixed<T,N> a, T b)
00595 {
00596   return a.value() < b;
00597 }
00598 
00602 template<class T, int N>
00603 bool operator>(fixed<T,N> a, fixed<T,N> b)
00604 {
00605   return b < a;
00606 }
00610 template<class T, int N>
00611 bool operator>(T a, fixed<T,N> b)
00612 {
00613   return b < a;
00614 }
00618 template<class T, int N>
00619 bool operator>(fixed<T,N> a, T b)
00620 {
00621   return b < a;
00622 }
00623 
00627 template<class T, int N>
00628 bool operator<=(fixed<T,N> a, fixed<T,N> b)
00629 {
00630   return not (b < a);
00631 }
00635 template<class T, int N>
00636 bool operator<=(T a, fixed<T,N> b)
00637 {
00638   return not (b < a);
00639 }
00643 template<class T, int N>
00644 bool operator<=(fixed<T,N> a, T b)
00645 {
00646   return not (b < a);
00647 }
00648 
00652 template<class T, int N>
00653 bool operator>=(fixed<T,N> a, fixed<T,N> b)
00654 {
00655   return not (a < b);
00656 }
00660 template<class T, int N>
00661 bool operator>=(T a, fixed<T,N> b)
00662 {
00663   return not (a < b);
00664 }
00668 template<class T, int N>
00669 bool operator>=(fixed<T,N> a, T b)
00670 {
00671   return not (a < b);
00672 }
00673 
00674 #endif

Generated on Sun Nov 30 09:53:22 2008 for Exploring C++ - Final Forms of Key Examples by  doxygen 1.5.3