- Main Page
- Namespaces
- 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 #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