Project 3 - Currency Type

- Main Page
- Classes
- Files

- File List
- File Members

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
82 rational& operator++();
84 rational& operator--();
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>
106 rational<T>::rational(value_type num, value_type den)
107 : numerator_(num),
108 denominator_(den == value_type() ? throw zero_denominator("zero denominator") : den)
109 {
110 normalize();
111 }
112
113 template<class T>
114 rational<T>::rational(double r)
115 : numerator_(static_cast<T>(r / 100000)), denominator_(static_cast<T>(100000))
116 {}
117
118 template<class T>
119 template<class U>
120 rational<T>::rational(rational<U> const& that)
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>
137 void rational<T>::normalize()
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>
158 rational<T>& rational<T>::operator=(T num)
159 {
160 numerator_ = num;
161 denominator_ = value_type(1);
162 return *this;
163 }
164
165 template<class T>
166 template<class U>
167 rational<T>& rational<T>::operator=(rational<U> const& rhs)
168 {
169 numerator_ = scale<U>(rhs.numerator());
170 denominator_ = scale<U>(rhs.denominator());
171 reduce();
172 return *this;
173 }
174
175 template<class T>
176 rational<T>& rational<T>::operator+=(rational const& rhs)
177 {
178 numerator_ = numerator() * rhs.denominator() + rhs.numerator() * denominator();
179 denominator_ *= rhs.denominator();
180 reduce();
181 return *this;
182 }
183
184 template<class T>
185 rational<T>& rational<T>::operator+=(value_type const& rhs)
186 {
187 numerator_ = numerator() + rhs * denominator();
188 reduce();
189 return *this;
190 }
191
192 template<class T>
193 rational<T>& rational<T>::operator-=(rational const& rhs)
194 {
195 numerator_ = numerator() * rhs.denominator() - rhs.numerator() * denominator();
196 denominator_ *= rhs.denominator();
197 reduce();
198 return *this;
199 }
200
201 template<class T>
202 rational<T>& rational<T>::operator-=(value_type const& rhs)
203 {
204 numerator_ = numerator() - rhs * denominator();
205 reduce();
206 return *this;
207 }
208
209 template<class T>
210 rational<T>& rational<T>::operator*=(rational const& rhs)
211 {
212 numerator_ *= rhs.numerator();
213 denominator_ *= rhs.denominator();
214 reduce();
215 return *this;
216 }
217
218 template<class T>
219 rational<T>& rational<T>::operator*=(value_type const& rhs)
220 {
221 numerator_ *= rhs;
222 reduce();
223 return *this;
224 }
225
226 template<class T>
227 rational<T>& rational<T>::operator/=(rational const& rhs)
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>
238 rational<T>& rational<T>::operator/=(value_type const& rhs)
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>
248 rational<T>& rational<T>::operator++()
249 {
250 numerator_ += denominator();
251 return *this;
252 }
253
254 template<class T>
255 rational<T> rational<T>::operator++(int)
256 {
257 rational result(*this);
258 ++*this;
259 return result;
260 }
261
262 template<class T>
263 rational<T>& rational<T>::operator--()
264 {
265 numerator_ -= denominator();
266 return *this;
267 }
268
269 template<class T>
270 rational<T> rational<T>::operator--(int)
271 {
272 rational result(*this);
273 --*this;
274 return result;
275 }
276
278 template<class T>
279 rational<T> operator-(rational<T> const& r)
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>
293 rational<T> operator+(rational<T> lhs, rational<T> const& rhs)
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>
317 rational<T> operator-(rational<T> lhs, rational<T> const& rhs)
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>
342 rational<T> operator*(rational<T> lhs, rational<T> const& rhs)
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>
366 rational<T> operator/(rational<T> lhs, rational<T> const& rhs)
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
operator+
currency< T, N > operator+(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:304
operator==
bool operator==(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:366
operator*
currency< T, N > operator*(currency< T, N > a, T b)
Definition: currency.hpp:324
rational::operator=
rational & operator=(value_type)
Assignment of an integer.
Definition: rational.hpp:158
rational::denominator
value_type denominator() const
Return the denominator.
Definition: rational.hpp:49
rational::zero_denominator::zero_denominator
zero_denominator(std::string const &what)
Construct the exception object.
Definition: rational.hpp:26
operator/
currency< T, N > operator/(currency< T, N > a, T b)
Definition: currency.hpp:344
rational::operator-=
rational & operator-=(rational const &rhs)
Subtraction assignment operator.
Definition: rational.hpp:193
rational::numerator
value_type numerator() const
Return the numerator.
Definition: rational.hpp:47
rational::operator--
rational & operator--()
Pre-decrement.
Definition: rational.hpp:263
ioflags.hpp
Save and restore I/O stream flags.
rational::operator+=
rational & operator+=(rational const &rhs)
Addition assignment operator.
Definition: rational.hpp:176
operator!=
bool operator!=(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:391
rational::rational
rational(value_type num=0)
Definition: rational.hpp:33
rational::operator*=
rational & operator*=(rational const &rhs)
Multiplication assignment operator.
Definition: rational.hpp:210
rational::operator/=
rational & operator/=(rational const &rhs)
Division assignment operator.
Definition: rational.hpp:227
rational
Represent a rational number (fraction) as a numerator and denominator.
Definition: rational.hpp:16
operator>=
bool operator>=(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:491
rational::value_type
T value_type
Convenience typedef for the integral type of the numerator and denominator.
Definition: rational.hpp:20
rational::as
U as() const
Convert the rational number to another type, especially floating-point.
Definition: rational.hpp:52
rational::operator++
rational & operator++()
Pre-increment.
Definition: rational.hpp:248
rational::zero_denominator
Exception class if the denominator is ever zero.
Definition: rational.hpp:22
ioflags
Definition: ioflags.hpp:15
operator>
bool operator>(currency< T, N > a, currency< T, N > b)
Definition: currency.hpp:441
operator>>
std::basic_istream< Char, Traits > & operator>>(std::basic_istream< Char, Traits > &strm, currency< T, N > &c)
Definition: currency.hpp:274
operator-
currency< T, N > operator-(currency< T, N > a)
Negate a currency value.
Definition: currency.hpp:294