units
Use physical dimensions at compile-time or run-time.
rational.hpp
Go to the documentation of this file.
1 /// @file vnix/rat/rational.hpp
2 /// @brief Definition of vnix::rat::rational and operators for it.
3 /// @copyright 2019 Thomas E. Vaughan; all rights reserved.
4 /// @license BSD Three-Clause; see LICENSE.
5 
6 #ifndef VNIX_RAT_RATIONAL_HPP
7 #define VNIX_RAT_RATIONAL_HPP
8 
9 #include <iostream>
10 #include <vnix/rat/common-denom.hpp>
11 #include <vnix/rat/encoding.hpp>
12 
13 namespace vnix {
14 
15 /// Classes and functions supporting a model of a fixed-precision rational
16 /// number.
17 namespace rat {
18 
19 
20 /// Model of a fixed-precision rational number.
21 ///
22 /// Numerator and denominator are encoded in same unsigned integer word. They
23 /// form a partition of the bits in the word.
24 ///
25 /// @tparam NB Number of bits for numerator.
26 /// @tparam DB Number of bits for denominator.
27 template <unsigned NB, unsigned DB> class rational : public encoding<NB, DB> {
28  struct dummy_arg {};
29  using P = encoding<NB, DB>;
30 
31 public:
32  using typename P::stype;
33  using typename P::utype;
34 
35 private:
36  /// Construct from encoding.
37  /// @param u Encoding of rational number.
38  constexpr rational(utype u, dummy_arg) : P(u) {}
39 
40 public:
41  using P::d;
42  using P::n;
43 
44  /// Initialize from numerator and denominator.
45  /// @param n Numerator (zero by default).
46  /// @param d Denominator (unity by default).
47  constexpr rational(stype n = 0, stype d = 1)
48  : P(normalized_pair<NB, DB>(n, d)) {}
49 
50  /// Initialize from other rational.
51  /// @tparam ONB Number of numerator-bits in other type of rational.
52  /// @tparam ODB Number of denominator-bits in other type of rational.
53  /// @param r Copy of other rational.
54  template <unsigned ONB, unsigned ODB>
55  constexpr rational(rational<ONB, ODB> r)
56  : P(normalized_pair<NB, DB>(r.n(), r.d())) {}
57 
58  /// Convert to (signed) integer.
59  constexpr stype to_int() const {
60  if (d() != 1) { throw "attempted conversion to integer from fraction"; }
61  return n();
62  }
63 
64  /// Automatically convert to boolean.
65  constexpr bool to_bool() const { return n() != 0; }
66 
67  /// Convert to float.
68  constexpr float to_float() const { return n() * 1.0f / d(); }
69 
70  /// Convert to double.
71  constexpr double to_double() const { return n() * 1.0 / d(); }
72 
73  /// Modify this rational number by adding other rational number.
74  /// @tparam ONB Number of numerator -bits in other rational.
75  /// @tparam ODB Number of denominator-bits in other rational.
76  /// @param r Other rational number.
77  /// @return Reference to this rational number (after addition).
78  template <unsigned ONB, unsigned ODB>
79  constexpr rational &operator+=(rational<ONB, ODB> r);
80 
81  /// Modify this rational number by subtracting other rational number.
82  /// @tparam ONB Number of numerator -bits in other rational.
83  /// @tparam ODB Number of denominator-bits in other rational.
84  /// @param r Other rational number.
85  /// @return Reference to this rational number (after subtraction).
86  template <unsigned ONB, unsigned ODB>
87  constexpr rational &operator-=(rational<ONB, ODB> r);
88 
89  /// Reciprocal of this rational number.
90  constexpr rational reciprocal() const {
91  if (n() == 0) { throw "attempt to take reciprocal of zero"; }
92  if (n() < 0) { return rational(-d(), -n()); }
93  return rational(d(), n());
94  }
95 
96  /// Modify this rational number by multiplying by other rational number.
97  /// @tparam ONB Number of numerator -bits in other rational.
98  /// @tparam ODB Number of denominator-bits in other rational.
99  /// @param r Other rational number.
100  /// @return Reference to this rational number (after multiplication).
101  template <unsigned ONB, unsigned ODB>
102  constexpr rational &operator*=(rational<ONB, ODB> r);
103 
104  /// Modify this rational number by dividing by other rational number.
105  /// @tparam ONB Number of numerator -bits in other rational.
106  /// @tparam ODB Number of denominator-bits in other rational.
107  /// @param r Other rational number.
108  /// @return Reference to this rational number (after division).
109  template <unsigned ONB, unsigned ODB>
110  constexpr rational &operator/=(rational<ONB, ODB> r);
111 
112  /// Encoding from rational number.
113  constexpr static utype encode(rational r) { return r.c_; }
114 
115  /// Rational number from encoding.
116  constexpr static rational decode(utype u) { return {u, dummy_arg()}; }
117 };
118 
119 
120 /// Compare rationals for equality.
121 /// @tparam NB1 Number of numerator -bits in left -hand rational.
122 /// @tparam DB1 Number of denominator-bits in left -hand rational.
123 /// @tparam NB2 Number of numerator -bits in right-hand rational.
124 /// @tparam DB2 Number of denominator-bits in right-hand rational.
125 /// @param r1 Left -hand operand.
126 /// @param r2 Right-hand operand.
127 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
128 constexpr bool operator==(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
129  return r1.n() == r2.n() && r1.d() == r2.d();
130 }
131 
132 
133 /// Compare rationals for inequality.
134 /// @tparam NB1 Number of numerator -bits in left -hand rational.
135 /// @tparam DB1 Number of denominator-bits in left -hand rational.
136 /// @tparam NB2 Number of numerator -bits in right-hand rational.
137 /// @tparam DB2 Number of denominator-bits in right-hand rational.
138 /// @param r1 Left -hand operand.
139 /// @param r2 Right-hand operand.
140 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
141 constexpr bool operator!=(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
142  return !(r1 == r2);
143 }
144 
145 
146 /// Compare for less-than-or-equal ordering with another rational.
147 /// @tparam NB1 Number of numerator -bits in left -hand rational.
148 /// @tparam DB1 Number of denominator-bits in left -hand rational.
149 /// @tparam NB2 Number of numerator -bits in right-hand rational.
150 /// @tparam DB2 Number of denominator-bits in right-hand rational.
151 /// @param r1 Left -hand operand.
152 /// @param r2 Right-hand operand.
153 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
154 constexpr bool operator<=(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
155  auto const c = common_denom(r1, r2);
156  return c.n1 <= c.n2;
157 }
158 
159 
160 /// Compare for less-than ordering with another rational.
161 /// @tparam NB1 Number of numerator -bits in left -hand rational.
162 /// @tparam DB1 Number of denominator-bits in left -hand rational.
163 /// @tparam NB2 Number of numerator -bits in right-hand rational.
164 /// @tparam DB2 Number of denominator-bits in right-hand rational.
165 /// @param r1 Left -hand operand.
166 /// @param r2 Right-hand operand.
167 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
168 constexpr bool operator<(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
169  auto const c = common_denom(r1, r2);
170  return c.n1 < c.n2;
171 }
172 
173 
174 /// Compare for greater-than-or-equal ordering with another rational.
175 /// @tparam NB1 Number of numerator -bits in left -hand rational.
176 /// @tparam DB1 Number of denominator-bits in left -hand rational.
177 /// @tparam NB2 Number of numerator -bits in right-hand rational.
178 /// @tparam DB2 Number of denominator-bits in right-hand rational.
179 /// @param r1 Left -hand operand.
180 /// @param r2 Right-hand operand.
181 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
182 constexpr bool operator>=(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
183  return !(r1 < r2);
184 }
185 
186 
187 /// Compare for greater-than ordering with another rational.
188 /// @tparam NB1 Number of numerator -bits in left -hand rational.
189 /// @tparam DB1 Number of denominator-bits in left -hand rational.
190 /// @tparam NB2 Number of numerator -bits in right-hand rational.
191 /// @tparam DB2 Number of denominator-bits in right-hand rational.
192 /// @param r1 Left -hand operand.
193 /// @param r2 Right-hand operand.
194 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
195 constexpr bool operator>(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
196  return !(r1 <= r2);
197 }
198 
199 
200 /// Copy rational number by way of unary operator+.
201 /// @tparam NB Number of bits for numerator.
202 /// @tparam DB Number of bits for denominator.
203 /// @param r Number to copy.
204 /// @return Copy of number.
205 template <unsigned NB, unsigned DB>
206 constexpr auto operator+(rational<NB, DB> r) {
207  return r;
208 }
209 
210 
211 /// Negate rational number.
212 /// @tparam NB Number of bits for numerator.
213 /// @tparam DB Number of bits for denominator.
214 /// @param r Number to negate.
215 /// @return Negative of number.
216 template <unsigned NB, unsigned DB>
217 constexpr auto operator-(rational<NB, DB> r) {
218  return rational<NB, DB>(-r.n(), r.d());
219 }
220 
221 
222 /// Sum of two rational numbers.
223 /// @tparam NB1 Number of numerator -bits in left -hand rational.
224 /// @tparam DB1 Number of denominator-bits in left -hand rational.
225 /// @tparam NB2 Number of numerator -bits in right-hand rational.
226 /// @tparam DB2 Number of denominator-bits in right-hand rational.
227 /// @param r1 Addend.
228 /// @param r2 Adder.
229 /// @return Sum.
230 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
231 constexpr auto operator+(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
232  auto const c = common_denom(r1, r2);
233  return rational<c.NMR_BITS, c.LCD_BITS>(c.n1 + c.n2, c.lcd);
234 }
235 
236 
237 // Modify rational number by adding other rational number.
238 template <unsigned NB, unsigned DB>
239 template <unsigned ONB, unsigned ODB>
240 constexpr rational<NB, DB> &rational<NB, DB>::
241  operator+=(rational<ONB, ODB> r) {
242  return *this = *this + r;
243 }
244 
245 
246 /// Difference between two rational numbers.
247 /// @tparam NB1 Number of numerator -bits in left -hand rational.
248 /// @tparam DB1 Number of denominator-bits in left -hand rational.
249 /// @tparam NB2 Number of numerator -bits in right-hand rational.
250 /// @tparam DB2 Number of denominator-bits in right-hand rational.
251 /// @param r1 Minuend.
252 /// @param r2 Subtrahend.
253 /// @return Difference.
254 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
255 constexpr auto operator-(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
256  return -r2 + r1;
257 }
258 
259 
260 // Modify this rational number by subtracting other rational number.
261 template <unsigned NB, unsigned DB>
262 template <unsigned ONB, unsigned ODB>
263 constexpr rational<NB, DB> &rational<NB, DB>::
264  operator-=(rational<ONB, ODB> r) {
265  return *this = *this - r;
266 }
267 
268 
269 /// Product of two rational numbers.
270 /// @tparam NB1 Number of numerator -bits in left -hand rational.
271 /// @tparam DB1 Number of denominator-bits in left -hand rational.
272 /// @tparam NB2 Number of numerator -bits in right-hand rational.
273 /// @tparam DB2 Number of denominator-bits in right-hand rational.
274 /// @param r1 Multiplicand.
275 /// @param r2 Multiplier.
276 /// @return Product.
277 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
278 constexpr auto operator*(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
279  auto const n1 = r1.n();
280  auto const n2 = r2.n();
281  auto const d1 = r1.d();
282  auto const d2 = r2.d();
283  auto const ga = gcd(n1, d2);
284  auto const gb = gcd(n2, d1);
285  enum { NB = (NB1 > NB2 ? NB1 : NB2), DB = (DB1 > DB2 ? DB1 : DB2) };
286  using S = typename int_types<NB>::SF;
287  using U = typename int_types<DB>::UF;
288  return rational<NB, DB>(S(n1) / ga * n2 / gb, U(d1) / gb * d2 / ga);
289 }
290 
291 
292 /// Quotient of two rational numbers.
293 /// @tparam NB1 Number of numerator -bits in left -hand rational.
294 /// @tparam DB1 Number of denominator-bits in left -hand rational.
295 /// @tparam NB2 Number of numerator -bits in right-hand rational.
296 /// @tparam DB2 Number of denominator-bits in right-hand rational.
297 /// @param r1 Dividend.
298 /// @param r2 Divisor.
299 /// @return Quotient.
300 template <unsigned NB1, unsigned DB1, unsigned NB2, unsigned DB2>
301 constexpr auto operator/(rational<NB1, DB1> r1, rational<NB2, DB2> r2) {
302  return r1 * r2.reciprocal();
303 }
304 
305 
306 /// Quotient of two rational numbers.
307 /// @tparam NB1 Number of numerator -bits in left -hand rational.
308 /// @tparam DB1 Number of denominator-bits in left -hand rational.
309 /// @param r1 Dividend.
310 /// @param r2 Divisor.
311 /// @return Quotient.
312 template <unsigned NB1, unsigned DB1>
313 constexpr auto operator/(rational<NB1, DB1> r1,
314  typename rational<NB1, DB1>::stype r2) {
315  return r1 * rational<NB1, DB1>(r2).reciprocal();
316 }
317 
318 
319 // Modify this rational number by multiplying by other rational number.
320 template <unsigned NB, unsigned DB>
321 template <unsigned ONB, unsigned ODB>
322 constexpr rational<NB, DB> &rational<NB, DB>::
323  operator*=(rational<ONB, ODB> r) {
324  return *this = (*this) * r;
325 }
326 
327 
328 // Modify this rational number by dividing by other rational number.
329 template <unsigned NB, unsigned DB>
330 template <unsigned ONB, unsigned ODB>
331 constexpr rational<NB, DB> &rational<NB, DB>::
332  operator/=(rational<ONB, ODB> r) {
333  return *this = (*this) / r;
334 }
335 
336 
337 /// Print rational number to output-stream.
338 /// @tparam NB Number of bits for numerator of rational.
339 /// @tparam DB Number of bits for denominator of rational.
340 /// @param s Reference to output-stream.
341 /// @param r Rational number.
342 /// @return Reference to modified output-stream.
343 template <unsigned NB, unsigned DB>
344 std::ostream &operator<<(std::ostream &s, rational<NB, DB> r) {
345  s << int_fast64_t(r.n());
346  if (r.d() != 1) { s << '/' << uint_fast64_t(r.d()); }
347  return s;
348 }
349 
350 
351 } // namespace rat
352 } // namespace vnix
353 
354 #endif // ndef VNIX_RAT_RATIONAL_HPP
static constexpr utype encode(rational r)
Encoding from rational number.
Definition: rational.hpp:113
constexpr auto operator-(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Difference between two rational numbers.
Definition: rational.hpp:255
constexpr rational(utype u, dummy_arg)
Construct from encoding.
Definition: rational.hpp:38
constexpr rational< NB, DB > & operator-=(rational< ONB, ODB > r)
Definition: rational.hpp:264
Numerator and denominator of a rational number as separate numbers, not encoded into the same word...
static constexpr rational decode(utype u)
Rational number from encoding.
Definition: rational.hpp:116
constexpr auto operator+(rational< NB, DB > r)
Copy rational number by way of unary operator+.
Definition: rational.hpp:206
constexpr float to_float() const
Convert to float.
Definition: rational.hpp:68
constexpr auto operator/(rational< NB1, DB1 > r1, typename rational< NB1, DB1 >::stype r2)
Quotient of two rational numbers.
Definition: rational.hpp:313
constexpr rational< NB, DB > & operator/=(rational< ONB, ODB > r)
Definition: rational.hpp:332
constexpr auto operator*(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Product of two rational numbers.
Definition: rational.hpp:278
constexpr double to_double() const
Convert to double.
Definition: rational.hpp:71
constexpr rational(rational< ONB, ODB > r)
Initialize from other rational.
Definition: rational.hpp:55
constexpr auto operator+(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Sum of two rational numbers.
Definition: rational.hpp:231
constexpr rational(stype n=0, stype d=1)
Initialize from numerator and denominator.
Definition: rational.hpp:47
Smallest integer types for holding certain number of bits.
Definition: int-types.hpp:21
constexpr rational reciprocal() const
Reciprocal of this rational number.
Definition: rational.hpp:90
constexpr auto operator-(rational< NB, DB > r)
Negate rational number.
Definition: rational.hpp:217
constexpr rational< NB, DB > & operator+=(rational< ONB, ODB > r)
Definition: rational.hpp:241
constexpr bool operator>(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Compare for greater-than ordering with another rational.
Definition: rational.hpp:195
constexpr auto operator/(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Quotient of two rational numbers.
Definition: rational.hpp:301
constexpr stype to_int() const
Convert to (signed) integer.
Definition: rational.hpp:59
constexpr bool operator==(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Compare rationals for equality.
Definition: rational.hpp:128
constexpr bool operator!=(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Compare rationals for inequality.
Definition: rational.hpp:141
constexpr bool to_bool() const
Automatically convert to boolean.
Definition: rational.hpp:65
constexpr bool operator>=(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Compare for greater-than-or-equal ordering with another rational.
Definition: rational.hpp:182
Thomas E. Vaughan&#39;s public software.
Definition: rational.hpp:13
constexpr bool operator<(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Compare for less-than ordering with another rational.
Definition: rational.hpp:168
Model of a fixed-precision rational number.
Definition: rational.hpp:27
constexpr rational< NB, DB > & operator*=(rational< ONB, ODB > r)
Definition: rational.hpp:323
constexpr bool operator<=(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Compare for less-than-or-equal ordering with another rational.
Definition: rational.hpp:154
Classes and functions supporting a model of a fixed-precision rational number.
Definition: rational.hpp:17
Encoding of numerator and denominator into unsigned word.
Definition: encoding.hpp:19