Project 3 - Currency Type
fixed.hpp
Go to the documentation of this file.
1 
4 #ifndef FIXED_HPP_
5 #define FIXED_HPP_
6 
7 #include <cassert>
8 #include <cmath>
9 #include <iomanip>
10 #include <ios>
11 #include <istream>
12 #include <locale>
13 #include <ostream>
14 #include <sstream>
15 #include <stdexcept>
16 #include <string>
17 
18 #include "ioflags.hpp"
19 #include "power10.hpp"
20 
25 template<class T, int N>
26 class fixed
27 {
28 public:
29  typedef T value_type;
30 
31  static value_type constexpr places{N};
32  static value_type constexpr places10{power10(N)};
33 
35  constexpr fixed() : value_() {}
36 
41 
43  constexpr fixed(value_type integer);
44 
46  fixed(double value)
47  : value_(static_cast<value_type>(value * places10 + (value < 0 ? -0.5 : 0.5)))
48  {}
49 
52  std::string as_string() const;
57  template<class Char, class Traits>
58  bool read(std::basic_istream<Char, Traits>& strm);
60  double as_long_double() const { return static_cast<long double>(value()) / places10; }
62  double as_double() const { return static_cast<double>(value()) / places10; }
64  float as_float() const { return static_cast<float>(value()) / places10; }
68  value_type round() const;
69 
71  value_type integer() const { return value() / places10; }
73  value_type fraction() const;
74 
83 
85  void negate();
86 
88  fixed& operator++();
90  fixed operator++(int);
92  fixed& operator--();
94  fixed operator--(int);
95 
97  value_type value() const { return value_; }
98 private:
100  value_type reduce(value_type frac);
101  value_type value_;
102 };
103 
104 template<class T, int N>
106 
107 // Construct a fixed value from an integer part and a fraction part
108 template<class T, int N>
110 {
111  if (fraction < T())
112  throw std::invalid_argument("negative fraction not allowed");
113  fraction = reduce(fraction);
114  if (integer < T())
115  value_ = integer * places10 - fraction;
116  else
117  value_ = integer * places10 + fraction;
118 }
119 
120 // Construct a fixed value from an integer part with no fraction
121 template<class T, int N>
122 constexpr
124 : value_(integer * places10)
125 {}
126 
127 // Get the fraction part
128 template<class T, int N>
130 const
131 {
132  return std::abs(value()) % places10;
133 }
134 
144 template<class T, int N>
145 typename fixed<T,N>::value_type fixed<T,N>::reduce(value_type frac)
146 {
147  // First scan for zero digits on the right.
148  value_type f(frac);
149  while (f >= places10*10 and f % 10 == 0)
150  {
151  f /= 10;
152  }
153 
154  if (f >= places10*10)
155  {
156  int x(0);
157  // Loop ended because a non-zero digit was seen so Y* > 0.
158  // Discard the remaining digits, but keep track of the last
159  // digit to be processed (X).
160  while (f >= places10)
161  {
162  x = f % 10;
163  f /= 10;
164  }
165  // Round up if the last digit (X) is 5 or more
166  if (x >= 5)
167  ++f;
168  return f;
169  }
170  // Else all digits so far are zero. Check how many digits there were,
171  // that is, check whether G, and X at least are present.
172  else if (f >= places10)
173  {
174  // Yes, G and X are present. If X == 5, implement banker's rounding.
175  // Otherwise, round to nearest.
176  int x(f % 10);
177  f /= 10;
178  assert(f < places10);
179  if (x == 5)
180  {
181  // Yes, so implement banker's rounding.
182  if (f % 2 != 0)
183  ++f;
184  return f;
185  }
186  else if (x < 5)
187  {
188  // Round down.
189  return f;
190  }
191  else
192  {
193  // Round up.
194  return f + 1;
195  }
196  }
197  // Not enough digits, so nothing to round.
198  assert(frac < places10);
199  return frac;
200 }
201 
202 // Round off to nearest integer.
203 template<class T, int N>
205 const
206 {
207  const value_type frac(fraction());
208  int adjust(value() < 0 ? -1 : +1);
209  if (frac > places10/2)
210  return integer()+adjust;
211  else if (frac < places10/2)
212  return integer();
213  else if (integer() % 2 == 0)
214  return integer();
215  else
216  return integer()+adjust;
217 }
218 
219 // Convert to a string using fixed-point notation.
220 template<class T, int N>
222 const
223 {
224  std::ostringstream out;
225  out << integer() << '.'
226  << std::setfill('0') << std::setw(places) << fraction();
227  return out.str();
228 }
229 
230 template<class T, int N>
232 {
233  value_ += f.value();
234  return *this;
235 }
236 
237 template<class T, int N>
239 {
240  value_ -= f.value();
241  return *this;
242 }
243 
244 template<class T, int N>
246 {
247  value_ = (value_ * f.value()) / places10;
248  return *this;
249 }
250 
251 template<class T, int N>
253 {
254  value_ = (value_ * places10) / f.value();
255  return *this;
256 }
257 
258 template<class T, int N>
260 {
261  value_ = -value_;
262 }
263 
264 template<class T, int N>
266 {
267  value_ += places10;
268  return *this;
269 }
270 
271 template<class T, int N>
273 {
274  fixed result(*this);
275  ++*this;
276  return result;
277 }
278 
279 template<class T, int N>
281 {
282  value_ -= places10;
283  return *this;
284 }
285 
286 template<class T, int N>
288 {
289  fixed result(*this);
290  --*this;
291  return result;
292 }
293 
294 template<class T, int N>
295 template<class Char, class Traits>
296 bool fixed<T,N>::read(std::basic_istream<Char, Traits>& strm)
297 {
298  ioflags flags(strm);
299 
300  value_type integer;
301  char decimal;
302  if (not (strm >> integer))
303  return false;
304  strm.unsetf(std::ios_base::skipws);
305  if (not (strm >> decimal) or decimal != '.')
306  {
307  // Just an integer is fine. Push back the non-decimal character,
308  // if there is one, and reset the stream flags to show that
309  // reading the fixed value succeeded.
310  strm.unget();
311  strm.clear(strm.rdstate() & ~strm.failbit);
312  value_ = integer * places10;
313  return true;
314  }
315  else
316  {
317  value_type fraction(0);
318  char c;
319  int p(0);
320  // Read one extra place for round-off.
321  for (;
322  p != places+1 and strm >> c and std::isdigit(c, strm.getloc());
323  ++p)
324  {
325  fraction = fraction * 10 + (c - '0');
326  }
327  // Pad out to the requisite number of decimal places.
328  for (; p < places; ++p)
329  fraction = fraction * 10;
330  // If the loop terminated because the maximum number of decimal
331  // places were read, keep reading the stream to discard excees digits.
332  while (strm and std::isdigit(c, strm.getloc()))
333  strm >> c;
334  // Push back the last, non-digit character read from the stream.
335  // If the stream reached EOF, unget() is harmless.
336  strm.unget();
337  // Clear failbit because even if reading a character or whatever
338  // failed, reading the fixed value did not.
339  strm.clear(strm.rdstate() & ~strm.failbit);
340  fraction = reduce(fraction);
341  if (integer < 0)
342  value_ = integer * places10 - fraction;
343  else
344  value_ = integer * places10 + fraction;
345  }
346  return true;
347 }
348 
350 template<class T, int N, class Char, class Traits>
351 std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& strm, fixed<T,N>& f)
352 {
353  if (not f.read(strm))
354  strm.setstate(strm.failbit);
355  return strm;
356 }
357 
359 template<class T, int N, class Char, class Traits>
360 std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& strm, fixed<T,N> f)
361 {
362  strm << f.as_string();
363  return strm;
364 }
365 
367 template<class T, int N>
369 {
370  a += b;
371  return a;
372 }
373 
375 template<class T, int N>
377 {
378  a -= b;
379  return a;
380 }
381 
383 template<class T, int N>
385 {
386  a *= b;
387  return a;
388 }
389 
391 template<class T, int N>
393 {
394  a /= b;
395  return a;
396 }
397 
399 template<class T, int N>
401 {
402  a.negate();
403  return a;
404 }
405 
407 template<class T, int N>
409 {
410  return a.value() == b.value();
411 }
413 template<class T, int N>
414 bool operator==(T a, fixed<T,N> b)
415 {
416  return a == b.value();
417 }
419 template<class T, int N>
420 bool operator==(fixed<T,N> a, T b)
421 {
422  return a.value() == b;
423 }
424 
426 template<class T, int N>
428 {
429  return not (a == b);
430 }
432 template<class T, int N>
433 bool operator!=(T a, fixed<T,N> b)
434 {
435  return not (a == b);
436 }
438 template<class T, int N>
439 bool operator!=(fixed<T,N> a, T b)
440 {
441  return not (a == b);
442 }
443 
445 template<class T, int N>
446 bool operator<(fixed<T,N> a, fixed<T,N> b)
447 {
448  return a.value() < b.value();
449 }
451 template<class T, int N>
452 bool operator<(T a, fixed<T,N> b)
453 {
454  return a < b.value();
455 }
457 template<class T, int N>
458 bool operator<(fixed<T,N> a, T b)
459 {
460  return a.value() < b;
461 }
462 
464 template<class T, int N>
466 {
467  return b < a;
468 }
470 template<class T, int N>
471 bool operator>(T a, fixed<T,N> b)
472 {
473  return b < a;
474 }
476 template<class T, int N>
477 bool operator>(fixed<T,N> a, T b)
478 {
479  return b < a;
480 }
481 
483 template<class T, int N>
484 bool operator<=(fixed<T,N> a, fixed<T,N> b)
485 {
486  return not (b < a);
487 }
489 template<class T, int N>
490 bool operator<=(T a, fixed<T,N> b)
491 {
492  return not (b < a);
493 }
495 template<class T, int N>
496 bool operator<=(fixed<T,N> a, T b)
497 {
498  return not (b < a);
499 }
500 
502 template<class T, int N>
504 {
505  return not (a < b);
506 }
508 template<class T, int N>
509 bool operator>=(T a, fixed<T,N> b)
510 {
511  return not (a < b);
512 }
514 template<class T, int N>
515 bool operator>=(fixed<T,N> a, T b)
516 {
517  return not (a < b);
518 }
519 
520 #endif
double as_long_double() const
Convert to long double.
Definition: fixed.hpp:60
currency< T, N > operator+(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:304
Implement a fixed-point number class template. Values have N places after the decimal point...
Definition: fixed.hpp:26
bool operator==(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:366
currency< T, N > operator*(currency< T, N > a, T b)
Definition: currency.hpp:324
std::string as_string() const
Definition: fixed.hpp:221
fixed & operator++()
Pre-increment.
Definition: fixed.hpp:265
currency< T, N > operator/(currency< T, N > a, T b)
Definition: currency.hpp:344
float as_float() const
Convert to float.
Definition: fixed.hpp:64
constexpr fixed()
Default constructor initializes to zero.
Definition: fixed.hpp:35
Save and restore I/O stream flags.
T value_type
Type of the actual value.
Definition: fixed.hpp:29
fixed & operator--()
Pre-decrement.
Definition: fixed.hpp:280
static value_type constexpr places10
10places
Definition: fixed.hpp:32
bool operator!=(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:391
double as_double() const
Convert to double.
Definition: fixed.hpp:62
value_type fraction() const
Return the fractional part, e.g., 3 for 12.03.
Definition: fixed.hpp:129
value_type round() const
Definition: fixed.hpp:204
fixed & operator*=(fixed f)
Multiplication assignment operator.
Definition: fixed.hpp:245
fixed(double value)
Construct by rounding off a floating point number.
Definition: fixed.hpp:46
bool operator>=(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:491
fixed & operator-=(fixed f)
Subtraction assignment operator.
Definition: fixed.hpp:238
fixed & operator/=(fixed f)
Division assignment operator.
Definition: fixed.hpp:252
value_type integer() const
Return the integer part (which is the same as trunc()).
Definition: fixed.hpp:71
bool read(std::basic_istream< Char, Traits > &strm)
Definition: fixed.hpp:296
value_type value() const
Return the internal value.
Definition: fixed.hpp:97
bool operator>(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:441
void negate()
Negate this value.
Definition: fixed.hpp:259
std::basic_istream< Char, Traits > & operator>>(std::basic_istream< Char, Traits > &strm, currency< T, N > &c)
Definition: currency.hpp:274
static value_type constexpr places
number of decimal places
Definition: fixed.hpp:31
fixed & operator+=(fixed f)
Addition assignment operator.
Definition: fixed.hpp:231
currency< T, N > operator-(currency< T, N > a)
Negate a currency value.
Definition: currency.hpp:294