]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | /////////////////////////////////////////////////////////////// |
1e59de90 | 2 | // Copyright 2020 John Maddock. Distributed under the Boost |
7c673cae | 3 | // Software License, Version 1.0. (See accompanying file |
92f5a8d4 | 4 | // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt |
7c673cae | 5 | |
1e59de90 TL |
6 | #ifndef BOOST_MULTIPRECISION_RATIONAL_ADAPTOR_HPP |
7 | #define BOOST_MULTIPRECISION_RATIONAL_ADAPTOR_HPP | |
7c673cae | 8 | |
7c673cae | 9 | #include <boost/multiprecision/number.hpp> |
1e59de90 TL |
10 | #include <boost/multiprecision/detail/hash.hpp> |
11 | #include <boost/multiprecision/detail/float128_functions.hpp> | |
12 | #include <boost/multiprecision/detail/no_exceptions_support.hpp> | |
7c673cae | 13 | |
92f5a8d4 TL |
14 | namespace boost { |
15 | namespace multiprecision { | |
16 | namespace backends { | |
7c673cae | 17 | |
1e59de90 | 18 | template <class Backend> |
7c673cae FG |
19 | struct rational_adaptor |
20 | { | |
1e59de90 TL |
21 | // |
22 | // Each backend need to declare 3 type lists which declare the types | |
23 | // with which this can interoperate. These lists must at least contain | |
24 | // the widest type in each category - so "long long" must be the final | |
25 | // type in the signed_types list for example. Any narrower types if not | |
26 | // present in the list will get promoted to the next wider type that is | |
27 | // in the list whenever mixed arithmetic involving that type is encountered. | |
28 | // | |
29 | typedef typename Backend::signed_types signed_types; | |
30 | typedef typename Backend::unsigned_types unsigned_types; | |
31 | typedef typename Backend::float_types float_types; | |
7c673cae | 32 | |
1e59de90 | 33 | typedef typename std::tuple_element<0, unsigned_types>::type ui_type; |
7c673cae | 34 | |
1e59de90 TL |
35 | static Backend get_one() |
36 | { | |
37 | Backend t; | |
38 | t = static_cast<ui_type>(1); | |
39 | return t; | |
40 | } | |
41 | static Backend get_zero() | |
7c673cae | 42 | { |
1e59de90 TL |
43 | Backend t; |
44 | t = static_cast<ui_type>(0); | |
45 | return t; | |
7c673cae | 46 | } |
7c673cae | 47 | |
1e59de90 | 48 | static const Backend& one() |
7c673cae | 49 | { |
1e59de90 TL |
50 | static const Backend result(get_one()); |
51 | return result; | |
52 | } | |
53 | static const Backend& zero() | |
54 | { | |
55 | static const Backend result(get_zero()); | |
56 | return result; | |
7c673cae FG |
57 | } |
58 | ||
1e59de90 | 59 | void normalize() |
7c673cae | 60 | { |
1e59de90 TL |
61 | using default_ops::eval_gcd; |
62 | using default_ops::eval_eq; | |
63 | using default_ops::eval_divide; | |
64 | ||
65 | Backend g, t; | |
66 | eval_gcd(g, m_num, m_denom); | |
67 | if (!eval_eq(g, one())) | |
68 | { | |
69 | eval_divide(t, m_num, g); | |
70 | m_num.swap(t); | |
71 | eval_divide(t, m_denom, g); | |
72 | m_denom = std::move(t); | |
73 | } | |
7c673cae | 74 | } |
1e59de90 TL |
75 | |
76 | // We must have a default constructor: | |
77 | rational_adaptor() | |
78 | : m_num(zero()), m_denom(one()) {} | |
79 | ||
80 | rational_adaptor(const rational_adaptor& o) : m_num(o.m_num), m_denom(o.m_denom) {} | |
81 | rational_adaptor(rational_adaptor&& o) = default; | |
82 | ||
83 | // Optional constructors, we can make this type slightly more efficient | |
84 | // by providing constructors from any type we can handle natively. | |
85 | // These will also cause number<> to be implicitly constructible | |
86 | // from these types unless we make such constructors explicit. | |
87 | // | |
88 | template <class Arithmetic> | |
89 | rational_adaptor(const Arithmetic& val, typename std::enable_if<std::is_constructible<Backend, Arithmetic>::value && !std::is_floating_point<Arithmetic>::value>::type const* = nullptr) | |
90 | : m_num(val), m_denom(one()) {} | |
91 | ||
92 | // | |
93 | // Pass-through 2-arg construction of components: | |
94 | // | |
95 | template <class T, class U> | |
96 | rational_adaptor(const T& a, const U& b, typename std::enable_if<std::is_constructible<Backend, T const&>::value && std::is_constructible<Backend, U const&>::value>::type const* = nullptr) | |
97 | : m_num(a), m_denom(b) | |
7c673cae | 98 | { |
1e59de90 | 99 | normalize(); |
7c673cae | 100 | } |
1e59de90 TL |
101 | template <class T, class U> |
102 | rational_adaptor(T&& a, const U& b, typename std::enable_if<std::is_constructible<Backend, T>::value && std::is_constructible<Backend, U>::value>::type const* = nullptr) | |
103 | : m_num(static_cast<T&&>(a)), m_denom(b) | |
7c673cae | 104 | { |
1e59de90 | 105 | normalize(); |
7c673cae | 106 | } |
1e59de90 TL |
107 | template <class T, class U> |
108 | rational_adaptor(T&& a, U&& b, typename std::enable_if<std::is_constructible<Backend, T>::value && std::is_constructible<Backend, U>::value>::type const* = nullptr) | |
109 | : m_num(static_cast<T&&>(a)), m_denom(static_cast<U&&>(b)) | |
7c673cae | 110 | { |
1e59de90 | 111 | normalize(); |
7c673cae | 112 | } |
1e59de90 TL |
113 | template <class T, class U> |
114 | rational_adaptor(const T& a, U&& b, typename std::enable_if<std::is_constructible<Backend, T>::value && std::is_constructible<Backend, U>::value>::type const* = nullptr) | |
115 | : m_num(a), m_denom(static_cast<U&&>(b)) | |
7c673cae | 116 | { |
1e59de90 TL |
117 | normalize(); |
118 | } | |
119 | // | |
120 | // In the absense of converting constructors, operator= takes the strain. | |
121 | // In addition to the usual suspects, there must be one operator= for each type | |
122 | // listed in signed_types, unsigned_types, and float_types plus a string constructor. | |
123 | // | |
124 | rational_adaptor& operator=(const rational_adaptor& o) = default; | |
125 | rational_adaptor& operator=(rational_adaptor&& o) = default; | |
126 | template <class Arithmetic> | |
127 | inline typename std::enable_if<!std::is_floating_point<Arithmetic>::value, rational_adaptor&>::type operator=(const Arithmetic& i) | |
128 | { | |
129 | m_num = i; | |
130 | m_denom = one(); | |
7c673cae FG |
131 | return *this; |
132 | } | |
92f5a8d4 | 133 | rational_adaptor& operator=(const char* s) |
7c673cae | 134 | { |
1e59de90 TL |
135 | using default_ops::eval_eq; |
136 | ||
92f5a8d4 | 137 | std::string s1; |
1e59de90 | 138 | multiprecision::number<Backend> v1, v2; |
92f5a8d4 TL |
139 | char c; |
140 | bool have_hex = false; | |
1e59de90 | 141 | const char* p = s; // saved for later |
7c673cae | 142 | |
92f5a8d4 | 143 | while ((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')))) |
7c673cae | 144 | { |
92f5a8d4 | 145 | if (c == 'x' || c == 'X') |
7c673cae FG |
146 | have_hex = true; |
147 | s1.append(1, c); | |
148 | ++s; | |
149 | } | |
150 | v1.assign(s1); | |
151 | s1.erase(); | |
92f5a8d4 | 152 | if (c == '/') |
7c673cae FG |
153 | { |
154 | ++s; | |
92f5a8d4 | 155 | while ((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')))) |
7c673cae | 156 | { |
92f5a8d4 | 157 | if (c == 'x' || c == 'X') |
7c673cae FG |
158 | have_hex = true; |
159 | s1.append(1, c); | |
160 | ++s; | |
161 | } | |
162 | v2.assign(s1); | |
163 | } | |
164 | else | |
165 | v2 = 1; | |
92f5a8d4 | 166 | if (*s) |
7c673cae | 167 | { |
1e59de90 TL |
168 | BOOST_MP_THROW_EXCEPTION(std::runtime_error(std::string("Could not parse the string \"") + p + std::string("\" as a valid rational number."))); |
169 | } | |
170 | multiprecision::number<Backend> gcd; | |
171 | eval_gcd(gcd.backend(), v1.backend(), v2.backend()); | |
172 | if (!eval_eq(gcd.backend(), one())) | |
173 | { | |
174 | v1 /= gcd; | |
175 | v2 /= gcd; | |
7c673cae | 176 | } |
1e59de90 TL |
177 | num() = std::move(std::move(v1).backend()); |
178 | denom() = std::move(std::move(v2).backend()); | |
7c673cae FG |
179 | return *this; |
180 | } | |
1e59de90 TL |
181 | template <class Float> |
182 | typename std::enable_if<std::is_floating_point<Float>::value, rational_adaptor&>::type operator=(Float i) | |
183 | { | |
184 | using default_ops::eval_eq; | |
185 | BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp; | |
186 | ||
187 | int e; | |
188 | Float f = frexp(i, &e); | |
189 | #ifdef BOOST_HAS_FLOAT128 | |
190 | f = ldexp(f, std::is_same<float128_type, Float>::value ? 113 : std::numeric_limits<Float>::digits); | |
191 | e -= std::is_same<float128_type, Float>::value ? 113 : std::numeric_limits<Float>::digits; | |
192 | #else | |
193 | f = ldexp(f, std::numeric_limits<Float>::digits); | |
194 | e -= std::numeric_limits<Float>::digits; | |
195 | #endif | |
196 | number<Backend> num(f); | |
197 | number<Backend> denom(1u); | |
198 | if (e > 0) | |
199 | { | |
200 | num <<= e; | |
201 | } | |
202 | else if (e < 0) | |
203 | { | |
204 | denom <<= -e; | |
205 | } | |
206 | number<Backend> gcd; | |
207 | eval_gcd(gcd.backend(), num.backend(), denom.backend()); | |
208 | if (!eval_eq(gcd.backend(), one())) | |
209 | { | |
210 | num /= gcd; | |
211 | denom /= gcd; | |
212 | } | |
213 | this->num() = std::move(std::move(num).backend()); | |
214 | this->denom() = std::move(std::move(denom).backend()); | |
215 | return *this; | |
216 | } | |
217 | ||
7c673cae FG |
218 | void swap(rational_adaptor& o) |
219 | { | |
1e59de90 TL |
220 | m_num.swap(o.m_num); |
221 | m_denom.swap(o.m_denom); | |
7c673cae | 222 | } |
92f5a8d4 | 223 | std::string str(std::streamsize digits, std::ios_base::fmtflags f) const |
7c673cae | 224 | { |
1e59de90 | 225 | using default_ops::eval_eq; |
7c673cae FG |
226 | // |
227 | // We format the string ourselves so we can match what GMP's mpq type does: | |
228 | // | |
1e59de90 TL |
229 | std::string result = num().str(digits, f); |
230 | if (!eval_eq(denom(), one())) | |
7c673cae FG |
231 | { |
232 | result.append(1, '/'); | |
1e59de90 | 233 | result.append(denom().str(digits, f)); |
7c673cae FG |
234 | } |
235 | return result; | |
236 | } | |
237 | void negate() | |
238 | { | |
1e59de90 | 239 | m_num.negate(); |
7c673cae | 240 | } |
92f5a8d4 | 241 | int compare(const rational_adaptor& o) const |
7c673cae | 242 | { |
1e59de90 TL |
243 | std::ptrdiff_t s1 = eval_get_sign(*this); |
244 | std::ptrdiff_t s2 = eval_get_sign(o); | |
245 | if (s1 != s2) | |
246 | { | |
247 | return s1 < s2 ? -1 : 1; | |
248 | } | |
249 | else if (s1 == 0) | |
250 | return 0; // both zero. | |
251 | ||
252 | bool neg = false; | |
253 | if (s1 >= 0) | |
254 | { | |
255 | s1 = eval_msb(num()) + eval_msb(o.denom()); | |
256 | s2 = eval_msb(o.num()) + eval_msb(denom()); | |
257 | } | |
258 | else | |
259 | { | |
260 | Backend t(num()); | |
261 | t.negate(); | |
262 | s1 = eval_msb(t) + eval_msb(o.denom()); | |
263 | t = o.num(); | |
264 | t.negate(); | |
265 | s2 = eval_msb(t) + eval_msb(denom()); | |
266 | neg = true; | |
267 | } | |
268 | s1 -= s2; | |
269 | if (s1 < -1) | |
270 | return neg ? 1 : -1; | |
271 | else if (s1 > 1) | |
272 | return neg ? -1 : 1; | |
273 | ||
274 | Backend t1, t2; | |
275 | eval_multiply(t1, num(), o.denom()); | |
276 | eval_multiply(t2, o.num(), denom()); | |
277 | return t1.compare(t2); | |
7c673cae | 278 | } |
1e59de90 TL |
279 | // |
280 | // Comparison with arithmetic types, default just constructs a temporary: | |
281 | // | |
282 | template <class A> | |
283 | typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, int>::type compare(A i) const | |
7c673cae | 284 | { |
1e59de90 TL |
285 | rational_adaptor t; |
286 | t = i; // Note: construct directly from i if supported. | |
287 | return compare(t); | |
7c673cae | 288 | } |
7c673cae | 289 | |
1e59de90 TL |
290 | Backend& num() { return m_num; } |
291 | const Backend& num()const { return m_num; } | |
292 | Backend& denom() { return m_denom; } | |
293 | const Backend& denom()const { return m_denom; } | |
294 | ||
295 | #ifndef BOOST_MP_STANDALONE | |
7c673cae | 296 | template <class Archive> |
1e59de90 | 297 | void serialize(Archive& ar, const std::integral_constant<bool, true>&) |
7c673cae FG |
298 | { |
299 | // Saving | |
1e59de90 TL |
300 | number<Backend> n(num()), d(denom()); |
301 | ar& boost::make_nvp("numerator", n); | |
302 | ar& boost::make_nvp("denominator", d); | |
7c673cae FG |
303 | } |
304 | template <class Archive> | |
1e59de90 | 305 | void serialize(Archive& ar, const std::integral_constant<bool, false>&) |
7c673cae FG |
306 | { |
307 | // Loading | |
1e59de90 TL |
308 | number<Backend> n, d; |
309 | ar& boost::make_nvp("numerator", n); | |
310 | ar& boost::make_nvp("denominator", d); | |
311 | num() = n.backend(); | |
312 | denom() = d.backend(); | |
7c673cae FG |
313 | } |
314 | template <class Archive> | |
315 | void serialize(Archive& ar, const unsigned int /*version*/) | |
316 | { | |
1e59de90 TL |
317 | using tag = typename Archive::is_saving; |
318 | using saving_tag = std::integral_constant<bool, tag::value>; | |
319 | serialize(ar, saving_tag()); | |
7c673cae | 320 | } |
1e59de90 TL |
321 | #endif // BOOST_MP_STANDALONE |
322 | ||
92f5a8d4 | 323 | private: |
1e59de90 | 324 | Backend m_num, m_denom; |
7c673cae FG |
325 | }; |
326 | ||
1e59de90 TL |
327 | // |
328 | // Helpers: | |
329 | // | |
330 | template <class T> | |
331 | inline constexpr typename std::enable_if<std::numeric_limits<T>::is_specialized && !std::numeric_limits<T>::is_signed, bool>::type | |
332 | is_minus_one(const T&) | |
7c673cae | 333 | { |
1e59de90 | 334 | return false; |
7c673cae | 335 | } |
1e59de90 TL |
336 | template <class T> |
337 | inline constexpr typename std::enable_if<!std::numeric_limits<T>::is_specialized || std::numeric_limits<T>::is_signed, bool>::type | |
338 | is_minus_one(const T& val) | |
7c673cae | 339 | { |
1e59de90 | 340 | return val == -1; |
7c673cae | 341 | } |
1e59de90 TL |
342 | |
343 | // | |
344 | // Required non-members: | |
345 | // | |
346 | template <class Backend> | |
347 | inline void eval_add(rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b) | |
7c673cae | 348 | { |
1e59de90 | 349 | eval_add_subtract_imp(a, a, b, true); |
7c673cae | 350 | } |
1e59de90 TL |
351 | template <class Backend> |
352 | inline void eval_subtract(rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b) | |
7c673cae | 353 | { |
1e59de90 TL |
354 | eval_add_subtract_imp(a, a, b, false); |
355 | } | |
356 | ||
357 | template <class Backend> | |
358 | inline void eval_multiply(rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b) | |
359 | { | |
360 | eval_multiply_imp(a, a, b.num(), b.denom()); | |
7c673cae FG |
361 | } |
362 | ||
1e59de90 TL |
363 | template <class Backend> |
364 | void eval_divide(rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b) | |
365 | { | |
366 | using default_ops::eval_divide; | |
367 | rational_adaptor<Backend> t; | |
368 | eval_divide(t, a, b); | |
369 | a = std::move(t); | |
370 | } | |
371 | // | |
372 | // Conversions: | |
373 | // | |
7c673cae | 374 | template <class R, class IntBackend> |
1e59de90 | 375 | inline typename std::enable_if<number_category<R>::value == number_kind_floating_point>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend) |
7c673cae FG |
376 | { |
377 | // | |
378 | // The generic conversion is as good as anything we can write here: | |
379 | // | |
380 | ::boost::multiprecision::detail::generic_convert_rational_to_float(*result, backend); | |
381 | } | |
382 | ||
383 | template <class R, class IntBackend> | |
1e59de90 | 384 | inline typename std::enable_if<(number_category<R>::value != number_kind_integer) && (number_category<R>::value != number_kind_floating_point) && !std::is_enum<R>::value>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend) |
7c673cae | 385 | { |
1e59de90 TL |
386 | using default_ops::eval_convert_to; |
387 | R d; | |
388 | eval_convert_to(result, backend.num()); | |
389 | eval_convert_to(&d, backend.denom()); | |
390 | *result /= d; | |
7c673cae FG |
391 | } |
392 | ||
1e59de90 TL |
393 | template <class R, class Backend> |
394 | inline typename std::enable_if<number_category<R>::value == number_kind_integer>::type eval_convert_to(R* result, const rational_adaptor<Backend>& backend) | |
7c673cae | 395 | { |
1e59de90 TL |
396 | using default_ops::eval_divide; |
397 | using default_ops::eval_convert_to; | |
398 | Backend t; | |
399 | eval_divide(t, backend.num(), backend.denom()); | |
400 | eval_convert_to(result, t); | |
7c673cae FG |
401 | } |
402 | ||
1e59de90 TL |
403 | // |
404 | // Hashing support, not strictly required, but it is used in our tests: | |
405 | // | |
406 | template <class Backend> | |
407 | inline std::size_t hash_value(const rational_adaptor<Backend>& arg) | |
408 | { | |
409 | std::size_t result = hash_value(arg.num()); | |
410 | std::size_t result2 = hash_value(arg.denom()); | |
411 | boost::multiprecision::detail::hash_combine(result, result2); | |
412 | return result; | |
413 | } | |
414 | // | |
415 | // assign_components: | |
416 | // | |
417 | template <class Backend> | |
418 | void assign_components(rational_adaptor<Backend>& result, Backend const& a, Backend const& b) | |
419 | { | |
420 | using default_ops::eval_gcd; | |
421 | using default_ops::eval_divide; | |
422 | using default_ops::eval_eq; | |
423 | ||
424 | Backend g; | |
425 | eval_gcd(g, a, b); | |
426 | if (eval_eq(g, rational_adaptor<Backend>::one())) | |
427 | { | |
428 | result.num() = a; | |
429 | result.denom() = b; | |
430 | } | |
431 | else | |
432 | { | |
433 | eval_divide(result.num(), a, g); | |
434 | eval_divide(result.denom(), b, g); | |
435 | } | |
436 | } | |
437 | // | |
438 | // Again for arithmetic types, overload for whatever arithmetic types are directly supported: | |
439 | // | |
440 | template <class Backend, class Arithmetic1, class Arithmetic2> | |
441 | inline void assign_components(rational_adaptor<Backend>& result, const Arithmetic1& a, const Arithmetic2& b) | |
442 | { | |
443 | using default_ops::eval_gcd; | |
444 | using default_ops::eval_divide; | |
445 | using default_ops::eval_eq; | |
446 | ||
447 | Backend g; | |
448 | result.num() = a; | |
449 | eval_gcd(g, result.num(), b); | |
450 | if (eval_eq(g, rational_adaptor<Backend>::one())) | |
451 | { | |
452 | result.denom() = b; | |
453 | } | |
454 | else | |
455 | { | |
456 | eval_divide(result.num(), g); | |
457 | eval_divide(result.denom(), b, g); | |
458 | } | |
459 | } | |
460 | // | |
461 | // Optional comparison operators: | |
462 | // | |
463 | template <class Backend> | |
464 | inline bool eval_is_zero(const rational_adaptor<Backend>& arg) | |
7c673cae | 465 | { |
92f5a8d4 | 466 | using default_ops::eval_is_zero; |
1e59de90 | 467 | return eval_is_zero(arg.num()); |
7c673cae | 468 | } |
1e59de90 TL |
469 | |
470 | template <class Backend> | |
471 | inline int eval_get_sign(const rational_adaptor<Backend>& arg) | |
7c673cae | 472 | { |
92f5a8d4 | 473 | using default_ops::eval_get_sign; |
1e59de90 | 474 | return eval_get_sign(arg.num()); |
7c673cae FG |
475 | } |
476 | ||
1e59de90 TL |
477 | template <class Backend> |
478 | inline bool eval_eq(const rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b) | |
7c673cae | 479 | { |
1e59de90 TL |
480 | using default_ops::eval_eq; |
481 | return eval_eq(a.num(), b.num()) && eval_eq(a.denom(), b.denom()); | |
7c673cae FG |
482 | } |
483 | ||
1e59de90 TL |
484 | template <class Backend, class Arithmetic> |
485 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value&& std::is_integral<Arithmetic>::value, bool>::type | |
486 | eval_eq(const rational_adaptor<Backend>& a, Arithmetic b) | |
7c673cae | 487 | { |
1e59de90 TL |
488 | using default_ops::eval_eq; |
489 | return eval_eq(a.denom(), rational_adaptor<Backend>::one()) && eval_eq(a.num(), b); | |
490 | } | |
491 | ||
492 | template <class Backend, class Arithmetic> | |
493 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value&& std::is_integral<Arithmetic>::value, bool>::type | |
494 | eval_eq(Arithmetic b, const rational_adaptor<Backend>& a) | |
495 | { | |
496 | using default_ops::eval_eq; | |
497 | return eval_eq(a.denom(), rational_adaptor<Backend>::one()) && eval_eq(a.num(), b); | |
498 | } | |
499 | ||
500 | // | |
501 | // Arithmetic operations, starting with addition: | |
502 | // | |
503 | template <class Backend, class Arithmetic> | |
504 | void eval_add_subtract_imp(rational_adaptor<Backend>& result, const Arithmetic& arg, bool isaddition) | |
505 | { | |
506 | using default_ops::eval_multiply; | |
507 | using default_ops::eval_divide; | |
508 | using default_ops::eval_add; | |
509 | using default_ops::eval_gcd; | |
510 | Backend t; | |
511 | eval_multiply(t, result.denom(), arg); | |
512 | if (isaddition) | |
513 | eval_add(result.num(), t); | |
514 | else | |
515 | eval_subtract(result.num(), t); | |
516 | // | |
517 | // There is no need to re-normalize here, we have | |
518 | // (a + bm) / b | |
519 | // and gcd(a + bm, b) = gcd(a, b) = 1 | |
520 | // | |
521 | /* | |
522 | eval_gcd(t, result.num(), result.denom()); | |
523 | if (!eval_eq(t, rational_adaptor<Backend>::one()) != 0) | |
524 | { | |
525 | Backend t2; | |
526 | eval_divide(t2, result.num(), t); | |
527 | t2.swap(result.num()); | |
528 | eval_divide(t2, result.denom(), t); | |
529 | t2.swap(result.denom()); | |
530 | } | |
531 | */ | |
532 | } | |
533 | ||
534 | template <class Backend, class Arithmetic> | |
535 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && (std::is_integral<Arithmetic>::value || std::is_same<Arithmetic, Backend>::value)>::type | |
536 | eval_add(rational_adaptor<Backend>& result, const Arithmetic& arg) | |
537 | { | |
538 | eval_add_subtract_imp(result, arg, true); | |
539 | } | |
540 | ||
541 | template <class Backend, class Arithmetic> | |
542 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && (std::is_integral<Arithmetic>::value || std::is_same<Arithmetic, Backend>::value)>::type | |
543 | eval_subtract(rational_adaptor<Backend>& result, const Arithmetic& arg) | |
544 | { | |
545 | eval_add_subtract_imp(result, arg, false); | |
546 | } | |
547 | ||
548 | template <class Backend> | |
549 | void eval_add_subtract_imp(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b, bool isaddition) | |
550 | { | |
551 | using default_ops::eval_eq; | |
552 | using default_ops::eval_multiply; | |
553 | using default_ops::eval_divide; | |
554 | using default_ops::eval_add; | |
555 | using default_ops::eval_subtract; | |
556 | // | |
557 | // Let a = an/ad | |
558 | // b = bn/bd | |
559 | // g = gcd(ad, bd) | |
560 | // result = rn/rd | |
561 | // | |
562 | // Then: | |
563 | // rn = an * (bd/g) + bn * (ad/g) | |
564 | // rd = ad * (bd/g) | |
565 | // = (ad/g) * (bd/g) * g | |
566 | // | |
567 | // And the whole thing can then be rescaled by | |
568 | // gcd(rn, g) | |
569 | // | |
570 | Backend gcd, t1, t2, t3, t4; | |
571 | // | |
572 | // Begin by getting the gcd of the 2 denominators: | |
573 | // | |
574 | eval_gcd(gcd, a.denom(), b.denom()); | |
575 | // | |
576 | // Do we have gcd > 1: | |
577 | // | |
578 | if (!eval_eq(gcd, rational_adaptor<Backend>::one())) | |
579 | { | |
580 | // | |
581 | // Scale the denominators by gcd, and put the results in t1 and t2: | |
582 | // | |
583 | eval_divide(t1, b.denom(), gcd); | |
584 | eval_divide(t2, a.denom(), gcd); | |
585 | // | |
586 | // multiply the numerators by the scale denominators and put the results in t3, t4: | |
587 | // | |
588 | eval_multiply(t3, a.num(), t1); | |
589 | eval_multiply(t4, b.num(), t2); | |
590 | // | |
591 | // Add them up: | |
592 | // | |
593 | if (isaddition) | |
594 | eval_add(t3, t4); | |
595 | else | |
596 | eval_subtract(t3, t4); | |
597 | // | |
598 | // Get the gcd of gcd and our numerator (t3): | |
599 | // | |
600 | eval_gcd(t4, t3, gcd); | |
601 | if (eval_eq(t4, rational_adaptor<Backend>::one())) | |
602 | { | |
603 | result.num() = t3; | |
604 | eval_multiply(result.denom(), t1, a.denom()); | |
605 | } | |
606 | else | |
607 | { | |
608 | // | |
609 | // Uncommon case where gcd is not 1, divide the numerator | |
610 | // and the denominator terms by the new gcd. Note we perform division | |
611 | // on the existing gcd value as this is the smallest of the 3 denominator | |
612 | // terms we'll be multiplying together, so there's a good chance it's a | |
613 | // single limb value already: | |
614 | // | |
615 | eval_divide(result.num(), t3, t4); | |
616 | eval_divide(t3, gcd, t4); | |
617 | eval_multiply(t4, t1, t2); | |
618 | eval_multiply(result.denom(), t4, t3); | |
619 | } | |
620 | } | |
621 | else | |
622 | { | |
623 | // | |
624 | // Most common case (approx 60%) where gcd is one: | |
625 | // | |
626 | eval_multiply(t1, a.num(), b.denom()); | |
627 | eval_multiply(t2, a.denom(), b.num()); | |
628 | if (isaddition) | |
629 | eval_add(result.num(), t1, t2); | |
630 | else | |
631 | eval_subtract(result.num(), t1, t2); | |
632 | eval_multiply(result.denom(), a.denom(), b.denom()); | |
633 | } | |
634 | } | |
635 | ||
636 | ||
637 | template <class Backend> | |
638 | inline void eval_add(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b) | |
639 | { | |
640 | eval_add_subtract_imp(result, a, b, true); | |
641 | } | |
642 | template <class Backend> | |
643 | inline void eval_subtract(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b) | |
644 | { | |
645 | eval_add_subtract_imp(result, a, b, false); | |
646 | } | |
647 | ||
648 | template <class Backend, class Arithmetic> | |
649 | void eval_add_subtract_imp(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const Arithmetic& b, bool isaddition) | |
650 | { | |
651 | using default_ops::eval_add; | |
652 | using default_ops::eval_subtract; | |
653 | using default_ops::eval_multiply; | |
654 | ||
655 | if (&result == &a) | |
656 | return eval_add_subtract_imp(result, b, isaddition); | |
657 | ||
658 | eval_multiply(result.num(), a.denom(), b); | |
659 | if (isaddition) | |
660 | eval_add(result.num(), a.num()); | |
661 | else | |
662 | BOOST_IF_CONSTEXPR(std::numeric_limits<Backend>::is_signed == false) | |
663 | { | |
664 | Backend t; | |
665 | eval_subtract(t, a.num(), result.num()); | |
666 | result.num() = std::move(t); | |
667 | } | |
668 | else | |
669 | { | |
670 | eval_subtract(result.num(), a.num()); | |
671 | result.negate(); | |
672 | } | |
673 | result.denom() = a.denom(); | |
674 | // | |
675 | // There is no need to re-normalize here, we have | |
676 | // (a + bm) / b | |
677 | // and gcd(a + bm, b) = gcd(a, b) = 1 | |
678 | // | |
679 | } | |
680 | template <class Backend, class Arithmetic> | |
681 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && (std::is_integral<Arithmetic>::value || std::is_same<Arithmetic, Backend>::value)>::type | |
682 | eval_add(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const Arithmetic& b) | |
683 | { | |
684 | eval_add_subtract_imp(result, a, b, true); | |
685 | } | |
686 | template <class Backend, class Arithmetic> | |
687 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && (std::is_integral<Arithmetic>::value || std::is_same<Arithmetic, Backend>::value)>::type | |
688 | eval_subtract(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const Arithmetic& b) | |
689 | { | |
690 | eval_add_subtract_imp(result, a, b, false); | |
691 | } | |
692 | ||
693 | // | |
694 | // Multiplication: | |
695 | // | |
696 | template <class Backend> | |
697 | void eval_multiply_imp(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const Backend& b_num, const Backend& b_denom) | |
698 | { | |
699 | using default_ops::eval_multiply; | |
700 | using default_ops::eval_divide; | |
701 | using default_ops::eval_gcd; | |
702 | using default_ops::eval_get_sign; | |
703 | using default_ops::eval_eq; | |
704 | ||
705 | Backend gcd_left, gcd_right, t1, t2; | |
706 | eval_gcd(gcd_left, a.num(), b_denom); | |
707 | eval_gcd(gcd_right, b_num, a.denom()); | |
708 | // | |
709 | // Unit gcd's are the most likely case: | |
710 | // | |
711 | bool b_left = eval_eq(gcd_left, rational_adaptor<Backend>::one()); | |
712 | bool b_right = eval_eq(gcd_right, rational_adaptor<Backend>::one()); | |
713 | ||
714 | if (b_left && b_right) | |
715 | { | |
716 | eval_multiply(result.num(), a.num(), b_num); | |
717 | eval_multiply(result.denom(), a.denom(), b_denom); | |
718 | } | |
719 | else if (b_left) | |
720 | { | |
721 | eval_divide(t2, b_num, gcd_right); | |
722 | eval_multiply(result.num(), a.num(), t2); | |
723 | eval_divide(t1, a.denom(), gcd_right); | |
724 | eval_multiply(result.denom(), t1, b_denom); | |
725 | } | |
726 | else if (b_right) | |
727 | { | |
728 | eval_divide(t1, a.num(), gcd_left); | |
729 | eval_multiply(result.num(), t1, b_num); | |
730 | eval_divide(t2, b_denom, gcd_left); | |
731 | eval_multiply(result.denom(), a.denom(), t2); | |
732 | } | |
733 | else | |
734 | { | |
735 | eval_divide(t1, a.num(), gcd_left); | |
736 | eval_divide(t2, b_num, gcd_right); | |
737 | eval_multiply(result.num(), t1, t2); | |
738 | eval_divide(t1, a.denom(), gcd_right); | |
739 | eval_divide(t2, b_denom, gcd_left); | |
740 | eval_multiply(result.denom(), t1, t2); | |
741 | } | |
742 | // | |
743 | // We may have b_denom negative if this is actually division, if so just correct things now: | |
744 | // | |
745 | if (eval_get_sign(b_denom) < 0) | |
746 | { | |
747 | result.num().negate(); | |
748 | result.denom().negate(); | |
749 | } | |
750 | } | |
751 | ||
752 | template <class Backend> | |
753 | void eval_multiply(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b) | |
754 | { | |
755 | using default_ops::eval_multiply; | |
756 | ||
757 | if (&a == &b) | |
758 | { | |
759 | // squaring, gcd's are 1: | |
760 | eval_multiply(result.num(), a.num(), b.num()); | |
761 | eval_multiply(result.denom(), a.denom(), b.denom()); | |
762 | return; | |
763 | } | |
764 | eval_multiply_imp(result, a, b.num(), b.denom()); | |
765 | } | |
766 | ||
767 | template <class Backend, class Arithmetic> | |
768 | void eval_multiply_imp(Backend& result_num, Backend& result_denom, Arithmetic arg) | |
769 | { | |
770 | if (arg == 0) | |
771 | { | |
772 | result_num = rational_adaptor<Backend>::zero(); | |
773 | result_denom = rational_adaptor<Backend>::one(); | |
774 | return; | |
775 | } | |
776 | else if (arg == 1) | |
777 | return; | |
778 | ||
779 | using default_ops::eval_multiply; | |
780 | using default_ops::eval_divide; | |
781 | using default_ops::eval_gcd; | |
782 | using default_ops::eval_convert_to; | |
783 | ||
784 | Backend gcd, t; | |
785 | Arithmetic integer_gcd; | |
786 | eval_gcd(gcd, result_denom, arg); | |
787 | eval_convert_to(&integer_gcd, gcd); | |
788 | arg /= integer_gcd; | |
789 | if (boost::multiprecision::detail::unsigned_abs(arg) > 1) | |
790 | { | |
791 | eval_multiply(t, result_num, arg); | |
792 | result_num = std::move(t); | |
793 | } | |
794 | else if (is_minus_one(arg)) | |
795 | result_num.negate(); | |
796 | if (integer_gcd > 1) | |
797 | { | |
798 | eval_divide(t, result_denom, integer_gcd); | |
799 | result_denom = std::move(t); | |
800 | } | |
801 | } | |
802 | template <class Backend> | |
803 | void eval_multiply_imp(Backend& result_num, Backend& result_denom, Backend arg) | |
804 | { | |
805 | using default_ops::eval_multiply; | |
806 | using default_ops::eval_divide; | |
807 | using default_ops::eval_gcd; | |
808 | using default_ops::eval_convert_to; | |
809 | using default_ops::eval_is_zero; | |
810 | using default_ops::eval_eq; | |
811 | using default_ops::eval_get_sign; | |
812 | ||
813 | if (eval_is_zero(arg)) | |
814 | { | |
815 | result_num = rational_adaptor<Backend>::zero(); | |
816 | result_denom = rational_adaptor<Backend>::one(); | |
817 | return; | |
818 | } | |
819 | else if (eval_eq(arg, rational_adaptor<Backend>::one())) | |
820 | return; | |
821 | ||
822 | Backend gcd, t; | |
823 | eval_gcd(gcd, result_denom, arg); | |
824 | if (!eval_eq(gcd, rational_adaptor<Backend>::one())) | |
825 | { | |
826 | eval_divide(t, arg, gcd); | |
827 | arg = t; | |
828 | } | |
829 | else | |
830 | t = arg; | |
831 | if (eval_get_sign(arg) < 0) | |
832 | t.negate(); | |
833 | ||
834 | if (!eval_eq(t, rational_adaptor<Backend>::one())) | |
835 | { | |
836 | eval_multiply(t, result_num, arg); | |
837 | result_num = std::move(t); | |
838 | } | |
839 | else if (eval_get_sign(arg) < 0) | |
840 | result_num.negate(); | |
841 | if (!eval_eq(gcd, rational_adaptor<Backend>::one())) | |
842 | { | |
843 | eval_divide(t, result_denom, gcd); | |
844 | result_denom = std::move(t); | |
845 | } | |
846 | } | |
847 | ||
848 | template <class Backend, class Arithmetic> | |
849 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && (std::is_integral<Arithmetic>::value || std::is_same<Arithmetic, Backend>::value)>::type | |
850 | eval_multiply(rational_adaptor<Backend>& result, const Arithmetic& arg) | |
851 | { | |
852 | eval_multiply_imp(result.num(), result.denom(), arg); | |
853 | } | |
854 | ||
855 | template <class Backend, class Arithmetic> | |
856 | typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && std::is_integral<Arithmetic>::value>::type | |
857 | eval_multiply_imp(rational_adaptor<Backend>& result, const Backend& a_num, const Backend& a_denom, Arithmetic b) | |
858 | { | |
859 | if (b == 0) | |
860 | { | |
861 | result.num() = rational_adaptor<Backend>::zero(); | |
862 | result.denom() = rational_adaptor<Backend>::one(); | |
863 | return; | |
864 | } | |
865 | else if (b == 1) | |
866 | { | |
867 | result.num() = a_num; | |
868 | result.denom() = a_denom; | |
869 | return; | |
870 | } | |
871 | ||
872 | using default_ops::eval_multiply; | |
873 | using default_ops::eval_divide; | |
874 | using default_ops::eval_gcd; | |
875 | using default_ops::eval_convert_to; | |
876 | ||
877 | Backend gcd; | |
878 | Arithmetic integer_gcd; | |
879 | eval_gcd(gcd, a_denom, b); | |
880 | eval_convert_to(&integer_gcd, gcd); | |
881 | b /= integer_gcd; | |
882 | if (boost::multiprecision::detail::unsigned_abs(b) > 1) | |
883 | eval_multiply(result.num(), a_num, b); | |
884 | else if (is_minus_one(b)) | |
885 | { | |
886 | result.num() = a_num; | |
887 | result.num().negate(); | |
888 | } | |
889 | else | |
890 | result.num() = a_num; | |
891 | if (integer_gcd > 1) | |
892 | eval_divide(result.denom(), a_denom, integer_gcd); | |
893 | else | |
894 | result.denom() = a_denom; | |
895 | } | |
896 | template <class Backend> | |
897 | inline void eval_multiply_imp(rational_adaptor<Backend>& result, const Backend& a_num, const Backend& a_denom, const Backend& b) | |
898 | { | |
899 | result.num() = a_num; | |
900 | result.denom() = a_denom; | |
901 | eval_multiply_imp(result.num(), result.denom(), b); | |
902 | } | |
903 | ||
904 | template <class Backend, class Arithmetic> | |
905 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && (std::is_integral<Arithmetic>::value || std::is_same<Arithmetic, Backend>::value)>::type | |
906 | eval_multiply(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const Arithmetic& b) | |
907 | { | |
908 | if (&result == &a) | |
909 | return eval_multiply(result, b); | |
910 | ||
911 | eval_multiply_imp(result, a.num(), a.denom(), b); | |
912 | } | |
913 | ||
914 | template <class Backend, class Arithmetic> | |
915 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && (std::is_integral<Arithmetic>::value || std::is_same<Arithmetic, Backend>::value)>::type | |
916 | eval_multiply(rational_adaptor<Backend>& result, const Arithmetic& b, const rational_adaptor<Backend>& a) | |
917 | { | |
918 | return eval_multiply(result, a, b); | |
919 | } | |
920 | ||
921 | // | |
922 | // Division: | |
923 | // | |
924 | template <class Backend> | |
925 | inline void eval_divide(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, const rational_adaptor<Backend>& b) | |
926 | { | |
927 | using default_ops::eval_multiply; | |
928 | using default_ops::eval_get_sign; | |
929 | ||
930 | if (eval_get_sign(b.num()) == 0) | |
931 | { | |
932 | BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero")); | |
933 | return; | |
934 | } | |
935 | if (&a == &b) | |
936 | { | |
937 | // Huh? Really? | |
938 | result.num() = result.denom() = rational_adaptor<Backend>::one(); | |
939 | return; | |
940 | } | |
941 | if (&result == &b) | |
942 | { | |
943 | rational_adaptor<Backend> t(b); | |
944 | return eval_divide(result, a, t); | |
945 | } | |
946 | eval_multiply_imp(result, a, b.denom(), b.num()); | |
947 | } | |
948 | ||
949 | template <class Backend, class Arithmetic> | |
950 | inline typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && (std::is_integral<Arithmetic>::value || std::is_same<Arithmetic, Backend>::value)>::type | |
951 | eval_divide(rational_adaptor<Backend>& result, const Arithmetic& b, const rational_adaptor<Backend>& a) | |
952 | { | |
953 | using default_ops::eval_get_sign; | |
954 | ||
955 | if (eval_get_sign(a.num()) == 0) | |
956 | { | |
957 | BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero")); | |
958 | return; | |
959 | } | |
960 | if (&a == &result) | |
961 | { | |
962 | eval_multiply_imp(result.denom(), result.num(), b); | |
963 | result.num().swap(result.denom()); | |
964 | } | |
965 | else | |
966 | eval_multiply_imp(result, a.denom(), a.num(), b); | |
967 | ||
968 | if (eval_get_sign(result.denom()) < 0) | |
969 | { | |
970 | result.num().negate(); | |
971 | result.denom().negate(); | |
972 | } | |
973 | } | |
974 | ||
975 | template <class Backend, class Arithmetic> | |
976 | typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && std::is_integral<Arithmetic>::value>::type | |
977 | eval_divide(rational_adaptor<Backend>& result, Arithmetic arg) | |
978 | { | |
979 | if (arg == 0) | |
980 | { | |
981 | BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero")); | |
982 | return; | |
983 | } | |
984 | else if (arg == 1) | |
985 | return; | |
986 | else if (is_minus_one(arg)) | |
987 | { | |
988 | result.negate(); | |
989 | return; | |
990 | } | |
991 | if (eval_get_sign(result) == 0) | |
992 | { | |
993 | return; | |
994 | } | |
995 | ||
996 | ||
997 | using default_ops::eval_multiply; | |
998 | using default_ops::eval_gcd; | |
999 | using default_ops::eval_convert_to; | |
1000 | using default_ops::eval_divide; | |
1001 | ||
1002 | Backend gcd, t; | |
1003 | Arithmetic integer_gcd; | |
1004 | eval_gcd(gcd, result.num(), arg); | |
1005 | eval_convert_to(&integer_gcd, gcd); | |
1006 | arg /= integer_gcd; | |
1007 | ||
1008 | eval_multiply(t, result.denom(), boost::multiprecision::detail::unsigned_abs(arg)); | |
1009 | result.denom() = std::move(t); | |
1010 | if (arg < 0) | |
1011 | { | |
1012 | result.num().negate(); | |
1013 | } | |
1014 | if (integer_gcd > 1) | |
1015 | { | |
1016 | eval_divide(t, result.num(), integer_gcd); | |
1017 | result.num() = std::move(t); | |
1018 | } | |
1019 | } | |
1020 | template <class Backend> | |
1021 | void eval_divide(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, Backend arg) | |
1022 | { | |
1023 | using default_ops::eval_multiply; | |
1024 | using default_ops::eval_gcd; | |
1025 | using default_ops::eval_convert_to; | |
1026 | using default_ops::eval_divide; | |
1027 | using default_ops::eval_is_zero; | |
1028 | using default_ops::eval_eq; | |
1029 | using default_ops::eval_get_sign; | |
1030 | ||
1031 | if (eval_is_zero(arg)) | |
1032 | { | |
1033 | BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero")); | |
1034 | return; | |
1035 | } | |
1036 | else if (eval_eq(a, rational_adaptor<Backend>::one()) || (eval_get_sign(a) == 0)) | |
1037 | { | |
1038 | if (&result != &a) | |
1039 | result = a; | |
1040 | return; | |
1041 | } | |
1042 | ||
1043 | Backend gcd, u_arg, t; | |
1044 | eval_gcd(gcd, a.num(), arg); | |
1045 | bool has_unit_gcd = eval_eq(gcd, rational_adaptor<Backend>::one()); | |
1046 | if (!has_unit_gcd) | |
1047 | { | |
1048 | eval_divide(u_arg, arg, gcd); | |
1049 | arg = u_arg; | |
1050 | } | |
1051 | else | |
1052 | u_arg = arg; | |
1053 | if (eval_get_sign(u_arg) < 0) | |
1054 | u_arg.negate(); | |
1055 | ||
1056 | eval_multiply(t, a.denom(), u_arg); | |
1057 | result.denom() = std::move(t); | |
1058 | ||
1059 | if (!has_unit_gcd) | |
1060 | { | |
1061 | eval_divide(t, a.num(), gcd); | |
1062 | result.num() = std::move(t); | |
1063 | } | |
1064 | else if (&result != &a) | |
1065 | result.num() = a.num(); | |
1066 | ||
1067 | if (eval_get_sign(arg) < 0) | |
1068 | { | |
1069 | result.num().negate(); | |
1070 | } | |
1071 | } | |
1072 | template <class Backend> | |
1073 | void eval_divide(rational_adaptor<Backend>& result, Backend arg) | |
1074 | { | |
1075 | eval_divide(result, result, arg); | |
1076 | } | |
1077 | ||
1078 | template <class Backend, class Arithmetic> | |
1079 | typename std::enable_if<std::is_convertible<Arithmetic, Backend>::value && std::is_integral<Arithmetic>::value>::type | |
1080 | eval_divide(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& a, Arithmetic arg) | |
1081 | { | |
1082 | if (&result == &a) | |
1083 | return eval_divide(result, arg); | |
1084 | if (arg == 0) | |
1085 | { | |
1086 | BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero")); | |
1087 | return; | |
1088 | } | |
1089 | else if (arg == 1) | |
1090 | { | |
1091 | result = a; | |
1092 | return; | |
1093 | } | |
1094 | else if (is_minus_one(arg)) | |
1095 | { | |
1096 | result = a; | |
1097 | result.num().negate(); | |
1098 | return; | |
1099 | } | |
1100 | ||
1101 | if (eval_get_sign(a) == 0) | |
1102 | { | |
1103 | result = a; | |
1104 | return; | |
1105 | } | |
1106 | ||
1107 | using default_ops::eval_multiply; | |
1108 | using default_ops::eval_divide; | |
1109 | using default_ops::eval_gcd; | |
1110 | using default_ops::eval_convert_to; | |
1111 | ||
1112 | Backend gcd; | |
1113 | Arithmetic integer_gcd; | |
1114 | eval_gcd(gcd, a.num(), arg); | |
1115 | eval_convert_to(&integer_gcd, gcd); | |
1116 | arg /= integer_gcd; | |
1117 | eval_multiply(result.denom(), a.denom(), boost::multiprecision::detail::unsigned_abs(arg)); | |
1118 | ||
1119 | if (integer_gcd > 1) | |
1120 | { | |
1121 | eval_divide(result.num(), a.num(), integer_gcd); | |
1122 | } | |
1123 | else | |
1124 | result.num() = a.num(); | |
1125 | if (arg < 0) | |
1126 | { | |
1127 | result.num().negate(); | |
1128 | } | |
1129 | } | |
1130 | ||
1131 | // | |
1132 | // Increment and decrement: | |
1133 | // | |
1134 | template <class Backend> | |
1135 | inline void eval_increment(rational_adaptor<Backend>& arg) | |
1136 | { | |
1137 | using default_ops::eval_add; | |
1138 | eval_add(arg.num(), arg.denom()); | |
1139 | } | |
1140 | template <class Backend> | |
1141 | inline void eval_decrement(rational_adaptor<Backend>& arg) | |
1142 | { | |
1143 | using default_ops::eval_subtract; | |
1144 | eval_subtract(arg.num(), arg.denom()); | |
1145 | } | |
1146 | ||
1147 | // | |
1148 | // abs: | |
1149 | // | |
1150 | template <class Backend> | |
1151 | inline void eval_abs(rational_adaptor<Backend>& result, const rational_adaptor<Backend>& arg) | |
1152 | { | |
1153 | using default_ops::eval_abs; | |
1154 | eval_abs(result.num(), arg.num()); | |
1155 | result.denom() = arg.denom(); | |
7c673cae FG |
1156 | } |
1157 | ||
7c673cae FG |
1158 | } // namespace backends |
1159 | ||
1e59de90 TL |
1160 | // |
1161 | // Import the backend into this namespace: | |
1162 | // | |
1163 | using boost::multiprecision::backends::rational_adaptor; | |
1164 | // | |
1165 | // Define a category for this number type, one of: | |
1166 | // | |
1167 | // number_kind_integer | |
1168 | // number_kind_floating_point | |
1169 | // number_kind_rational | |
1170 | // number_kind_fixed_point | |
1171 | // number_kind_complex | |
1172 | // | |
1173 | template<class Backend> | |
1174 | struct number_category<rational_adaptor<Backend> > : public std::integral_constant<int, number_kind_rational> | |
92f5a8d4 TL |
1175 | {}; |
1176 | ||
1177 | template <class IntBackend> | |
1e59de90 | 1178 | struct expression_template_default<backends::rational_adaptor<IntBackend> > : public expression_template_default<IntBackend> |
92f5a8d4 | 1179 | {}; |
7c673cae | 1180 | |
92f5a8d4 | 1181 | template <class Backend, expression_template_option ExpressionTemplates> |
1e59de90 | 1182 | struct component_type<number<rational_adaptor<Backend>, ExpressionTemplates> > |
7c673cae | 1183 | { |
92f5a8d4 | 1184 | typedef number<Backend, ExpressionTemplates> type; |
7c673cae FG |
1185 | }; |
1186 | ||
1187 | template <class IntBackend, expression_template_option ET> | |
1188 | inline number<IntBackend, ET> numerator(const number<rational_adaptor<IntBackend>, ET>& val) | |
1189 | { | |
1e59de90 | 1190 | return val.backend().num(); |
7c673cae FG |
1191 | } |
1192 | template <class IntBackend, expression_template_option ET> | |
1193 | inline number<IntBackend, ET> denominator(const number<rational_adaptor<IntBackend>, ET>& val) | |
1194 | { | |
1e59de90 | 1195 | return val.backend().denom(); |
7c673cae FG |
1196 | } |
1197 | ||
1e59de90 TL |
1198 | template <class Backend> |
1199 | struct is_unsigned_number<rational_adaptor<Backend> > : public is_unsigned_number<Backend> | |
92f5a8d4 | 1200 | {}; |
7c673cae | 1201 | |
7c673cae | 1202 | |
92f5a8d4 | 1203 | }} // namespace boost::multiprecision |
7c673cae | 1204 | |
92f5a8d4 | 1205 | namespace std { |
7c673cae | 1206 | |
1e59de90 TL |
1207 | template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates> |
1208 | class numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> > : public std::numeric_limits<boost::multiprecision::number<IntBackend, ExpressionTemplates> > | |
1209 | { | |
1210 | using base_type = std::numeric_limits<boost::multiprecision::number<IntBackend> >; | |
1211 | using number_type = boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend> >; | |
7c673cae | 1212 | |
1e59de90 TL |
1213 | public: |
1214 | static constexpr bool is_integer = false; | |
1215 | static constexpr bool is_exact = true; | |
1216 | static constexpr number_type(min)() { return (base_type::min)(); } | |
1217 | static constexpr number_type(max)() { return (base_type::max)(); } | |
1218 | static constexpr number_type lowest() { return -(max)(); } | |
1219 | static constexpr number_type epsilon() { return base_type::epsilon(); } | |
1220 | static constexpr number_type round_error() { return epsilon() / 2; } | |
1221 | static constexpr number_type infinity() { return base_type::infinity(); } | |
1222 | static constexpr number_type quiet_NaN() { return base_type::quiet_NaN(); } | |
1223 | static constexpr number_type signaling_NaN() { return base_type::signaling_NaN(); } | |
1224 | static constexpr number_type denorm_min() { return base_type::denorm_min(); } | |
1225 | }; | |
7c673cae | 1226 | |
1e59de90 TL |
1227 | template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates> |
1228 | constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_integer; | |
1229 | template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates> | |
1230 | constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_exact; | |
7c673cae | 1231 | |
92f5a8d4 | 1232 | } // namespace std |
7c673cae FG |
1233 | |
1234 | #endif |