Project 3 - Currency Type
rational.hpp
1 #ifndef RATIONAL_HPP_
2 #define RATIONAL_HPP_
3 
4 #include <istream>
5 #include <limits>
6 #include <ostream>
7 #include <sstream>
8 #include <stdexcept>
9 #include <string>
10 
11 #include "gcd.hpp"
12 #include "ioflags.hpp"
13 
15 template<class T>
16 class rational
17 {
18 public:
20  typedef T value_type;
22  class zero_denominator : public std::logic_error
23  {
24  public:
26  zero_denominator(std::string const& what) : logic_error{what} {}
27  };
28 
33  rational(value_type num = 0): numerator_{num}, denominator_{1} {}
38  rational(value_type num, value_type den);
41  rational(double r);
43  template<class U>
44  rational(rational<U> const& that);
45 
47  value_type numerator() const { return numerator_; }
49  value_type denominator() const { return denominator_; }
51  template<class U>
52  U as() const { return static_cast<U>(numerator()) / denominator(); }
53 
55  rational& operator=(value_type); // optimization to avoid an unneeded call to reduce()
56 
58  template<class U>
59  rational& operator=(rational<U> const& rhs);
60 
62  rational& operator+=(rational const& rhs);
64  rational& operator+=(value_type const& rhs);
65 
67  rational& operator-=(rational const& rhs);
69  rational& operator-=(value_type const& rhs);
70 
72  rational& operator*=(rational const& rhs);
74  rational& operator*=(value_type const& rhs);
75 
77  rational& operator/=(rational const& rhs);
79  rational& operator/=(value_type const& rhs);
80 
86  rational operator++(int);
88  rational operator--(int);
89 
90 private:
92  void reduce();
95  void normalize();
98  template<class U>
99  value_type scale(U value);
100 
101  value_type numerator_;
102  value_type denominator_;
103 };
104 
105 template<class T>
107 : numerator_(num),
108  denominator_(den == value_type() ? throw zero_denominator("zero denominator") : den)
109 {
110  normalize();
111 }
112 
113 template<class T>
115 : numerator_(static_cast<T>(r / 100000)), denominator_(static_cast<T>(100000))
116 {}
117 
118 template<class T>
119 template<class U>
121 : numerator_(scale<U>(that.numerator())), denominator_(scale<U>(that.denominator()))
122 {
123  reduce();
124 }
125 
126 template<class T>
127 template<class U>
128 T rational<T>::scale(U value)
129 {
130  if (std::numeric_limits<T>::digits >= std::numeric_limits<U>::digits)
131  return T(value);
132  else
133  return T(value >> (std::numeric_limits<U>::digits - std::numeric_limits<T>::digits));
134 }
135 
136 template<class T>
138 {
139  if (denominator_ < value_type())
140  {
141  denominator_ = -denominator_;
142  numerator_ = -numerator_;
143  }
144  reduce();
145 }
146 
147 template<class T>
148 void rational<T>::reduce()
149 {
150  value_type div(gcd(numerator(), denominator()));
151  if (div == value_type())
152  throw zero_denominator("zero denominator");
153  numerator_ /= div;
154  denominator_ /= div;
155 }
156 
157 template<class T>
159 {
160  numerator_ = num;
161  denominator_ = value_type(1);
162  return *this;
163 }
164 
165 template<class T>
166 template<class U>
168 {
169  numerator_ = scale<U>(rhs.numerator());
170  denominator_ = scale<U>(rhs.denominator());
171  reduce();
172  return *this;
173 }
174 
175 template<class T>
177 {
178  numerator_ = numerator() * rhs.denominator() + rhs.numerator() * denominator();
179  denominator_ *= rhs.denominator();
180  reduce();
181  return *this;
182 }
183 
184 template<class T>
186 {
187  numerator_ = numerator() + rhs * denominator();
188  reduce();
189  return *this;
190 }
191 
192 template<class T>
194 {
195  numerator_ = numerator() * rhs.denominator() - rhs.numerator() * denominator();
196  denominator_ *= rhs.denominator();
197  reduce();
198  return *this;
199 }
200 
201 template<class T>
203 {
204  numerator_ = numerator() - rhs * denominator();
205  reduce();
206  return *this;
207 }
208 
209 template<class T>
211 {
212  numerator_ *= rhs.numerator();
213  denominator_ *= rhs.denominator();
214  reduce();
215  return *this;
216 }
217 
218 template<class T>
220 {
221  numerator_ *= rhs;
222  reduce();
223  return *this;
224 }
225 
226 template<class T>
228 {
229  if (rhs.numerator() == value_type())
230  throw zero_denominator("divide by zero");
231  numerator_ *= rhs.denominator();
232  denominator_ *= rhs.numerator();
233  normalize();
234  return *this;
235 }
236 
237 template<class T>
239 {
240  if (rhs == value_type())
241  throw zero_denominator("divide by zero");
242  denominator_ *= rhs;
243  normalize();
244  return *this;
245 }
246 
247 template<class T>
249 {
250  numerator_ += denominator();
251  return *this;
252 }
253 
254 template<class T>
256 {
257  rational result(*this);
258  ++*this;
259  return result;
260 }
261 
262 template<class T>
264 {
265  numerator_ -= denominator();
266  return *this;
267 }
268 
269 template<class T>
271 {
272  rational result(*this);
273  --*this;
274  return result;
275 }
276 
278 template<class T>
280 {
281  return rational<T>(-r.numerator(), r.denominator());
282 }
283 
284 template<class T>
285 rational<T> absval(rational<T> const& r)
286 {
287  using namespace std;
288  return rational<T>(abs(r.numerator()), r.denominator());
289 }
290 
292 template<class T>
294 {
295  lhs += rhs;
296  return lhs;
297 }
298 
300 template<class T>
301 rational<T> operator+(rational<T> lhs, T const& rhs)
302 {
303  lhs += rhs;
304  return lhs;
305 }
306 
308 template<class T>
309 rational<T> operator+(T const& lhs, rational<T> rhs)
310 {
311  rhs += lhs;
312  return rhs;
313 }
314 
316 template<class T>
318 {
319  lhs -= rhs;
320  return lhs;
321 }
322 
324 template<class T>
325 rational<T> operator-(rational<T> lhs, T const& rhs)
326 {
327  lhs -= rhs;
328  return lhs;
329 }
330 
332 template<class T>
333 rational<T> operator-(T const& lhs, rational<T> rhs)
334 {
335  // Gotta be a little tricky.
336  rhs += -lhs;
337  return -rhs;
338 }
339 
341 template<class T>
343 {
344  lhs *= rhs;
345  return lhs;
346 }
347 
349 template<class T>
350 rational<T> operator*(rational<T> lhs, T const& rhs)
351 {
352  lhs *= rhs;
353  return lhs;
354 }
355 
357 template<class T>
358  rational<T> operator*(T const& lhs, rational<T> rhs)
359 {
360  rhs *= lhs;
361  return rhs;
362 }
363 
365 template<class T>
367 {
368  lhs /= rhs;
369  return lhs;
370 }
371 
373 template<class T>
374 rational<T> operator/(rational<T> lhs, T const& rhs)
375 {
376  lhs /= rhs;
377  return lhs;
378 }
379 
381 template<class T>
382 rational<T> operator/(T const& lhs, rational<T> rhs)
383 {
384  return rational<T>(lhs * rhs.denominator(), rhs.numerator());
385 }
386 
387 
389 template<class T, class U>
390 bool operator==(rational<T> const& a, rational<U> const& b)
391 {
392  return a.numerator() == b.numerator() and
393  a.denominator() == b.denominator();
394 }
395 
397 template<class T>
398 bool operator==(rational<T> const& lhs, T rhs)
399 {
400  return lhs.denominator() == 1 and
401  lhs.numerator() == rhs;
402 }
403 
405 template<class T>
406 bool operator==(T lhs, rational<T> const& rhs)
407 {
408  return rhs.denominator() == 1 and
409  rhs.numerator() == lhs;
410 }
411 
413 template<class T>
414 bool operator<(rational<T> const& a, rational<T> const& b)
415 {
416  return a.numerator() * b.denominator() < b.numerator() * a.denominator();
417 }
418 
420 template<class T>
421 bool operator<(rational<T> const& a, T const& b)
422 {
423  return a.numerator() < b * a.denominator();
424 }
425 
427 template<class T>
428 bool operator<(T const& a, rational<T> const& b)
429 {
430  return a * b.denominator() < b.numerator();
431 }
432 
434 template<class T, class U>
435 inline bool operator!=(rational<T> const& a, rational<U> const& b)
436 {
437  return not (a == b);
438 }
439 
441 template<class T>
442 inline bool operator!=(rational<T> const& a, T b)
443 {
444  return not (a == b);
445 }
446 
448 template<class T>
449 inline bool operator!=(T a, rational<T> const& b)
450 {
451  return not (a == b);
452 }
453 
455 template<class T>
456 inline bool operator<=(rational<T> const& a, rational<T> const& b)
457 {
458  return not (b < a);
459 }
460 
462 template<class T>
463 inline bool operator<=(rational<T> const& a, T const& b)
464 {
465  return not (b < a);
466 }
467 
469 template<class T>
470 inline bool operator<=(T const& a, rational<T> const& b)
471 {
472  return not (b < a);
473 }
474 
476 template<class T>
477 inline bool operator>(rational<T> const& a, rational<T> const& b)
478 {
479  return b < a;
480 }
481 
483 template<class T>
484 inline bool operator>(rational<T> const& a, T const& b)
485 {
486  return b < a;
487 }
488 
490 template<class T>
491 inline bool operator>(T const& a, rational<T> const& b)
492 {
493  return b < a;
494 }
495 
497 template<class T>
498 inline bool operator>=(rational<T> const& a, rational<T> const& b)
499 {
500  return not (b > a);
501 }
502 
504 template<class T>
505 inline bool operator>=(rational<T> const& a, T const& b)
506 {
507  return not (b > a);
508 }
509 
511 template<class T>
512 inline bool operator>=(T const& a, rational<T> const& b)
513 {
514  return not (b > a);
515 }
516 
518 template<class T, class Char, class Traits>
519 std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, rational<T>& rat)
520 {
521  typename std::basic_istream<Char, Traits>::sentry sentry(in, false);
522  ioflags flags(in);
523 
524  T n = T();
525  if (not (in >> n))
526  // Error reading the numerator.
527  return in;
528 
529  in >> std::noskipws;
530  char sep('\0');
531  if (not (in >> sep))
532  // Error reading the separator character.
533  return in;
534  else if (sep != '/')
535  {
536  // Push sep back into the input stream, so the next input operation
537  // will read it.
538  in.unget();
539  rat = n;
540  return in;
541  }
542  else
543  {
544  T d = T();
545  if (in >> d)
546  // Successfully read numerator, separator, and denominator.
547  rat = rational<T>(n, d);
548  }
549 
550  return in;
551 }
552 
554 template<class T, class Char, class Traits>
555 std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, rational<T> const& rat)
556 {
557  typename std::basic_ostream<Char, Traits>::sentry sentry(out);
558  std::ostringstream stream;
559  stream << rat.numerator() << '/' << rat.denominator();
560  out << stream.str();
561  return out;
562 }
563 
564 #endif
currency< T, N > operator+(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:304
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
rational & operator=(value_type)
Assignment of an integer.
Definition: rational.hpp:158
value_type denominator() const
Return the denominator.
Definition: rational.hpp:49
zero_denominator(std::string const &what)
Construct the exception object.
Definition: rational.hpp:26
currency< T, N > operator/(currency< T, N > a, T b)
Definition: currency.hpp:344
rational & operator-=(rational const &rhs)
Subtraction assignment operator.
Definition: rational.hpp:193
value_type numerator() const
Return the numerator.
Definition: rational.hpp:47
rational & operator--()
Pre-decrement.
Definition: rational.hpp:263
Save and restore I/O stream flags.
rational & operator+=(rational const &rhs)
Addition assignment operator.
Definition: rational.hpp:176
bool operator!=(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:391
rational(value_type num=0)
Definition: rational.hpp:33
rational & operator*=(rational const &rhs)
Multiplication assignment operator.
Definition: rational.hpp:210
rational & operator/=(rational const &rhs)
Division assignment operator.
Definition: rational.hpp:227
Represent a rational number (fraction) as a numerator and denominator.
Definition: rational.hpp:16
bool operator>=(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:491
T value_type
Convenience typedef for the integral type of the numerator and denominator.
Definition: rational.hpp:20
U as() const
Convert the rational number to another type, especially floating-point.
Definition: rational.hpp:52
rational & operator++()
Pre-increment.
Definition: rational.hpp:248
Exception class if the denominator is ever zero.
Definition: rational.hpp:22
bool operator>(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:441
std::basic_istream< Char, Traits > & operator>>(std::basic_istream< Char, Traits > &strm, currency< T, N > &c)
Definition: currency.hpp:274
currency< T, N > operator-(currency< T, N > a)
Negate a currency value.
Definition: currency.hpp:294