Calculator  Step 6
rational.hpp
Go to the documentation of this file.
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 #include <type_traits>
11 
12 #include "gcd.hpp"
13 #include "ioflags.hpp"
14 #include "power10.hpp"
15 
17 class zero_denominator : public std::logic_error
18 {
19 public:
21  zero_denominator(std::string const& what) : logic_error{what} {}
22 };
23 
25 template<class T>
26 class rational
27 {
28 public:
30  typedef T value_type;
31 
41  rational(value_type num, value_type den);
44  rational(double r);
46  template<class U>
47  rational(rational<U> const& that);
48 
50  value_type numerator() const { return numerator_; }
52  value_type denominator() const { return denominator_; }
54  template<class U, class EnableIfFloat = typename std::enable_if<std::is_floating_point<U>::value>::type>
55  explicit operator U() const { return static_cast<U>(numerator()) / denominator(); }
56 
58  rational& operator=(value_type); // optimization to avoid an unneeded call to reduce()
59 
61  template<class U>
62  rational& operator=(rational<U> const& rhs);
63 
65  rational& operator+=(rational const& rhs);
67  rational& operator+=(value_type const& rhs);
68 
70  rational& operator-=(rational const& rhs);
72  rational& operator-=(value_type const& rhs);
73 
75  rational& operator*=(rational const& rhs);
77  rational& operator*=(value_type const& rhs);
78 
80  rational& operator/=(rational const& rhs);
82  rational& operator/=(value_type const& rhs);
83 
89  rational operator++(int);
91  rational operator--(int);
92 
93 private:
95  void reduce();
98  void normalize();
101  template<class U>
102  value_type scale(U value);
103 
106  static constexpr value_type double_divisor = power10<value_type>(std::numeric_limits<value_type>::digits10 - 1);
107 
110 };
111 
112 template<class T>
114 : numerator_{num},
115  denominator_{den == value_type{} ? throw zero_denominator{"zero denominator"} : den}
116 {
117  normalize();
118 }
119 
120 template<class T>
122 : numerator_{static_cast<T>(r / double_divisor + 0.5)}, denominator_{double_divisor}
123 {}
124 
125 template<class T>
126 template<class U>
128 : numerator_{scale<U>(that.numerator())}, denominator_{scale<U>(that.denominator())}
129 {
130  reduce();
131 }
132 
133 template<class T>
134 template<class U>
136 {
137  if (std::numeric_limits<T>::digits >= std::numeric_limits<U>::digits)
138  return T{value};
139  else
140  return T{value >> (std::numeric_limits<U>::digits - std::numeric_limits<T>::digits)};
141 }
142 
143 template<class T>
145 {
146  if (denominator_ < value_type{})
147  {
150  }
151  reduce();
152 }
153 
154 template<class T>
156 {
157  value_type div{gcd(numerator(), denominator())};
158  if (div == value_type{})
159  throw zero_denominator{"zero denominator"};
160  numerator_ /= div;
161  denominator_ /= div;
162 }
163 
164 template<class T>
166 {
167  numerator_ = num;
169  return *this;
170 }
171 
172 template<class T>
173 template<class U>
175 {
176  numerator_ = scale<U>(rhs.numerator());
177  denominator_ = scale<U>(rhs.denominator());
178  reduce();
179  return *this;
180 }
181 
182 template<class T>
184 {
185  numerator_ = numerator() * rhs.denominator() + rhs.numerator() * denominator();
186  denominator_ *= rhs.denominator();
187  reduce();
188  return *this;
189 }
190 
191 template<class T>
193 {
194  numerator_ = numerator() + rhs * denominator();
195  reduce();
196  return *this;
197 }
198 
199 template<class T>
201 {
202  numerator_ = numerator() * rhs.denominator() - rhs.numerator() * denominator();
203  denominator_ *= rhs.denominator();
204  reduce();
205  return *this;
206 }
207 
208 template<class T>
210 {
211  numerator_ = numerator() - rhs * denominator();
212  reduce();
213  return *this;
214 }
215 
216 template<class T>
218 {
219  numerator_ *= rhs.numerator();
220  denominator_ *= rhs.denominator();
221  reduce();
222  return *this;
223 }
224 
225 template<class T>
227 {
228  numerator_ *= rhs;
229  reduce();
230  return *this;
231 }
232 
233 template<class T>
235 {
236  if (rhs.numerator() == value_type{})
237  throw zero_denominator{"divide by zero"};
238  numerator_ *= rhs.denominator();
239  denominator_ *= rhs.numerator();
240  normalize();
241  return *this;
242 }
243 
244 template<class T>
246 {
247  if (rhs == value_type{})
248  throw zero_denominator{"divide by zero"};
249  denominator_ *= rhs;
250  normalize();
251  return *this;
252 }
253 
254 template<class T>
256 {
257  numerator_ += denominator();
258  return *this;
259 }
260 
261 template<class T>
263 {
264  rational result(*this);
265  ++*this;
266  return result;
267 }
268 
269 template<class T>
271 {
272  numerator_ -= denominator();
273  return *this;
274 }
275 
276 template<class T>
278 {
279  rational result(*this);
280  --*this;
281  return result;
282 }
283 
285 template<class T>
287 {
288  return rational<T>{-r.numerator(), r.denominator()};
289 }
290 
291 template<class T>
293 {
294  using std::abs;
295  return rational<T>{abs(r.numerator()), r.denominator()};
296 }
297 
299 template<class T>
301 {
302  lhs += rhs;
303  return lhs;
304 }
305 
307 template<class T>
309 {
310  lhs += rhs;
311  return lhs;
312 }
313 
315 template<class T>
317 {
318  rhs += lhs;
319  return rhs;
320 }
321 
323 template<class T>
325 {
326  lhs -= rhs;
327  return lhs;
328 }
329 
331 template<class T>
333 {
334  lhs -= rhs;
335  return lhs;
336 }
337 
339 template<class T>
341 {
342  // Gotta be a little tricky.
343  rhs += -lhs;
344  return -rhs;
345 }
346 
348 template<class T>
350 {
351  lhs *= rhs;
352  return lhs;
353 }
354 
356 template<class T>
358 {
359  lhs *= rhs;
360  return lhs;
361 }
362 
364 template<class T>
365  rational<T> operator*(T const& lhs, rational<T> rhs)
366 {
367  rhs *= lhs;
368  return rhs;
369 }
370 
372 template<class T>
374 {
375  lhs /= rhs;
376  return lhs;
377 }
378 
380 template<class T>
382 {
383  lhs /= rhs;
384  return lhs;
385 }
386 
388 template<class T>
390 {
391  return rational<T>{lhs * rhs.denominator(), rhs.numerator()};
392 }
393 
394 
396 template<class T, class U>
397 bool operator==(rational<T> const& a, rational<U> const& b)
398 {
399  return a.numerator() == b.numerator() and
400  a.denominator() == b.denominator();
401 }
402 
404 template<class T>
405 bool operator==(rational<T> const& lhs, T rhs)
406 {
407  return lhs.denominator() == 1 and
408  lhs.numerator() == rhs;
409 }
410 
412 template<class T>
413 bool operator==(T lhs, rational<T> const& rhs)
414 {
415  return rhs.denominator() == 1 and
416  rhs.numerator() == lhs;
417 }
418 
420 template<class T>
421 bool operator<(rational<T> const& a, rational<T> const& b)
422 {
423  return a.numerator() * b.denominator() < b.numerator() * a.denominator();
424 }
425 
427 template<class T>
428 bool operator<(rational<T> const& a, T const& b)
429 {
430  return a.numerator() < b * a.denominator();
431 }
432 
434 template<class T>
435 bool operator<(T const& a, rational<T> const& b)
436 {
437  return a * b.denominator() < b.numerator();
438 }
439 
441 template<class T, class U>
442 inline bool operator!=(rational<T> const& a, rational<U> const& b)
443 {
444  return not (a == b);
445 }
446 
448 template<class T>
449 inline bool operator!=(rational<T> const& a, T b)
450 {
451  return not (a == b);
452 }
453 
455 template<class T>
456 inline bool operator!=(T a, rational<T> const& b)
457 {
458  return not (a == b);
459 }
460 
462 template<class T>
463 inline bool operator<=(rational<T> const& a, rational<T> const& b)
464 {
465  return not (b < a);
466 }
467 
469 template<class T>
470 inline bool operator<=(rational<T> const& a, T const& b)
471 {
472  return not (b < a);
473 }
474 
476 template<class T>
477 inline bool operator<=(T const& a, rational<T> const& b)
478 {
479  return not (b < a);
480 }
481 
483 template<class T>
484 inline bool operator>(rational<T> const& a, rational<T> const& b)
485 {
486  return b < a;
487 }
488 
490 template<class T>
491 inline bool operator>(rational<T> const& a, T const& b)
492 {
493  return b < a;
494 }
495 
497 template<class T>
498 inline bool operator>(T const& a, rational<T> const& b)
499 {
500  return b < a;
501 }
502 
504 template<class T>
505 inline bool operator>=(rational<T> const& a, rational<T> const& b)
506 {
507  return not (b > a);
508 }
509 
511 template<class T>
512 inline bool operator>=(rational<T> const& a, T const& b)
513 {
514  return not (b > a);
515 }
516 
518 template<class T>
519 inline bool operator>=(T const& a, rational<T> const& b)
520 {
521  return not (b > a);
522 }
523 
525 template<class T, class Char, class Traits>
526 std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, rational<T>& rat)
527 {
528  typename std::basic_istream<Char, Traits>::sentry sentry{in, false};
529  ioflags flags{in};
530 
531  T n{};
532  if (not (in >> n))
533  // Error reading the numerator.
534  return in;
535 
536  in >> std::noskipws;
537  char sep{};
538  if (not (in >> sep))
539  // Error reading the separator character.
540  return in;
541  else if (sep != '/')
542  {
543  // Push sep back into the input stream, so the next input operation
544  // will read it.
545  in.unget();
546  rat = n;
547  return in;
548  }
549  else
550  {
551  T d{};
552  if (in >> d)
553  // Successfully read numerator, separator, and denominator.
554  rat = rational<T>{n, d};
555  }
556 
557  return in;
558 }
559 
561 template<class T, class Char, class Traits>
562 std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, rational<T> const& rat)
563 {
564  typename std::basic_ostream<Char, Traits>::sentry sentry{out};
565  std::ostringstream stream;
566  stream << rat.numerator() << '/' << rat.denominator();
567  out << stream.str();
568  return out;
569 }
570 
571 #endif
bool operator!=(number a, number b)
Definition: number.hpp:149
rational & operator=(value_type)
Assignment of an integer.
Definition: rational.hpp:165
bool operator==(number a, number b)
Definition: number.hpp:138
value_type denominator() const
Return the denominator.
Definition: rational.hpp:52
rational< T > operator/(rational< T > lhs, rational< T > const &rhs)
Division.
Definition: rational.hpp:373
rational & operator-=(rational const &rhs)
Subtraction assignment operator.
Definition: rational.hpp:200
value_type numerator() const
Return the numerator.
Definition: rational.hpp:50
rational & operator--()
Pre-decrement.
Definition: rational.hpp:270
rational< T > absval(rational< T > const &r)
Definition: rational.hpp:292
value_type denominator_
Definition: rational.hpp:109
Save and restore I/O stream flags.
value_type scale(U value)
number operator-(number n)
Definition: number.hpp:202
rational & operator+=(rational const &rhs)
Addition assignment operator.
Definition: rational.hpp:183
zero_denominator(std::string const &what)
Construct the exception object.
Definition: rational.hpp:21
rational(value_type num=0)
Definition: rational.hpp:36
T gcd(T n, T m)
Definition: gcd.hpp:8
rational & operator*=(rational const &rhs)
Multiplication assignment operator.
Definition: rational.hpp:217
rational & operator/=(rational const &rhs)
Division assignment operator.
Definition: rational.hpp:234
std::basic_istream< Char, Traits > & operator>>(std::basic_istream< Char, Traits > &in, rational< T > &rat)
Input operator.
Definition: rational.hpp:526
Represent a rational number (fraction) as a numerator and denominator.
Definition: rational.hpp:26
void normalize()
Definition: rational.hpp:144
value_type numerator_
Definition: rational.hpp:108
rational< T > operator+(rational< T > lhs, rational< T > const &rhs)
Addition.
Definition: rational.hpp:300
T value_type
Convenience typedef for the integral type of the numerator and denominator.
Definition: rational.hpp:30
rational< T > operator*(rational< T > lhs, rational< T > const &rhs)
Multiplication.
Definition: rational.hpp:349
rational & operator++()
Pre-increment.
Definition: rational.hpp:255
bool operator>(number a, number b)
Definition: number.hpp:182
Exception class if the denominator is ever zero.
Definition: rational.hpp:17
static constexpr value_type double_divisor
Definition: rational.hpp:106
bool operator>=(number a, number b)
Definition: number.hpp:193
void reduce()
Reduce the numerator and denominator by their GCD.
Definition: rational.hpp:155