- Main Page
- Classes
- Files

# fixed.cpp

    00001 #include <cassert>
    00002 #include <cstdlib>
    00003 #include <iomanip>
    00004 #include <istream>
    00005 #include <locale>
    00006 #include <ostream>
    00007 #include <sstream>
    00008 #include <sstream>
    00009 #include <stdexcept>
    00010 #include <string>
    00011
    00012 #include "fixed.hpp"
    00013 #include "ioflags.hpp"
    00014
    00015 // Construct a fixed value from an integer part and a fraction part
    00016 fixed::fixed(value_type integer, value_type fraction)
    00017 {
    00018   if (fraction < 0)
    00019     throw std::invalid_argument("negative fraction not allowed");
    00020   fraction = reduce(fraction);
    00021   if (integer < 0)
    00022     value_ = integer * places10 - fraction;
    00023   else
    00024     value_ = integer * places10 + fraction;
    00025 }
    00026
    00027 // Construct a fixed value from an integer part with no fraction
    00028 fixed::fixed(value_type integer)
    00029 : value_(integer * places10)
    00030 {}
    00031
    00032 // Get the fraction part
    00033 fixed::value_type fixed::fraction()
    00034 const
    00035 {
    00036   return std::abs(value()) % places10;
    00037 }
    00038
    00048 fixed::value_type fixed::reduce(value_type frac)
    00049 {
    00050   // First scan for zero digits on the right.
    00051   value_type f(frac);
    00052   while (f >= places10*10 and f % 10 == 0)
    00053   {
    00054     f /= 10;
    00055   }
    00056
    00057   if (f >= places10*10)
    00058   {
    00059     int x(0);
    00060     // Loop ended because a non-zero digit was seen so Y* > 0.
    00061     // Discard the remaining digits, but keep track of the last
    00062     // digit to be processed (X).
    00063     while (f >= places10)
    00064     {
    00065       x = f % 10;
    00066       f /= 10;
    00067     }
    00068     // Round up if the last digit (X) is 5 or more
    00069     if (x >= 5)
    00070       ++f;
    00071     return f;
    00072   }
    00073   // Else all digits so far are zero. Check how many digits there were,
    00074   // that is, check whether G, and X at least are present.
    00075   else if (f >= places10)
    00076   {
    00077     // Yes, G and X are present. If X == 5, implement banker's rounding.
    00078     // Otherwise, round to nearest.
    00079     int x(f % 10);
    00080     f /= 10;
    00081     assert(f < places10);
    00082     if (x == 5)
    00083     {
    00084       // Yes, so implement banker's rounding.
    00085       if (f % 2 != 0)
    00086         ++f;
    00087       return f;
    00088     }
    00089     else if (x < 5)
    00090     {
    00091       // Round down.
    00092       return f;
    00093     }
    00094     else
    00095     {
    00096       // Round up.
    00097       return f + 1;
    00098     }
    00099   }
    00100   // Not enough digits, so nothing to round.
    00101   assert(frac < places10);
    00102   return frac;
    00103 }
    00104
    00105 // Round off to nearest integer.
    00106 fixed::value_type fixed::round()
    00107 const
    00108 {
    00109   const value_type frac(fraction());
    00110   int adjust(value() < 0 ? -1 : +1);
    00111   if (frac > places10/2)
    00112     return integer()+adjust;
    00113   else if (frac < places10/2)
    00114     return integer();
    00115   else if (integer() % 2 == 0)
    00116     return integer();
    00117   else
    00118     return integer()+adjust;
    00119 }
    00120
    00121 // Convert to a string using fixed-point notation.
    00122 std::string fixed::as_string()
    00123 const
    00124 {
    00125   std::ostringstream out;
    00126   out << integer() << '.'
    00127       << std::setfill('0') << std::setw(places) << fraction();
    00128   return out.str();
    00129 }
    00130
    00131 fixed& fixed::operator+=(fixed f)
    00132 {
    00133   value_ += f.value();
    00134   return *this;
    00135 }
    00136
    00137 fixed& fixed::operator-=(fixed f)
    00138 {
    00139   value_ -= f.value();
    00140   return *this;
    00141 }
    00142
    00143 fixed& fixed::operator*=(fixed f)
    00144 {
    00145   value_ = (value_ * f.value()) / places10;
    00146   return *this;
    00147 }
    00148
    00149 fixed& fixed::operator/=(fixed f)
    00150 {
    00151   value_ = (value_ * places10) / f.value();
    00152   return *this;
    00153 }
    00154
    00155 void fixed::negate()
    00156 {
    00157   value_ = -value_;
    00158 }
    00159
    00160 fixed& fixed::operator++()
    00161 {
    00162   value_ += places10;
    00163   return *this;
    00164 }
    00165
    00166 fixed fixed::operator++(int)
    00167 {
    00168   fixed result(*this);
    00169   ++*this;
    00170   return result;
    00171 }
    00172
    00173 fixed& fixed::operator--()
    00174 {
    00175   value_ -= places10;
    00176   return *this;
    00177 }
    00178
    00179 fixed fixed::operator--(int)
    00180 {
    00181   fixed result(*this);
    00182   --*this;
    00183   return result;
    00184 }
    00185
    00186 fixed operator-(fixed a)
    00187 {
    00188   a.negate();
    00189   return a;
    00190 }
    00191
    00192 bool fixed::read(std::istream& strm)
    00193 {
    00194   ioflags flags(strm);
    00195
    00196   value_type integer;
    00197   char decimal;
    00198   if (not (strm >> integer))
    00199     return false;
    00200   strm.unsetf(std::ios_base::skipws);
    00201   if (not (strm >> decimal) or decimal != '.')
    00202   {
    00203     // Just an integer is fine. Push back the non-decimal character,
    00204     // if there is one, and reset the stream flags to show that
    00205     // reading the fixed value succeeded.
    00206     strm.unget();
    00207     strm.clear(strm.rdstate() & ~strm.failbit);
    00208     value_ = integer * places10;
    00209     return true;
    00210   }
    00211   else
    00212   {
    00213     value_type fraction(0);
    00214     char c;
    00215     int p(0);
    00216     // Read one extra place for round-off.
    00217     for (;
    00218          p != places+1 and strm >> c and std::isdigit(c, strm.getloc());
    00219          ++p)
    00220     {
    00221         fraction = fraction * 10 + (c - '0');
    00222     }
    00223     // Pad out to the requisite number of decimal places.
    00224     for (; p < places; ++p)
    00225       fraction = fraction * 10;
    00226     // If the loop terminated because the maximum number of decimal
    00227     // places were read, keep reading the stream to discard excees digits.
    00228     while (strm and std::isdigit(c, strm.getloc()))
    00229       strm >> c;
    00230     // Push back the last, non-digit character read from the stream.
    00231     // If the stream reached EOF, unget() is harmless.
    00232     strm.unget();
    00233     // Clear failbit because even if reading a character or whatever
    00234     // failed, reading the fixed value did not.
    00235     strm.clear(strm.rdstate() & ~strm.failbit);
    00236     fraction = reduce(fraction);
    00237     if (integer < 0)
    00238       value_ = integer * places10 - fraction;
    00239     else
    00240       value_ = integer * places10 + fraction;
    00241   }
    00242   return true;
    00243 }
    00244
    00245 std::istream& operator>>(std::istream& strm, fixed& f)
    00246 {
    00247   if (not f.read(strm))
    00248     strm.setstate(strm.failbit);
    00249   return strm;
    00250 }
    00251
    00252 std::ostream& operator<<(std::ostream& strm, fixed f)
    00253 {
    00254   strm << f.as_string();
    00255   return strm;
    00256 }
    00257
    00258 fixed operator+(fixed a, fixed b)
    00259 {
    00260   a += b;
    00261   return a;
    00262 }
    00263
    00264 fixed operator-(fixed a, fixed b)
    00265 {
    00266   a -= b;
    00267   return a;
    00268 }
    00269
    00270 fixed operator*(fixed a, fixed b)
    00271 {
    00272   a *= b;
    00273   return a;
    00274 }
    00275
    00276 fixed operator/(fixed a, fixed b)
    00277 {
    00278   a /= b;
    00279   return a;
    00280 }
    00281
    00282 bool operator==(fixed a, fixed b)
    00283 {
    00284   return a.value() == b.value();
    00285 }
    00286
    00287 bool operator!=(fixed a, fixed b)
    00288 {
    00289   return not (a == b);
    00290 }
    00291
    00292 bool operator<(fixed a, fixed b)
    00293 {
    00294   return a.value() < b.value();
    00295 }
    00296
    00297 bool operator>(fixed a, fixed b)
    00298 {
    00299   return b < a;
    00300 }
    00301
    00302 bool operator<=(fixed a, fixed b)
    00303 {
    00304   return not (b < a);
    00305 }
    00306
    00307 bool operator>=(fixed a, fixed b)
    00308 {
    00309   return not (a < b);
    00310 }