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 }

Generated on Sun Nov 30 09:54:28 2008 for Project 2 - Fixed-Point Number Class by  doxygen 1.5.3