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

Generated on Sun Nov 30 10:03:13 2008 for Project 3 - Currency Type by  doxygen 1.5.3