]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/multiprecision/gmp.hpp
17b5230a5a4456278a76b7995da955181cd0bc16
[ceph.git] / ceph / src / boost / boost / multiprecision / gmp.hpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright 2011 John Maddock.
3 // Copyright 2021 Matt Borland. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7 #ifndef BOOST_MATH_ER_GMP_BACKEND_HPP
8 #define BOOST_MATH_ER_GMP_BACKEND_HPP
9
10 #include <boost/multiprecision/detail/standalone_config.hpp>
11 #include <boost/multiprecision/number.hpp>
12 #include <boost/multiprecision/debug_adaptor.hpp>
13 #include <boost/multiprecision/detail/integer_ops.hpp>
14 #include <boost/multiprecision/detail/float128_functions.hpp>
15 #include <boost/multiprecision/detail/digits.hpp>
16 #include <boost/multiprecision/detail/atomic.hpp>
17 #include <boost/multiprecision/detail/hash.hpp>
18 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
19 #include <boost/multiprecision/detail/assert.hpp>
20 #include <boost/multiprecision/detail/fpclassify.hpp>
21 #include <type_traits>
22 #include <memory>
23 #include <utility>
24 #include <cstdint>
25 #include <cmath>
26 #include <cctype>
27 #include <limits>
28 #include <climits>
29 #include <cstdlib>
30 #include <cfloat>
31
32 //
33 // Some includes we need from Boost.Math, since we rely on that library to provide these functions:
34 //
35 #ifdef BOOST_MP_MATH_AVAILABLE
36 #include <boost/math/special_functions/asinh.hpp>
37 #include <boost/math/special_functions/acosh.hpp>
38 #include <boost/math/special_functions/atanh.hpp>
39 #include <boost/math/special_functions/cbrt.hpp>
40 #include <boost/math/special_functions/expm1.hpp>
41 #include <boost/math/special_functions/gamma.hpp>
42 #endif
43
44 #ifdef BOOST_MSVC
45 #pragma warning(push)
46 #pragma warning(disable : 4127)
47 #endif
48 #include <gmp.h>
49 #ifdef BOOST_MSVC
50 #pragma warning(pop)
51 #endif
52
53 #if defined(__MPIR_VERSION) && defined(__MPIR_VERSION_MINOR) && defined(__MPIR_VERSION_PATCHLEVEL)
54 #define BOOST_MP_MPIR_VERSION (__MPIR_VERSION * 10000 + __MPIR_VERSION_MINOR * 100 + __MPIR_VERSION_PATCHLEVEL)
55 #else
56 #define BOOST_MP_MPIR_VERSION 0
57 #endif
58
59 namespace boost {
60 namespace multiprecision {
61 namespace backends {
62
63 #ifdef BOOST_MSVC
64 // warning C4127: conditional expression is constant
65 #pragma warning(push)
66 //#pragma warning(disable : 4127)
67 #endif
68
69 template <unsigned digits10>
70 struct gmp_float;
71 struct gmp_int;
72 struct gmp_rational;
73
74 } // namespace backends
75
76 template <>
77 struct number_category<backends::gmp_int> : public std::integral_constant<int, number_kind_integer>
78 {};
79 template <>
80 struct number_category<backends::gmp_rational> : public std::integral_constant<int, number_kind_rational>
81 {};
82 template <unsigned digits10>
83 struct number_category<backends::gmp_float<digits10> > : public std::integral_constant<int, number_kind_floating_point>
84 {};
85
86 namespace backends {
87 //
88 // Within this file, the only functions we mark as noexcept are those that manipulate
89 // (but don't create) an mpf_t. All other types may allocate at pretty much any time
90 // via a user-supplied allocator, and therefore throw.
91 //
92 namespace detail {
93
94 template <unsigned digits10>
95 struct gmp_float_imp
96 {
97 #ifdef BOOST_HAS_LONG_LONG
98 using signed_types = std::tuple<long, long long> ;
99 using unsigned_types = std::tuple<unsigned long, unsigned long long>;
100 #else
101 using signed_types = std::tuple<long> ;
102 using unsigned_types = std::tuple<unsigned long>;
103 #endif
104 using float_types = std::tuple<double, long double>;
105 using exponent_type = long ;
106
107 gmp_float_imp() noexcept
108 {
109 m_data[0]._mp_d = 0; // uninitialized m_data
110 m_data[0]._mp_prec = 1;
111 }
112
113 gmp_float_imp(const gmp_float_imp& o)
114 {
115 //
116 // We have to do an init followed by a set here, otherwise *this may be at
117 // a lower precision than o: seems like mpf_init_set copies just enough bits
118 // to get the right value, but if it's then used in further calculations
119 // things go badly wrong!!
120 //
121 mpf_init2(m_data, preserve_source_precision() ? mpf_get_prec(o.data()) : boost::multiprecision::detail::digits10_2_2(get_default_precision()));
122 if (o.m_data[0]._mp_d)
123 mpf_set(m_data, o.m_data);
124 }
125 // rvalue copy
126 gmp_float_imp(gmp_float_imp&& o) noexcept
127 {
128 if ((this->get_default_options() == variable_precision_options::preserve_target_precision) && (mpf_get_prec(o.data()) != boost::multiprecision::detail::digits10_2_2(get_default_precision())))
129 {
130 mpf_init2(m_data, boost::multiprecision::detail::digits10_2_2(get_default_precision()));
131 *this = static_cast<const gmp_float_imp&>(o);
132 }
133 else
134 {
135 m_data[0] = o.m_data[0];
136 o.m_data[0]._mp_d = 0;
137 }
138 }
139
140 gmp_float_imp& operator=(const gmp_float_imp& o)
141 {
142 if (m_data[0]._mp_d == 0)
143 {
144 mpf_init2(m_data, preserve_source_precision() ? mpf_get_prec(o.data()) : boost::multiprecision::detail::digits10_2_2(get_default_precision()));
145 mpf_set(m_data, o.m_data);
146 }
147 else if (preserve_source_precision() && (mpf_get_prec(data()) != mpf_get_prec(o.data())))
148 {
149 mpf_t t;
150 mpf_init2(t, mpf_get_prec(o.data()));
151 mpf_set(t, o.data());
152 mpf_swap(data(), t);
153 mpf_clear(t);
154 }
155 else
156 {
157 mpf_set(m_data, o.m_data);
158 }
159 return *this;
160 }
161 // rvalue assign
162 gmp_float_imp& operator=(gmp_float_imp&& o) noexcept
163 {
164 if ((this->get_default_options() == variable_precision_options::preserve_target_precision) && (mpf_get_prec(o.data()) != mpf_get_prec(data())))
165 *this = static_cast<const gmp_float_imp&>(o);
166 else
167 {
168 mpf_swap(m_data, o.m_data);
169 }
170 return *this;
171 }
172
173 #ifdef BOOST_HAS_LONG_LONG
174 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
175 gmp_float_imp& operator=(unsigned long long i)
176 {
177 *this = static_cast<unsigned long>(i);
178 return *this;
179 }
180 #else
181 gmp_float_imp& operator=(unsigned long long i)
182 {
183 if (m_data[0]._mp_d == 0)
184 {
185 mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
186 }
187 unsigned long long mask = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
188 unsigned shift = 0;
189 mpf_t t;
190 mpf_init2(t, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
191 mpf_set_ui(m_data, 0);
192 while (i)
193 {
194 mpf_set_ui(t, static_cast<unsigned long>(i & mask));
195 if (shift)
196 mpf_mul_2exp(t, t, shift);
197 mpf_add(m_data, m_data, t);
198 shift += std::numeric_limits<unsigned long>::digits;
199 i >>= std::numeric_limits<unsigned long>::digits;
200 }
201 mpf_clear(t);
202 return *this;
203 }
204 #endif
205 gmp_float_imp& operator=(long long i)
206 {
207 if (m_data[0]._mp_d == 0)
208 {
209 mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
210 }
211 bool neg = i < 0;
212 *this = static_cast<unsigned long long>(boost::multiprecision::detail::unsigned_abs(i));
213 if (neg)
214 mpf_neg(m_data, m_data);
215 return *this;
216 }
217 #endif
218 gmp_float_imp& operator=(unsigned long i)
219 {
220 if (m_data[0]._mp_d == 0)
221 {
222 mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
223 }
224 mpf_set_ui(m_data, i);
225 return *this;
226 }
227 gmp_float_imp& operator=(long i)
228 {
229 if (m_data[0]._mp_d == 0)
230 {
231 mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
232 }
233 mpf_set_si(m_data, i);
234 return *this;
235 }
236 #ifdef BOOST_HAS_INT128
237 gmp_float_imp& operator=(uint128_type i)
238 {
239 if (m_data[0]._mp_d == 0)
240 {
241 mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
242 }
243 unsigned long mask = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
244 unsigned shift = 0;
245 mpf_t t;
246 mpf_init2(t, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
247 mpf_set_ui(m_data, 0);
248 while (i)
249 {
250 mpf_set_ui(t, static_cast<unsigned long>(i & mask));
251 if (shift)
252 mpf_mul_2exp(t, t, shift);
253 mpf_add(m_data, m_data, t);
254 shift += std::numeric_limits<unsigned long>::digits;
255 i >>= std::numeric_limits<unsigned long>::digits;
256 }
257 mpf_clear(t);
258 return *this;
259 }
260 gmp_float_imp& operator=(int128_type i)
261 {
262 if (m_data[0]._mp_d == 0)
263 {
264 mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
265 }
266 bool neg = i < 0;
267 *this = static_cast<uint128_type>(boost::multiprecision::detail::unsigned_abs(i));
268 if (neg)
269 mpf_neg(m_data, m_data);
270 return *this;
271 }
272 #endif
273 gmp_float_imp& operator=(double d)
274 {
275 if (m_data[0]._mp_d == 0)
276 {
277 mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
278 }
279 mpf_set_d(m_data, d);
280 return *this;
281 }
282 template <class F>
283 gmp_float_imp& assign_float(F a)
284 {
285 BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp;
286
287 if (m_data[0]._mp_d == 0)
288 {
289 mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
290 }
291
292 if (a == 0)
293 {
294 mpf_set_si(m_data, 0);
295 return *this;
296 }
297
298 if (a == 1)
299 {
300 mpf_set_si(m_data, 1);
301 return *this;
302 }
303
304 BOOST_MP_ASSERT(!BOOST_MP_ISINF(a));
305 BOOST_MP_ASSERT(!BOOST_MP_ISNAN(a));
306
307 int e;
308 F f, term;
309 mpf_set_ui(m_data, 0u);
310
311 f = frexp(a, &e);
312
313 constexpr const int shift = std::numeric_limits<int>::digits - 1;
314
315 while (f)
316 {
317 // extract int sized bits from f:
318 f = ldexp(f, shift);
319 term = floor(f);
320 e -= shift;
321 mpf_mul_2exp(m_data, m_data, shift);
322 if (term > 0)
323 mpf_add_ui(m_data, m_data, static_cast<unsigned>(term));
324 else
325 mpf_sub_ui(m_data, m_data, static_cast<unsigned>(-term));
326 f -= term;
327 }
328 if (e > 0)
329 mpf_mul_2exp(m_data, m_data, e);
330 else if (e < 0)
331 mpf_div_2exp(m_data, m_data, -e);
332 return *this;
333 }
334 gmp_float_imp& operator=(long double a)
335 {
336 return assign_float(a);
337 }
338 #ifdef BOOST_HAS_FLOAT128
339 gmp_float_imp& operator= (float128_type a)
340 {
341 return assign_float(a);
342 }
343 #endif
344 gmp_float_imp& operator=(const char* s)
345 {
346 if (m_data[0]._mp_d == 0)
347 {
348 mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
349 }
350 if (s && (*s == '+'))
351 ++s; // Leading "+" sign not supported by mpf_set_str:
352 if (0 != mpf_set_str(m_data, s, 10))
353 BOOST_MP_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid floating point number.")));
354 return *this;
355 }
356 void swap(gmp_float_imp& o) noexcept
357 {
358 mpf_swap(m_data, o.m_data);
359 }
360 std::string str(std::streamsize digits, std::ios_base::fmtflags f) const
361 {
362 BOOST_MP_ASSERT(m_data[0]._mp_d);
363
364 bool scientific = (f & std::ios_base::scientific) == std::ios_base::scientific;
365 bool fixed = (f & std::ios_base::fixed) == std::ios_base::fixed;
366 std::streamsize org_digits(digits);
367
368 if (scientific && digits)
369 ++digits;
370
371 std::string result;
372 mp_exp_t e;
373 void* (*alloc_func_ptr)(size_t);
374 void* (*realloc_func_ptr)(void*, size_t, size_t);
375 void (*free_func_ptr)(void*, size_t);
376 mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
377
378 if (mpf_sgn(m_data) == 0)
379 {
380 e = 0;
381 result = "0";
382 if (fixed && digits)
383 ++digits;
384 }
385 else
386 {
387 char* ps = mpf_get_str(0, &e, 10, static_cast<std::size_t>(digits), m_data);
388 --e; // To match with what our formatter expects.
389 if (fixed)
390 {
391 // Oops we actually need a different number of digits to what we asked for:
392 (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
393 digits += e + 1;
394 if (digits == 0)
395 {
396 // We need to get *all* the digits and then possibly round up,
397 // we end up with either "0" or "1" as the result.
398 ps = mpf_get_str(0, &e, 10, 0, m_data);
399 --e;
400 unsigned offset = *ps == '-' ? 1 : 0;
401 if (ps[offset] > '5')
402 {
403 ++e;
404 ps[offset] = '1';
405 ps[offset + 1] = 0;
406 }
407 else if (ps[offset] == '5')
408 {
409 unsigned i = offset + 1;
410 bool round_up = false;
411 while (ps[i] != 0)
412 {
413 if (ps[i] != '0')
414 {
415 round_up = true;
416 break;
417 }
418 ++i;
419 }
420 if (round_up)
421 {
422 ++e;
423 ps[offset] = '1';
424 ps[offset + 1] = 0;
425 }
426 else
427 {
428 ps[offset] = '0';
429 ps[offset + 1] = 0;
430 }
431 }
432 else
433 {
434 ps[offset] = '0';
435 ps[offset + 1] = 0;
436 }
437 }
438 else if (digits > 0)
439 {
440 mp_exp_t old_e = e;
441 ps = mpf_get_str(0, &e, 10, static_cast<std::size_t>(digits), m_data);
442 --e; // To match with what our formatter expects.
443 if (old_e > e)
444 {
445 // in some cases, when we ask for more digits of precision, it will
446 // change the number of digits to the left of the decimal, if that
447 // happens, account for it here.
448 // example: cout << fixed << setprecision(3) << mpf_float_50("99.9809")
449 digits -= old_e - e;
450 (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
451 ps = mpf_get_str(0, &e, 10, static_cast<std::size_t>(digits), m_data);
452 --e; // To match with what our formatter expects.
453 }
454 }
455 else
456 {
457 ps = mpf_get_str(0, &e, 10, 1, m_data);
458 --e;
459 unsigned offset = *ps == '-' ? 1 : 0;
460 ps[offset] = '0';
461 ps[offset + 1] = 0;
462 }
463 }
464 result = ps;
465 (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
466 }
467 boost::multiprecision::detail::format_float_string(result, e, org_digits, f, mpf_sgn(m_data) == 0);
468 return result;
469 }
470 ~gmp_float_imp() noexcept
471 {
472 if (m_data[0]._mp_d)
473 {
474 mpf_clear(m_data);
475 }
476 }
477 void negate() noexcept
478 {
479 BOOST_MP_ASSERT(m_data[0]._mp_d);
480 mpf_neg(m_data, m_data);
481 }
482 int compare(const gmp_float<digits10>& o) const noexcept
483 {
484 BOOST_MP_ASSERT(m_data[0]._mp_d && o.m_data[0]._mp_d);
485 return mpf_cmp(m_data, o.m_data);
486 }
487 int compare(long i) const noexcept
488 {
489 BOOST_MP_ASSERT(m_data[0]._mp_d);
490 return mpf_cmp_si(m_data, i);
491 }
492 int compare(unsigned long i) const noexcept
493 {
494 BOOST_MP_ASSERT(m_data[0]._mp_d);
495 return mpf_cmp_ui(m_data, i);
496 }
497 template <class V>
498 typename std::enable_if<boost::multiprecision::detail::is_arithmetic<V>::value, int>::type compare(V v) const
499 {
500 gmp_float<digits10> d;
501 d = v;
502 return compare(d);
503 }
504 mpf_t& data() noexcept
505 {
506 BOOST_MP_ASSERT(m_data[0]._mp_d);
507 return m_data;
508 }
509 const mpf_t& data() const noexcept
510 {
511 BOOST_MP_ASSERT(m_data[0]._mp_d);
512 return m_data;
513 }
514
515 protected:
516 mpf_t m_data;
517 static unsigned& get_default_precision() noexcept
518 {
519 static BOOST_MP_THREAD_LOCAL unsigned val(get_global_default_precision());
520 return val;
521 }
522 static boost::multiprecision::detail::precision_type& get_global_default_precision() noexcept
523 {
524 static boost::multiprecision::detail::precision_type val(50);
525 return val;
526 }
527 #ifndef BOOST_MT_NO_ATOMIC_INT
528 static std::atomic<variable_precision_options>& get_global_default_options() noexcept
529 #else
530 static variable_precision_options& get_global_default_options() noexcept
531 #endif
532 {
533 #ifndef BOOST_MT_NO_ATOMIC_INT
534 static std::atomic<variable_precision_options> val{variable_precision_options::preserve_related_precision};
535 #else
536 static variable_precision_options val{variable_precision_options::preserve_related_precision};
537 #endif
538 return val;
539 }
540 static variable_precision_options& get_default_options()noexcept
541 {
542 static BOOST_MP_THREAD_LOCAL variable_precision_options val(get_global_default_options());
543 return val;
544 }
545 static bool preserve_source_precision() noexcept
546 {
547 return get_default_options() >= variable_precision_options::preserve_source_precision;
548 }
549 };
550
551 class gmp_char_ptr
552 {
553 private:
554 char* ptr_val;
555 void* (*alloc_func_ptr)(size_t);
556 void* (*realloc_func_ptr)(void*, size_t, size_t);
557 void (*free_func_ptr)(void*, size_t);
558
559 public:
560 gmp_char_ptr() = delete;
561 explicit gmp_char_ptr(char* val_) : ptr_val {val_}
562 {
563 mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
564 }
565 ~gmp_char_ptr() noexcept
566 {
567 (*free_func_ptr)((void*)ptr_val, sizeof(*ptr_val));
568 ptr_val = nullptr;
569 }
570 inline char* get() noexcept { return ptr_val; }
571 };
572
573 } // namespace detail
574
575 struct gmp_int;
576 struct gmp_rational;
577
578 template <unsigned digits10>
579 struct gmp_float : public detail::gmp_float_imp<digits10>
580 {
581 gmp_float()
582 {
583 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
584 }
585 gmp_float(const gmp_float& o) : detail::gmp_float_imp<digits10>(o) {}
586 template <unsigned D>
587 gmp_float(const gmp_float<D>& o, typename std::enable_if<D <= digits10>::type* = 0);
588 template <unsigned D>
589 explicit gmp_float(const gmp_float<D>& o, typename std::enable_if<!(D <= digits10)>::type* = 0);
590 gmp_float(const gmp_int& o);
591 gmp_float(const gmp_rational& o);
592 gmp_float(const mpf_t val)
593 {
594 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
595 mpf_set(this->m_data, val);
596 }
597 gmp_float(const mpz_t val)
598 {
599 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
600 mpf_set_z(this->m_data, val);
601 }
602 gmp_float(const mpq_t val)
603 {
604 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
605 mpf_set_q(this->m_data, val);
606 }
607 // rvalue copy
608 gmp_float(gmp_float&& o) noexcept : detail::gmp_float_imp<digits10>(static_cast<detail::gmp_float_imp<digits10>&&>(o))
609 {}
610 gmp_float& operator=(const gmp_float& o)
611 {
612 *static_cast<detail::gmp_float_imp<digits10>*>(this) = static_cast<detail::gmp_float_imp<digits10> const&>(o);
613 return *this;
614 }
615 gmp_float& operator=(gmp_float&& o) noexcept
616 {
617 *static_cast<detail::gmp_float_imp<digits10>*>(this) = static_cast<detail::gmp_float_imp<digits10>&&>(o);
618 return *this;
619 }
620 template <unsigned D>
621 gmp_float& operator=(const gmp_float<D>& o);
622 gmp_float& operator=(const gmp_int& o);
623 gmp_float& operator=(const gmp_rational& o);
624 gmp_float& operator=(const mpf_t val)
625 {
626 if (this->m_data[0]._mp_d == 0)
627 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
628 mpf_set(this->m_data, val);
629 return *this;
630 }
631 gmp_float& operator=(const mpz_t val)
632 {
633 if (this->m_data[0]._mp_d == 0)
634 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
635 mpf_set_z(this->m_data, val);
636 return *this;
637 }
638 gmp_float& operator=(const mpq_t val)
639 {
640 if (this->m_data[0]._mp_d == 0)
641 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
642 mpf_set_q(this->m_data, val);
643 return *this;
644 }
645 template <class V>
646 typename std::enable_if<std::is_assignable<detail::gmp_float_imp<digits10>, V>::value, gmp_float&>::type operator=(const V& v)
647 {
648 *static_cast<detail::gmp_float_imp<digits10>*>(this) = v;
649 return *this;
650 }
651 };
652
653 template <>
654 struct gmp_float<0> : public detail::gmp_float_imp<0>
655 {
656 //
657 // We have a problem with mpf_t in that the precision we request isn't what we get.
658 // As a result the front end can end up chasing it's tail trying to create a variable
659 // with the the correct precision to hold the result of an expression.
660 // See: https://github.com/boostorg/multiprecision/issues/164
661 // The problem is made worse by the fact that our conversions from base10 to 2 and
662 // vice-versa do not exactly round trip (and probably never will).
663 // The workaround is to keep track of the precision requested, and always return
664 // that as the current actual precision.
665 //
666 private:
667 unsigned requested_precision;
668
669 public:
670 gmp_float() : requested_precision(get_default_precision())
671 {
672 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
673 }
674 gmp_float(const mpf_t val) : requested_precision(get_default_precision())
675 {
676 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
677 mpf_set(this->m_data, val);
678 }
679 gmp_float(const mpz_t val) : requested_precision(get_default_precision())
680 {
681 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
682 mpf_set_z(this->m_data, val);
683 }
684 gmp_float(const mpq_t val) : requested_precision(get_default_precision())
685 {
686 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
687 mpf_set_q(this->m_data, val);
688 }
689 gmp_float(const gmp_float& o) : detail::gmp_float_imp<0>(o), requested_precision(preserve_source_precision() ? o.requested_precision : get_default_precision()) {}
690 template <unsigned D>
691 gmp_float(const gmp_float<D>& o)
692 {
693 mpf_init2(this->m_data, preserve_related_precision() ? mpf_get_prec(o.data()) : multiprecision::detail::digits10_2_2(get_default_precision()));
694 mpf_set(this->m_data, o.data());
695 requested_precision = preserve_related_precision() ? D : get_default_precision();
696 }
697 // rvalue copy
698 gmp_float(gmp_float&& o) noexcept : detail::gmp_float_imp<0>(static_cast<detail::gmp_float_imp<0>&&>(o)), requested_precision((this->get_default_options() != variable_precision_options::preserve_target_precision) ? o.requested_precision : get_default_precision())
699 {}
700 gmp_float(const gmp_int& o);
701 gmp_float(const gmp_rational& o);
702 gmp_float(const gmp_float& o, unsigned digits10) : requested_precision(digits10)
703 {
704 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
705 mpf_set(this->m_data, o.data());
706 }
707 template <class V>
708 gmp_float(const V& o, unsigned digits10) : requested_precision(digits10)
709 {
710 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
711 *this = o;
712 }
713
714 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
715 //
716 // Support for new types in C++17
717 //
718 template <class Traits>
719 gmp_float(const std::basic_string_view<char, Traits>& o, unsigned digits10) : requested_precision(digits10)
720 {
721 using default_ops::assign_from_string_view;
722 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
723 assign_from_string_view(*this, o);
724 }
725 #endif
726 gmp_float& operator=(const gmp_float& o)
727 {
728 *static_cast<detail::gmp_float_imp<0>*>(this) = static_cast<detail::gmp_float_imp<0> const&>(o);
729 if(preserve_source_precision())
730 requested_precision = o.requested_precision;
731 return *this;
732 }
733 // rvalue copy
734 gmp_float& operator=(gmp_float&& o) noexcept
735 {
736 *static_cast<detail::gmp_float_imp<0>*>(this) = static_cast<detail::gmp_float_imp<0>&&>(o);
737 if ((this->get_default_options() != variable_precision_options::preserve_target_precision))
738 requested_precision = o.requested_precision;
739 return *this;
740 }
741 template <unsigned D>
742 gmp_float& operator=(const gmp_float<D>& o)
743 {
744 if (this->m_data[0]._mp_d == 0)
745 {
746 mpf_init2(this->m_data, preserve_related_precision() ? mpf_get_prec(o.data()) : multiprecision::detail::digits10_2_2(get_default_precision()));
747 }
748 else if(preserve_related_precision())
749 {
750 mpf_set_prec(this->m_data, mpf_get_prec(o.data()));
751 }
752 mpf_set(this->m_data, o.data());
753 if (preserve_related_precision())
754 requested_precision = D;
755 return *this;
756 }
757 gmp_float& operator=(const gmp_int& o);
758 gmp_float& operator=(const gmp_rational& o);
759 gmp_float& operator=(const mpf_t val)
760 {
761 if (this->m_data[0]._mp_d == 0)
762 {
763 requested_precision = get_default_precision();
764 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
765 }
766 mpf_set(this->m_data, val);
767 return *this;
768 }
769 gmp_float& operator=(const mpz_t val)
770 {
771 if (this->m_data[0]._mp_d == 0)
772 {
773 requested_precision = get_default_precision();
774 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
775 }
776 mpf_set_z(this->m_data, val);
777 return *this;
778 }
779 gmp_float& operator=(const mpq_t val)
780 {
781 if (this->m_data[0]._mp_d == 0)
782 {
783 requested_precision = get_default_precision();
784 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
785 }
786 mpf_set_q(this->m_data, val);
787 return *this;
788 }
789 template <class V>
790 typename std::enable_if<std::is_assignable<detail::gmp_float_imp<0>, V>::value, gmp_float&>::type operator=(const V& v)
791 {
792 constexpr unsigned d10 = std::is_floating_point<V>::value ?
793 std::numeric_limits<V>::digits10 :
794 std::numeric_limits<V>::digits10 ? 1 + std::numeric_limits<V>::digits10 :
795 1 + boost::multiprecision::detail::digits2_2_10(std::numeric_limits<V>::digits);
796 if((thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision) && (precision() < d10))
797 this->precision(d10);
798 *static_cast<detail::gmp_float_imp<0>*>(this) = v;
799 return *this;
800 }
801 static unsigned default_precision() noexcept
802 {
803 return get_global_default_precision();
804 }
805 static void default_precision(unsigned v) noexcept
806 {
807 get_global_default_precision() = v;
808 }
809 static unsigned thread_default_precision() noexcept
810 {
811 return get_default_precision();
812 }
813 static void thread_default_precision(unsigned v) noexcept
814 {
815 get_default_precision() = v;
816 }
817 unsigned precision() const noexcept
818 {
819 return requested_precision;
820 }
821 void precision(unsigned digits10) noexcept
822 {
823 requested_precision = digits10;
824 mpf_set_prec(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
825 }
826 //
827 // Variable precision options:
828 //
829 static variable_precision_options default_variable_precision_options()noexcept
830 {
831 return get_global_default_options();
832 }
833 static variable_precision_options thread_default_variable_precision_options()noexcept
834 {
835 return get_default_options();
836 }
837 static void default_variable_precision_options(variable_precision_options opts)
838 {
839 get_global_default_options() = opts;
840 }
841 static void thread_default_variable_precision_options(variable_precision_options opts)
842 {
843 get_default_options() = opts;
844 }
845 static bool preserve_source_precision()
846 {
847 return get_default_options() >= variable_precision_options::preserve_source_precision;
848 }
849 static bool preserve_related_precision()
850 {
851 return get_default_options() >= variable_precision_options::preserve_related_precision;
852 }
853 static bool preserve_all_precision()
854 {
855 return get_default_options() >= variable_precision_options::preserve_all_precision;
856 }
857 //
858 // swap:
859 //
860 void swap(gmp_float& o)
861 {
862 std::swap(requested_precision, o.requested_precision);
863 gmp_float_imp<0>::swap(o);
864 }
865 };
866
867 template <unsigned digits10, class T>
868 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_eq(const gmp_float<digits10>& a, const T& b) noexcept
869 {
870 return a.compare(b) == 0;
871 }
872 template <unsigned digits10, class T>
873 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_lt(const gmp_float<digits10>& a, const T& b) noexcept
874 {
875 return a.compare(b) < 0;
876 }
877 template <unsigned digits10, class T>
878 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_gt(const gmp_float<digits10>& a, const T& b) noexcept
879 {
880 return a.compare(b) > 0;
881 }
882
883 template <unsigned D1, unsigned D2>
884 inline void eval_add(gmp_float<D1>& result, const gmp_float<D2>& o)
885 {
886 mpf_add(result.data(), result.data(), o.data());
887 }
888 template <unsigned D1, unsigned D2>
889 inline void eval_subtract(gmp_float<D1>& result, const gmp_float<D2>& o)
890 {
891 mpf_sub(result.data(), result.data(), o.data());
892 }
893 template <unsigned D1, unsigned D2>
894 inline void eval_multiply(gmp_float<D1>& result, const gmp_float<D2>& o)
895 {
896 mpf_mul(result.data(), result.data(), o.data());
897 }
898 template <unsigned digits10>
899 inline bool eval_is_zero(const gmp_float<digits10>& val) noexcept
900 {
901 return mpf_sgn(val.data()) == 0;
902 }
903 template <unsigned D1, unsigned D2>
904 inline void eval_divide(gmp_float<D1>& result, const gmp_float<D2>& o)
905 {
906 if (eval_is_zero(o))
907 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
908 mpf_div(result.data(), result.data(), o.data());
909 }
910 template <unsigned digits10>
911 inline void eval_add(gmp_float<digits10>& result, unsigned long i)
912 {
913 mpf_add_ui(result.data(), result.data(), i);
914 }
915 template <unsigned digits10>
916 inline void eval_subtract(gmp_float<digits10>& result, unsigned long i)
917 {
918 mpf_sub_ui(result.data(), result.data(), i);
919 }
920 template <unsigned digits10>
921 inline void eval_multiply(gmp_float<digits10>& result, unsigned long i)
922 {
923 mpf_mul_ui(result.data(), result.data(), i);
924 }
925 template <unsigned digits10>
926 inline void eval_divide(gmp_float<digits10>& result, unsigned long i)
927 {
928 if (i == 0)
929 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
930 mpf_div_ui(result.data(), result.data(), i);
931 }
932 template <unsigned digits10>
933 inline void eval_add(gmp_float<digits10>& result, long i)
934 {
935 if (i > 0)
936 mpf_add_ui(result.data(), result.data(), i);
937 else
938 mpf_sub_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
939 }
940 template <unsigned digits10>
941 inline void eval_subtract(gmp_float<digits10>& result, long i)
942 {
943 if (i > 0)
944 mpf_sub_ui(result.data(), result.data(), i);
945 else
946 mpf_add_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
947 }
948 template <unsigned digits10>
949 inline void eval_multiply(gmp_float<digits10>& result, long i)
950 {
951 mpf_mul_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
952 if (i < 0)
953 mpf_neg(result.data(), result.data());
954 }
955 template <unsigned digits10>
956 inline void eval_divide(gmp_float<digits10>& result, long i)
957 {
958 if (i == 0)
959 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
960 mpf_div_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
961 if (i < 0)
962 mpf_neg(result.data(), result.data());
963 }
964 //
965 // Specialised 3 arg versions of the basic operators:
966 //
967 template <unsigned D1, unsigned D2, unsigned D3>
968 inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
969 {
970 mpf_add(a.data(), x.data(), y.data());
971 }
972 template <unsigned D1, unsigned D2>
973 inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
974 {
975 mpf_add_ui(a.data(), x.data(), y);
976 }
977 template <unsigned D1, unsigned D2>
978 inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
979 {
980 if (y < 0)
981 mpf_sub_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
982 else
983 mpf_add_ui(a.data(), x.data(), y);
984 }
985 template <unsigned D1, unsigned D2>
986 inline void eval_add(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
987 {
988 mpf_add_ui(a.data(), y.data(), x);
989 }
990 template <unsigned D1, unsigned D2>
991 inline void eval_add(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
992 {
993 if (x < 0)
994 {
995 mpf_ui_sub(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data());
996 mpf_neg(a.data(), a.data());
997 }
998 else
999 mpf_add_ui(a.data(), y.data(), x);
1000 }
1001 template <unsigned D1, unsigned D2, unsigned D3>
1002 inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
1003 {
1004 mpf_sub(a.data(), x.data(), y.data());
1005 }
1006 template <unsigned D1, unsigned D2>
1007 inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
1008 {
1009 mpf_sub_ui(a.data(), x.data(), y);
1010 }
1011 template <unsigned D1, unsigned D2>
1012 inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
1013 {
1014 if (y < 0)
1015 mpf_add_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
1016 else
1017 mpf_sub_ui(a.data(), x.data(), y);
1018 }
1019 template <unsigned D1, unsigned D2>
1020 inline void eval_subtract(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
1021 {
1022 mpf_ui_sub(a.data(), x, y.data());
1023 }
1024 template <unsigned D1, unsigned D2>
1025 inline void eval_subtract(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
1026 {
1027 if (x < 0)
1028 {
1029 mpf_add_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x));
1030 mpf_neg(a.data(), a.data());
1031 }
1032 else
1033 mpf_ui_sub(a.data(), x, y.data());
1034 }
1035
1036 template <unsigned D1, unsigned D2, unsigned D3>
1037 inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
1038 {
1039 mpf_mul(a.data(), x.data(), y.data());
1040 }
1041 template <unsigned D1, unsigned D2>
1042 inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
1043 {
1044 mpf_mul_ui(a.data(), x.data(), y);
1045 }
1046 template <unsigned D1, unsigned D2>
1047 inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
1048 {
1049 if (y < 0)
1050 {
1051 mpf_mul_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
1052 a.negate();
1053 }
1054 else
1055 mpf_mul_ui(a.data(), x.data(), y);
1056 }
1057 template <unsigned D1, unsigned D2>
1058 inline void eval_multiply(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
1059 {
1060 mpf_mul_ui(a.data(), y.data(), x);
1061 }
1062 template <unsigned D1, unsigned D2>
1063 inline void eval_multiply(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
1064 {
1065 if (x < 0)
1066 {
1067 mpf_mul_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x));
1068 mpf_neg(a.data(), a.data());
1069 }
1070 else
1071 mpf_mul_ui(a.data(), y.data(), x);
1072 }
1073
1074 template <unsigned D1, unsigned D2, unsigned D3>
1075 inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
1076 {
1077 if (eval_is_zero(y))
1078 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1079 mpf_div(a.data(), x.data(), y.data());
1080 }
1081 template <unsigned D1, unsigned D2>
1082 inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
1083 {
1084 if (y == 0)
1085 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1086 mpf_div_ui(a.data(), x.data(), y);
1087 }
1088 template <unsigned D1, unsigned D2>
1089 inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
1090 {
1091 if (y == 0)
1092 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1093 if (y < 0)
1094 {
1095 mpf_div_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
1096 a.negate();
1097 }
1098 else
1099 mpf_div_ui(a.data(), x.data(), y);
1100 }
1101 template <unsigned D1, unsigned D2>
1102 inline void eval_divide(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
1103 {
1104 if (eval_is_zero(y))
1105 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1106 mpf_ui_div(a.data(), x, y.data());
1107 }
1108 template <unsigned D1, unsigned D2>
1109 inline void eval_divide(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
1110 {
1111 if (eval_is_zero(y))
1112 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1113 if (x < 0)
1114 {
1115 mpf_ui_div(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data());
1116 mpf_neg(a.data(), a.data());
1117 }
1118 else
1119 mpf_ui_div(a.data(), x, y.data());
1120 }
1121
1122 template <unsigned digits10>
1123 inline int eval_get_sign(const gmp_float<digits10>& val) noexcept
1124 {
1125 return mpf_sgn(val.data());
1126 }
1127
1128 template <unsigned digits10>
1129 inline void eval_convert_to(unsigned long* result, const gmp_float<digits10>& val) noexcept
1130 {
1131 if (0 == mpf_fits_ulong_p(val.data()))
1132 *result = (std::numeric_limits<unsigned long>::max)();
1133 else
1134 *result = static_cast<unsigned long>(mpf_get_ui(val.data()));
1135 }
1136 template <unsigned digits10>
1137 inline void eval_convert_to(long* result, const gmp_float<digits10>& val) noexcept
1138 {
1139 if (0 == mpf_fits_slong_p(val.data()))
1140 {
1141 *result = (std::numeric_limits<long>::max)();
1142 *result *= mpf_sgn(val.data());
1143 }
1144 else
1145 *result = static_cast<long>(mpf_get_si(val.data()));
1146 }
1147 #ifdef BOOST_MP_STANDALONE
1148 template <unsigned digits10>
1149 inline void eval_convert_to(long double* result, const gmp_float<digits10>& val) noexcept
1150 {
1151 mp_exp_t exp = 0;
1152
1153 detail::gmp_char_ptr val_char_ptr {mpf_get_str(nullptr, &exp, 10, LDBL_DIG, val.data())};
1154
1155 auto temp_string = std::string(val_char_ptr.get());
1156 if(exp > 0 && static_cast<std::size_t>(exp) < temp_string.size())
1157 {
1158 if(temp_string.front() == '-')
1159 {
1160 ++exp;
1161 }
1162
1163 temp_string.insert(exp, 1, '.');
1164 }
1165
1166 *result = std::strtold(temp_string.c_str(), nullptr);
1167
1168 if((temp_string.size() == 2ul && *result < 0.0l) ||
1169 (static_cast<std::size_t>(exp) > temp_string.size()))
1170 {
1171 *result *= std::pow(10l, exp-1);
1172 }
1173 }
1174 #endif // BOOST_MP_STANDALONE
1175 template <unsigned digits10>
1176 inline void eval_convert_to(double* result, const gmp_float<digits10>& val) noexcept
1177 {
1178 *result = mpf_get_d(val.data());
1179 }
1180 #ifdef BOOST_HAS_LONG_LONG
1181 template <unsigned digits10>
1182 inline void eval_convert_to(long long* result, const gmp_float<digits10>& val)
1183 {
1184 gmp_float<digits10> t(val);
1185 if (eval_get_sign(t) < 0)
1186 t.negate();
1187
1188 long digits = std::numeric_limits<long long>::digits - std::numeric_limits<long>::digits;
1189
1190 if (digits > 0)
1191 mpf_div_2exp(t.data(), t.data(), digits);
1192
1193 if (!mpf_fits_slong_p(t.data()))
1194 {
1195 if (eval_get_sign(val) < 0)
1196 *result = (std::numeric_limits<long long>::min)();
1197 else
1198 *result = (std::numeric_limits<long long>::max)();
1199 return;
1200 };
1201
1202 *result = mpf_get_si(t.data());
1203 while (digits > 0)
1204 {
1205 *result <<= digits;
1206 digits -= std::numeric_limits<unsigned long>::digits;
1207 mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits<unsigned long>::digits : std::numeric_limits<unsigned long>::digits + digits);
1208 unsigned long l = static_cast<unsigned long>(mpf_get_ui(t.data()));
1209 if (digits < 0)
1210 l >>= -digits;
1211 *result |= l;
1212 }
1213 if (eval_get_sign(val) < 0)
1214 *result = -*result;
1215 }
1216 template <unsigned digits10>
1217 inline void eval_convert_to(unsigned long long* result, const gmp_float<digits10>& val)
1218 {
1219 gmp_float<digits10> t(val);
1220
1221 long digits = std::numeric_limits<long long>::digits - std::numeric_limits<long>::digits;
1222
1223 if (digits > 0)
1224 mpf_div_2exp(t.data(), t.data(), digits);
1225
1226 if (!mpf_fits_ulong_p(t.data()))
1227 {
1228 *result = (std::numeric_limits<long long>::max)();
1229 return;
1230 }
1231
1232 *result = mpf_get_ui(t.data());
1233 while (digits > 0)
1234 {
1235 *result <<= digits;
1236 digits -= std::numeric_limits<unsigned long>::digits;
1237 mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits<unsigned long>::digits : std::numeric_limits<unsigned long>::digits + digits);
1238 unsigned long l = static_cast<unsigned long>(mpf_get_ui(t.data()));
1239 if (digits < 0)
1240 l >>= -digits;
1241 *result |= l;
1242 }
1243 }
1244 #endif
1245
1246
1247 #ifdef BOOST_HAS_FLOAT128
1248 template <unsigned digits10>
1249 inline void eval_convert_to(float128_type* result, const gmp_float<digits10>& val)
1250 {
1251 *result = float128_procs::strtoflt128(val.str(0, std::ios_base::scientific).c_str(), nullptr);
1252 }
1253 #endif
1254
1255
1256 //
1257 // Native non-member operations:
1258 //
1259 template <unsigned Digits10>
1260 inline void eval_sqrt(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1261 {
1262 mpf_sqrt(result.data(), val.data());
1263 }
1264
1265 template <unsigned Digits10>
1266 inline void eval_abs(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1267 {
1268 mpf_abs(result.data(), val.data());
1269 }
1270
1271 template <unsigned Digits10>
1272 inline void eval_fabs(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1273 {
1274 mpf_abs(result.data(), val.data());
1275 }
1276 template <unsigned Digits10>
1277 inline void eval_ceil(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1278 {
1279 mpf_ceil(result.data(), val.data());
1280 }
1281 template <unsigned Digits10>
1282 inline void eval_floor(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1283 {
1284 mpf_floor(result.data(), val.data());
1285 }
1286 template <unsigned Digits10>
1287 inline void eval_trunc(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1288 {
1289 mpf_trunc(result.data(), val.data());
1290 }
1291 template <unsigned Digits10>
1292 inline void eval_ldexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, long e)
1293 {
1294 if (e > 0)
1295 mpf_mul_2exp(result.data(), val.data(), e);
1296 else if (e < 0)
1297 mpf_div_2exp(result.data(), val.data(), -e);
1298 else
1299 result = val;
1300 }
1301 template <unsigned Digits10>
1302 inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, int* e)
1303 {
1304 #if (BOOST_MP_MPIR_VERSION >= 20600) && (BOOST_MP_MPIR_VERSION < 30000)
1305 mpir_si v;
1306 mpf_get_d_2exp(&v, val.data());
1307 #else
1308 long v;
1309 mpf_get_d_2exp(&v, val.data());
1310 #endif
1311 *e = v;
1312 eval_ldexp(result, val, -v);
1313 }
1314 template <unsigned Digits10>
1315 inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, long* e)
1316 {
1317 #if (BOOST_MP_MPIR_VERSION >= 20600) && (BOOST_MP_MPIR_VERSION < 30000)
1318 mpir_si v;
1319 mpf_get_d_2exp(&v, val.data());
1320 *e = v;
1321 eval_ldexp(result, val, -v);
1322 #else
1323 mpf_get_d_2exp(e, val.data());
1324 eval_ldexp(result, val, -*e);
1325 #endif
1326 }
1327
1328 template <unsigned Digits10>
1329 inline std::size_t hash_value(const gmp_float<Digits10>& val)
1330 {
1331 std::size_t result = 0;
1332 for (int i = 0; i < std::abs(val.data()[0]._mp_size); ++i)
1333 boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_d[i]);
1334 boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_exp, val.data()[0]._mp_size);
1335 return result;
1336 }
1337
1338 struct gmp_int
1339 {
1340 #ifdef BOOST_HAS_LONG_LONG
1341 using signed_types = std::tuple<long, long long> ;
1342 using unsigned_types = std::tuple<unsigned long, unsigned long long>;
1343 #else
1344 using signed_types = std::tuple<long> ;
1345 using unsigned_types = std::tuple<unsigned long>;
1346 #endif
1347 using float_types = std::tuple<double, long double>;
1348
1349 gmp_int()
1350 {
1351 mpz_init(this->m_data);
1352 }
1353 gmp_int(const gmp_int& o)
1354 {
1355 if (o.m_data[0]._mp_d)
1356 mpz_init_set(m_data, o.m_data);
1357 else
1358 mpz_init(this->m_data);
1359 }
1360 // rvalue
1361 gmp_int(gmp_int&& o) noexcept
1362 {
1363 m_data[0] = o.m_data[0];
1364 o.m_data[0]._mp_d = 0;
1365 }
1366 explicit gmp_int(const mpf_t val)
1367 {
1368 mpz_init(this->m_data);
1369 mpz_set_f(this->m_data, val);
1370 }
1371 gmp_int(const mpz_t val)
1372 {
1373 mpz_init_set(this->m_data, val);
1374 }
1375 gmp_int(long i)
1376 {
1377 mpz_init_set_si(this->m_data, i);
1378 }
1379 gmp_int(unsigned long i)
1380 {
1381 mpz_init_set_ui(this->m_data, i);
1382 }
1383 explicit gmp_int(const mpq_t val)
1384 {
1385 mpz_init(this->m_data);
1386 mpz_set_q(this->m_data, val);
1387 }
1388 template <unsigned Digits10>
1389 explicit gmp_int(const gmp_float<Digits10>& o)
1390 {
1391 mpz_init(this->m_data);
1392 mpz_set_f(this->m_data, o.data());
1393 }
1394 explicit gmp_int(const gmp_rational& o);
1395 gmp_int& operator=(const gmp_int& o)
1396 {
1397 if (m_data[0]._mp_d == 0)
1398 mpz_init(this->m_data);
1399 mpz_set(m_data, o.m_data);
1400 return *this;
1401 }
1402 // rvalue copy
1403 gmp_int& operator=(gmp_int&& o) noexcept
1404 {
1405 mpz_swap(m_data, o.m_data);
1406 return *this;
1407 }
1408 #ifdef BOOST_HAS_LONG_LONG
1409 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
1410 gmp_int& operator=(unsigned long long i)
1411 {
1412 *this = static_cast<unsigned long>(i);
1413 return *this;
1414 }
1415 #else
1416 gmp_int& operator=(unsigned long long i)
1417 {
1418 if (m_data[0]._mp_d == 0)
1419 mpz_init(this->m_data);
1420 unsigned long long mask = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
1421 unsigned shift = 0;
1422 mpz_t t;
1423 mpz_set_ui(m_data, 0);
1424 mpz_init_set_ui(t, 0);
1425 while (i)
1426 {
1427 mpz_set_ui(t, static_cast<unsigned long>(i & mask));
1428 if (shift)
1429 mpz_mul_2exp(t, t, shift);
1430 mpz_add(m_data, m_data, t);
1431 shift += std::numeric_limits<unsigned long>::digits;
1432 i >>= std::numeric_limits<unsigned long>::digits;
1433 }
1434 mpz_clear(t);
1435 return *this;
1436 }
1437 #endif
1438 gmp_int& operator=(long long i)
1439 {
1440 if (m_data[0]._mp_d == 0)
1441 mpz_init(this->m_data);
1442 bool neg = i < 0;
1443 *this = boost::multiprecision::detail::unsigned_abs(i);
1444 if (neg)
1445 mpz_neg(m_data, m_data);
1446 return *this;
1447 }
1448 #endif
1449 #ifdef BOOST_HAS_INT128
1450 gmp_int& operator=(uint128_type i)
1451 {
1452 if (m_data[0]._mp_d == 0)
1453 mpz_init(this->m_data);
1454 uint128_type mask = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
1455 unsigned shift = 0;
1456 mpz_t t;
1457 mpz_set_ui(m_data, 0);
1458 mpz_init_set_ui(t, 0);
1459 while (i)
1460 {
1461 mpz_set_ui(t, static_cast<unsigned long>(i & mask));
1462 if (shift)
1463 mpz_mul_2exp(t, t, shift);
1464 mpz_add(m_data, m_data, t);
1465 shift += std::numeric_limits<unsigned long>::digits;
1466 i >>= std::numeric_limits<unsigned long>::digits;
1467 }
1468 mpz_clear(t);
1469 return *this;
1470 }
1471 gmp_int& operator=(int128_type i)
1472 {
1473 if (m_data[0]._mp_d == 0)
1474 mpz_init(this->m_data);
1475 bool neg = i < 0;
1476 *this = boost::multiprecision::detail::unsigned_abs(i);
1477 if (neg)
1478 mpz_neg(m_data, m_data);
1479 return *this;
1480 }
1481 #endif
1482 gmp_int& operator=(unsigned long i)
1483 {
1484 if (m_data[0]._mp_d == 0)
1485 mpz_init(this->m_data);
1486 mpz_set_ui(m_data, i);
1487 return *this;
1488 }
1489 gmp_int& operator=(long i)
1490 {
1491 if (m_data[0]._mp_d == 0)
1492 mpz_init(this->m_data);
1493 mpz_set_si(m_data, i);
1494 return *this;
1495 }
1496 gmp_int& operator=(double d)
1497 {
1498 if (m_data[0]._mp_d == 0)
1499 mpz_init(this->m_data);
1500 mpz_set_d(m_data, d);
1501 return *this;
1502 }
1503 template <class F>
1504 gmp_int& assign_float(F a)
1505 {
1506 BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp;
1507
1508 if (m_data[0]._mp_d == 0)
1509 mpz_init(this->m_data);
1510
1511 if (a == 0)
1512 {
1513 mpz_set_si(m_data, 0);
1514 return *this;
1515 }
1516
1517 if (a == 1)
1518 {
1519 mpz_set_si(m_data, 1);
1520 return *this;
1521 }
1522
1523 BOOST_MP_ASSERT(!BOOST_MP_ISINF(a));
1524 BOOST_MP_ASSERT(!BOOST_MP_ISNAN(a));
1525
1526 int e;
1527 F f, term;
1528 mpz_set_ui(m_data, 0u);
1529
1530 f = frexp(a, &e);
1531
1532 constexpr const int shift = std::numeric_limits<int>::digits - 1;
1533
1534 while (f)
1535 {
1536 // extract int sized bits from f:
1537 f = ldexp(f, shift);
1538 term = floor(f);
1539 e -= shift;
1540 mpz_mul_2exp(m_data, m_data, shift);
1541 if (term > 0)
1542 mpz_add_ui(m_data, m_data, static_cast<unsigned>(term));
1543 else
1544 mpz_sub_ui(m_data, m_data, static_cast<unsigned>(-term));
1545 f -= term;
1546 }
1547 if (e > 0)
1548 mpz_mul_2exp(m_data, m_data, e);
1549 else if (e < 0)
1550 mpz_div_2exp(m_data, m_data, -e);
1551 return *this;
1552 }
1553 gmp_int& operator=(long double a)
1554 {
1555 return assign_float(a);
1556 }
1557 gmp_int& operator=(const char* s)
1558 {
1559 if (m_data[0]._mp_d == 0)
1560 mpz_init(this->m_data);
1561 std::size_t n = s ? std::strlen(s) : 0;
1562 int radix = 10;
1563 if (n && (*s == '0'))
1564 {
1565 if ((n > 1) && ((s[1] == 'x') || (s[1] == 'X')))
1566 {
1567 radix = 16;
1568 s += 2;
1569 n -= 2;
1570 }
1571 else
1572 {
1573 radix = 8;
1574 n -= 1;
1575 }
1576 }
1577 if (n)
1578 {
1579 if (0 != mpz_set_str(m_data, s, radix))
1580 BOOST_MP_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid integer.")));
1581 }
1582 else
1583 mpz_set_ui(m_data, 0);
1584 return *this;
1585 }
1586 #ifdef BOOST_HAS_FLOAT128
1587 gmp_int& operator=(float128_type a)
1588 {
1589 return assign_float(a);
1590 }
1591 #endif
1592 gmp_int& operator=(const mpf_t val)
1593 {
1594 if (m_data[0]._mp_d == 0)
1595 mpz_init(this->m_data);
1596 mpz_set_f(this->m_data, val);
1597 return *this;
1598 }
1599 gmp_int& operator=(const mpz_t val)
1600 {
1601 if (m_data[0]._mp_d == 0)
1602 mpz_init(this->m_data);
1603 mpz_set(this->m_data, val);
1604 return *this;
1605 }
1606 gmp_int& operator=(const mpq_t val)
1607 {
1608 if (m_data[0]._mp_d == 0)
1609 mpz_init(this->m_data);
1610 mpz_set_q(this->m_data, val);
1611 return *this;
1612 }
1613 template <unsigned Digits10>
1614 gmp_int& operator=(const gmp_float<Digits10>& o)
1615 {
1616 if (m_data[0]._mp_d == 0)
1617 mpz_init(this->m_data);
1618 mpz_set_f(this->m_data, o.data());
1619 return *this;
1620 }
1621 gmp_int& operator=(const gmp_rational& o);
1622 void swap(gmp_int& o)
1623 {
1624 mpz_swap(m_data, o.m_data);
1625 }
1626 std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags f) const
1627 {
1628 BOOST_MP_ASSERT(m_data[0]._mp_d);
1629
1630 int base = 10;
1631 if ((f & std::ios_base::oct) == std::ios_base::oct)
1632 base = 8;
1633 else if ((f & std::ios_base::hex) == std::ios_base::hex)
1634 base = 16;
1635 //
1636 // sanity check, bases 8 and 16 are only available for positive numbers:
1637 //
1638 if ((base != 10) && (mpz_sgn(m_data) < 0))
1639 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Formatted output in bases 8 or 16 is only available for positive numbers"));
1640 void* (*alloc_func_ptr)(size_t);
1641 void* (*realloc_func_ptr)(void*, size_t, size_t);
1642 void (*free_func_ptr)(void*, size_t);
1643 const char* ps = mpz_get_str(0, base, m_data);
1644 std::string s = ps;
1645 mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
1646 (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
1647 if (f & std::ios_base::uppercase)
1648 for (size_t i = 0; i < s.length(); ++i)
1649 s[i] = static_cast<char>(std::toupper(s[i]));
1650 if ((base != 10) && (f & std::ios_base::showbase))
1651 {
1652 int pos = s[0] == '-' ? 1 : 0;
1653 const char* pp = base == 8 ? "0" : (f & std::ios_base::uppercase) ? "0X" : "0x";
1654 s.insert(static_cast<std::string::size_type>(pos), pp);
1655 }
1656 if ((f & std::ios_base::showpos) && (s[0] != '-'))
1657 s.insert(static_cast<std::string::size_type>(0), 1, '+');
1658
1659 return s;
1660 }
1661 ~gmp_int() noexcept
1662 {
1663 if (m_data[0]._mp_d)
1664 mpz_clear(m_data);
1665 }
1666 void negate() noexcept
1667 {
1668 BOOST_MP_ASSERT(m_data[0]._mp_d);
1669 mpz_neg(m_data, m_data);
1670 }
1671 int compare(const gmp_int& o) const noexcept
1672 {
1673 BOOST_MP_ASSERT(m_data[0]._mp_d && o.m_data[0]._mp_d);
1674 return mpz_cmp(m_data, o.m_data);
1675 }
1676 int compare(long i) const noexcept
1677 {
1678 BOOST_MP_ASSERT(m_data[0]._mp_d);
1679 return mpz_cmp_si(m_data, i);
1680 }
1681 int compare(unsigned long i) const noexcept
1682 {
1683 BOOST_MP_ASSERT(m_data[0]._mp_d);
1684 return mpz_cmp_ui(m_data, i);
1685 }
1686 template <class V>
1687 int compare(V v) const
1688 {
1689 gmp_int d;
1690 d = v;
1691 return compare(d);
1692 }
1693 mpz_t& data() noexcept
1694 {
1695 BOOST_MP_ASSERT(m_data[0]._mp_d);
1696 return m_data;
1697 }
1698 const mpz_t& data() const noexcept
1699 {
1700 BOOST_MP_ASSERT(m_data[0]._mp_d);
1701 return m_data;
1702 }
1703
1704 protected:
1705 mpz_t m_data;
1706 };
1707
1708 template <class T>
1709 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_eq(const gmp_int& a, const T& b)
1710 {
1711 return a.compare(b) == 0;
1712 }
1713 template <class T>
1714 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_lt(const gmp_int& a, const T& b)
1715 {
1716 return a.compare(b) < 0;
1717 }
1718 template <class T>
1719 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_gt(const gmp_int& a, const T& b)
1720 {
1721 return a.compare(b) > 0;
1722 }
1723
1724 inline bool eval_is_zero(const gmp_int& val)
1725 {
1726 return mpz_sgn(val.data()) == 0;
1727 }
1728 inline void eval_add(gmp_int& t, const gmp_int& o)
1729 {
1730 mpz_add(t.data(), t.data(), o.data());
1731 }
1732 inline void eval_multiply_add(gmp_int& t, const gmp_int& a, const gmp_int& b)
1733 {
1734 mpz_addmul(t.data(), a.data(), b.data());
1735 }
1736 inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, const gmp_int& b)
1737 {
1738 mpz_submul(t.data(), a.data(), b.data());
1739 }
1740 inline void eval_subtract(gmp_int& t, const gmp_int& o)
1741 {
1742 mpz_sub(t.data(), t.data(), o.data());
1743 }
1744 inline void eval_multiply(gmp_int& t, const gmp_int& o)
1745 {
1746 mpz_mul(t.data(), t.data(), o.data());
1747 }
1748 inline void eval_divide(gmp_int& t, const gmp_int& o)
1749 {
1750 if (eval_is_zero(o))
1751 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1752 mpz_tdiv_q(t.data(), t.data(), o.data());
1753 }
1754 inline void eval_modulus(gmp_int& t, const gmp_int& o)
1755 {
1756 mpz_tdiv_r(t.data(), t.data(), o.data());
1757 }
1758 inline void eval_add(gmp_int& t, unsigned long i)
1759 {
1760 mpz_add_ui(t.data(), t.data(), i);
1761 }
1762 inline void eval_multiply_add(gmp_int& t, const gmp_int& a, unsigned long i)
1763 {
1764 mpz_addmul_ui(t.data(), a.data(), i);
1765 }
1766 inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, unsigned long i)
1767 {
1768 mpz_submul_ui(t.data(), a.data(), i);
1769 }
1770 inline void eval_subtract(gmp_int& t, unsigned long i)
1771 {
1772 mpz_sub_ui(t.data(), t.data(), i);
1773 }
1774 inline void eval_multiply(gmp_int& t, unsigned long i)
1775 {
1776 mpz_mul_ui(t.data(), t.data(), i);
1777 }
1778 inline void eval_modulus(gmp_int& t, unsigned long i)
1779 {
1780 mpz_tdiv_r_ui(t.data(), t.data(), i);
1781 }
1782 inline void eval_divide(gmp_int& t, unsigned long i)
1783 {
1784 if (i == 0)
1785 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1786 mpz_tdiv_q_ui(t.data(), t.data(), i);
1787 }
1788 inline void eval_add(gmp_int& t, long i)
1789 {
1790 if (i > 0)
1791 mpz_add_ui(t.data(), t.data(), i);
1792 else
1793 mpz_sub_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1794 }
1795 inline void eval_multiply_add(gmp_int& t, const gmp_int& a, long i)
1796 {
1797 if (i > 0)
1798 mpz_addmul_ui(t.data(), a.data(), i);
1799 else
1800 mpz_submul_ui(t.data(), a.data(), boost::multiprecision::detail::unsigned_abs(i));
1801 }
1802 inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, long i)
1803 {
1804 if (i > 0)
1805 mpz_submul_ui(t.data(), a.data(), i);
1806 else
1807 mpz_addmul_ui(t.data(), a.data(), boost::multiprecision::detail::unsigned_abs(i));
1808 }
1809 inline void eval_subtract(gmp_int& t, long i)
1810 {
1811 if (i > 0)
1812 mpz_sub_ui(t.data(), t.data(), i);
1813 else
1814 mpz_add_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1815 }
1816 inline void eval_multiply(gmp_int& t, long i)
1817 {
1818 mpz_mul_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1819 if (i < 0)
1820 mpz_neg(t.data(), t.data());
1821 }
1822 inline void eval_modulus(gmp_int& t, long i)
1823 {
1824 mpz_tdiv_r_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1825 }
1826 inline void eval_divide(gmp_int& t, long i)
1827 {
1828 if (i == 0)
1829 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1830 mpz_tdiv_q_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1831 if (i < 0)
1832 mpz_neg(t.data(), t.data());
1833 }
1834 template <class UI>
1835 inline void eval_left_shift(gmp_int& t, UI i)
1836 {
1837 mpz_mul_2exp(t.data(), t.data(), static_cast<unsigned long>(i));
1838 }
1839 template <class UI>
1840 inline void eval_right_shift(gmp_int& t, UI i)
1841 {
1842 mpz_fdiv_q_2exp(t.data(), t.data(), static_cast<unsigned long>(i));
1843 }
1844 template <class UI>
1845 inline void eval_left_shift(gmp_int& t, const gmp_int& v, UI i)
1846 {
1847 mpz_mul_2exp(t.data(), v.data(), static_cast<unsigned long>(i));
1848 }
1849 template <class UI>
1850 inline void eval_right_shift(gmp_int& t, const gmp_int& v, UI i)
1851 {
1852 mpz_fdiv_q_2exp(t.data(), v.data(), static_cast<unsigned long>(i));
1853 }
1854
1855 inline void eval_bitwise_and(gmp_int& result, const gmp_int& v)
1856 {
1857 mpz_and(result.data(), result.data(), v.data());
1858 }
1859
1860 inline void eval_bitwise_or(gmp_int& result, const gmp_int& v)
1861 {
1862 mpz_ior(result.data(), result.data(), v.data());
1863 }
1864
1865 inline void eval_bitwise_xor(gmp_int& result, const gmp_int& v)
1866 {
1867 mpz_xor(result.data(), result.data(), v.data());
1868 }
1869
1870 inline void eval_add(gmp_int& t, const gmp_int& p, const gmp_int& o)
1871 {
1872 mpz_add(t.data(), p.data(), o.data());
1873 }
1874 inline void eval_subtract(gmp_int& t, const gmp_int& p, const gmp_int& o)
1875 {
1876 mpz_sub(t.data(), p.data(), o.data());
1877 }
1878 inline void eval_multiply(gmp_int& t, const gmp_int& p, const gmp_int& o)
1879 {
1880 mpz_mul(t.data(), p.data(), o.data());
1881 }
1882 inline void eval_divide(gmp_int& t, const gmp_int& p, const gmp_int& o)
1883 {
1884 if (eval_is_zero(o))
1885 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1886 mpz_tdiv_q(t.data(), p.data(), o.data());
1887 }
1888 inline void eval_modulus(gmp_int& t, const gmp_int& p, const gmp_int& o)
1889 {
1890 mpz_tdiv_r(t.data(), p.data(), o.data());
1891 }
1892 inline void eval_add(gmp_int& t, const gmp_int& p, unsigned long i)
1893 {
1894 mpz_add_ui(t.data(), p.data(), i);
1895 }
1896 inline void eval_subtract(gmp_int& t, const gmp_int& p, unsigned long i)
1897 {
1898 mpz_sub_ui(t.data(), p.data(), i);
1899 }
1900 inline void eval_multiply(gmp_int& t, const gmp_int& p, unsigned long i)
1901 {
1902 mpz_mul_ui(t.data(), p.data(), i);
1903 }
1904 inline void eval_modulus(gmp_int& t, const gmp_int& p, unsigned long i)
1905 {
1906 mpz_tdiv_r_ui(t.data(), p.data(), i);
1907 }
1908 inline void eval_divide(gmp_int& t, const gmp_int& p, unsigned long i)
1909 {
1910 if (i == 0)
1911 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1912 mpz_tdiv_q_ui(t.data(), p.data(), i);
1913 }
1914 inline void eval_add(gmp_int& t, const gmp_int& p, long i)
1915 {
1916 if (i > 0)
1917 mpz_add_ui(t.data(), p.data(), i);
1918 else
1919 mpz_sub_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1920 }
1921 inline void eval_subtract(gmp_int& t, const gmp_int& p, long i)
1922 {
1923 if (i > 0)
1924 mpz_sub_ui(t.data(), p.data(), i);
1925 else
1926 mpz_add_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1927 }
1928 inline void eval_multiply(gmp_int& t, const gmp_int& p, long i)
1929 {
1930 mpz_mul_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1931 if (i < 0)
1932 mpz_neg(t.data(), t.data());
1933 }
1934 inline void eval_modulus(gmp_int& t, const gmp_int& p, long i)
1935 {
1936 mpz_tdiv_r_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1937 }
1938 inline void eval_divide(gmp_int& t, const gmp_int& p, long i)
1939 {
1940 if (i == 0)
1941 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1942 mpz_tdiv_q_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1943 if (i < 0)
1944 mpz_neg(t.data(), t.data());
1945 }
1946
1947 inline void eval_bitwise_and(gmp_int& result, const gmp_int& u, const gmp_int& v)
1948 {
1949 mpz_and(result.data(), u.data(), v.data());
1950 }
1951
1952 inline void eval_bitwise_or(gmp_int& result, const gmp_int& u, const gmp_int& v)
1953 {
1954 mpz_ior(result.data(), u.data(), v.data());
1955 }
1956
1957 inline void eval_bitwise_xor(gmp_int& result, const gmp_int& u, const gmp_int& v)
1958 {
1959 mpz_xor(result.data(), u.data(), v.data());
1960 }
1961
1962 inline void eval_complement(gmp_int& result, const gmp_int& u)
1963 {
1964 mpz_com(result.data(), u.data());
1965 }
1966
1967 inline int eval_get_sign(const gmp_int& val)
1968 {
1969 return mpz_sgn(val.data());
1970 }
1971 inline void eval_convert_to(unsigned long* result, const gmp_int& val)
1972 {
1973 if (mpz_sgn(val.data()) < 0)
1974 {
1975 BOOST_MP_THROW_EXCEPTION(std::range_error("Conversion from negative integer to an unsigned type results in undefined behaviour"));
1976 }
1977 else
1978 *result = static_cast<unsigned long>(mpz_get_ui(val.data()));
1979 }
1980 inline void eval_convert_to(long* result, const gmp_int& val)
1981 {
1982 if (0 == mpz_fits_slong_p(val.data()))
1983 {
1984 *result = mpz_sgn(val.data()) < 0 ? (std::numeric_limits<long>::min)() : (std::numeric_limits<long>::max)();
1985 }
1986 else
1987 *result = static_cast<long>(mpz_get_si(val.data()));
1988 }
1989 inline void eval_convert_to(long double* result, const gmp_int& val)
1990 {
1991 detail::gmp_char_ptr val_char_ptr {mpz_get_str(nullptr, 10, val.data())};
1992 *result = std::strtold(val_char_ptr.get(), nullptr);
1993 }
1994 inline void eval_convert_to(double* result, const gmp_int& val)
1995 {
1996 *result = mpz_get_d(val.data());
1997 }
1998 #ifdef BOOST_HAS_LONG_LONG
1999 inline void eval_convert_to(unsigned long long* result, const gmp_int& val)
2000 {
2001 if (mpz_sgn(val.data()) < 0)
2002 {
2003 BOOST_MP_THROW_EXCEPTION(std::range_error("Conversion from negative integer to an unsigned type results in undefined behaviour"));
2004 }
2005 *result = 0;
2006 gmp_int t(val);
2007 unsigned parts = sizeof(unsigned long long) / sizeof(unsigned long);
2008
2009 for (unsigned i = 0; i < parts; ++i)
2010 {
2011 unsigned long long part = mpz_get_ui(t.data());
2012 if (i)
2013 *result |= part << (i * sizeof(unsigned long) * CHAR_BIT);
2014 else
2015 *result = part;
2016 mpz_tdiv_q_2exp(t.data(), t.data(), sizeof(unsigned long) * CHAR_BIT);
2017 }
2018 }
2019 inline void eval_convert_to(long long* result, const gmp_int& val)
2020 {
2021 int s = mpz_sgn(val.data());
2022 *result = 0;
2023 gmp_int t(val);
2024 unsigned parts = sizeof(unsigned long long) / sizeof(unsigned long);
2025 unsigned long long unsigned_result = 0;
2026
2027 for (unsigned i = 0; i < parts; ++i)
2028 {
2029 unsigned long long part = mpz_get_ui(t.data());
2030 if (i)
2031 unsigned_result |= part << (i * sizeof(unsigned long) * CHAR_BIT);
2032 else
2033 unsigned_result = part;
2034 mpz_tdiv_q_2exp(t.data(), t.data(), sizeof(unsigned long) * CHAR_BIT);
2035 }
2036 //
2037 // Overflow check:
2038 //
2039 bool overflow = false;
2040 if (mpz_sgn(t.data()))
2041 {
2042 overflow = true;
2043 }
2044 if ((s > 0) && (unsigned_result > static_cast<unsigned long long>((std::numeric_limits<long long>::max)())))
2045 overflow = true;
2046 if((s < 0) && (unsigned_result > 1u - static_cast<unsigned long long>((std::numeric_limits<long long>::min)() + 1)))
2047 overflow = true;
2048 if(overflow)
2049 *result = s < 0 ? (std::numeric_limits<long long>::min)() : (std::numeric_limits<long long>::max)();
2050 else
2051 *result = s < 0 ? -static_cast<long long>(unsigned_result - 1) - 1 : unsigned_result;
2052 }
2053 #endif
2054 #ifdef BOOST_HAS_INT128
2055 inline void eval_convert_to(uint128_type* result, const gmp_int& val)
2056 {
2057 if (mpz_sgn(val.data()) < 0)
2058 {
2059 BOOST_MP_THROW_EXCEPTION(std::range_error("Conversion from negative integer to an unsigned type results in undefined behaviour"));
2060 }
2061 *result = 0;
2062 gmp_int t(val);
2063 unsigned parts = sizeof(uint128_type) / sizeof(unsigned long);
2064
2065 for (unsigned i = 0; i < parts; ++i)
2066 {
2067 uint128_type part = mpz_get_ui(t.data());
2068 if (i)
2069 *result |= part << (i * sizeof(unsigned long) * CHAR_BIT);
2070 else
2071 *result = part;
2072 mpz_tdiv_q_2exp(t.data(), t.data(), sizeof(unsigned long) * CHAR_BIT);
2073 }
2074 }
2075 inline void eval_convert_to(int128_type* result, const gmp_int& val)
2076 {
2077 int s = mpz_sgn(val.data());
2078 *result = 0;
2079 gmp_int t(val);
2080 unsigned parts = sizeof(uint128_type) / sizeof(unsigned long);
2081 uint128_type unsigned_result = 0;
2082
2083 for (unsigned i = 0; i < parts; ++i)
2084 {
2085 uint128_type part = mpz_get_ui(t.data());
2086 if (i)
2087 unsigned_result |= part << (i * sizeof(unsigned long) * CHAR_BIT);
2088 else
2089 unsigned_result = part;
2090 mpz_tdiv_q_2exp(t.data(), t.data(), sizeof(unsigned long) * CHAR_BIT);
2091 }
2092 //
2093 // Overflow check:
2094 //
2095 constexpr const int128_type int128_max = static_cast<int128_type>((static_cast<uint128_type>(1u) << 127) - 1);
2096 constexpr const int128_type int128_min = (static_cast<uint128_type>(1u) << 127);
2097 bool overflow = false;
2098 if (mpz_sgn(t.data()))
2099 {
2100 overflow = true;
2101 }
2102 if ((s > 0) && (unsigned_result > static_cast<uint128_type>(int128_max)))
2103 overflow = true;
2104 if ((s < 0) && (unsigned_result > 1u - static_cast<uint128_type>(int128_min + 1)))
2105 overflow = true;
2106 if (overflow)
2107 *result = s < 0 ? int128_min : int128_max;
2108 else
2109 *result = s < 0 ? -int128_type(unsigned_result - 1) - 1 : unsigned_result;
2110 }
2111
2112 template <unsigned digits10>
2113 inline void eval_convert_to(int128_type* result, const gmp_float<digits10>& val)
2114 {
2115 gmp_int i;
2116 mpz_set_f(i.data(), val.data());
2117 eval_convert_to(result, i);
2118 }
2119 template <unsigned digits10>
2120 inline void eval_convert_to(uint128_type* result, const gmp_float<digits10>& val)
2121 {
2122 gmp_int i;
2123 mpz_set_f(i.data(), val.data());
2124 eval_convert_to(result, i);
2125 }
2126
2127 #endif
2128
2129 #ifdef BOOST_HAS_FLOAT128
2130 inline void eval_convert_to(float128_type* result, const gmp_int& val)
2131 {
2132 *result = float128_procs::strtoflt128(val.str(0, std::ios_base::fixed).c_str(), nullptr);
2133 }
2134 #endif
2135
2136 inline void eval_abs(gmp_int& result, const gmp_int& val)
2137 {
2138 mpz_abs(result.data(), val.data());
2139 }
2140
2141 inline void eval_gcd(gmp_int& result, const gmp_int& a, const gmp_int& b)
2142 {
2143 mpz_gcd(result.data(), a.data(), b.data());
2144 }
2145 inline void eval_lcm(gmp_int& result, const gmp_int& a, const gmp_int& b)
2146 {
2147 mpz_lcm(result.data(), a.data(), b.data());
2148 }
2149 template <class I>
2150 inline typename std::enable_if<(boost::multiprecision::detail::is_unsigned<I>::value && (sizeof(I) <= sizeof(unsigned long)))>::type eval_gcd(gmp_int& result, const gmp_int& a, const I b)
2151 {
2152 mpz_gcd_ui(result.data(), a.data(), b);
2153 }
2154 template <class I>
2155 inline typename std::enable_if<(boost::multiprecision::detail::is_unsigned<I>::value && (sizeof(I) <= sizeof(unsigned long)))>::type eval_lcm(gmp_int& result, const gmp_int& a, const I b)
2156 {
2157 mpz_lcm_ui(result.data(), a.data(), b);
2158 }
2159 template <class I>
2160 inline typename std::enable_if<(boost::multiprecision::detail::is_signed<I>::value && boost::multiprecision::detail::is_integral<I>::value && (sizeof(I) <= sizeof(long)))>::type eval_gcd(gmp_int& result, const gmp_int& a, const I b)
2161 {
2162 mpz_gcd_ui(result.data(), a.data(), boost::multiprecision::detail::unsigned_abs(b));
2163 }
2164 template <class I>
2165 inline typename std::enable_if<boost::multiprecision::detail::is_signed<I>::value && boost::multiprecision::detail::is_integral<I>::value && ((sizeof(I) <= sizeof(long)))>::type eval_lcm(gmp_int& result, const gmp_int& a, const I b)
2166 {
2167 mpz_lcm_ui(result.data(), a.data(), boost::multiprecision::detail::unsigned_abs(b));
2168 }
2169
2170 inline void eval_integer_sqrt(gmp_int& s, gmp_int& r, const gmp_int& x)
2171 {
2172 mpz_sqrtrem(s.data(), r.data(), x.data());
2173 }
2174
2175 inline std::size_t eval_lsb(const gmp_int& val)
2176 {
2177 int c = eval_get_sign(val);
2178 if (c == 0)
2179 {
2180 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
2181 }
2182 if (c < 0)
2183 {
2184 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
2185 }
2186 return static_cast<unsigned>(mpz_scan1(val.data(), 0));
2187 }
2188
2189 inline std::size_t eval_msb(const gmp_int& val)
2190 {
2191 int c = eval_get_sign(val);
2192 if (c == 0)
2193 {
2194 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
2195 }
2196 if (c < 0)
2197 {
2198 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
2199 }
2200 return static_cast<unsigned>(mpz_sizeinbase(val.data(), 2) - 1);
2201 }
2202
2203 inline bool eval_bit_test(const gmp_int& val, std::size_t index)
2204 {
2205 return mpz_tstbit(val.data(), index) ? true : false;
2206 }
2207
2208 inline void eval_bit_set(gmp_int& val, std::size_t index)
2209 {
2210 mpz_setbit(val.data(), index);
2211 }
2212
2213 inline void eval_bit_unset(gmp_int& val, std::size_t index)
2214 {
2215 mpz_clrbit(val.data(), index);
2216 }
2217
2218 inline void eval_bit_flip(gmp_int& val, std::size_t index)
2219 {
2220 mpz_combit(val.data(), index);
2221 }
2222
2223 inline void eval_qr(const gmp_int& x, const gmp_int& y,
2224 gmp_int& q, gmp_int& r)
2225 {
2226 mpz_tdiv_qr(q.data(), r.data(), x.data(), y.data());
2227 }
2228
2229 template <class Integer>
2230 inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<Integer>::value, Integer>::type eval_integer_modulus(const gmp_int& x, Integer val)
2231 {
2232 #if defined(__MPIR_VERSION) && (__MPIR_VERSION >= 3)
2233 if ((sizeof(Integer) <= sizeof(mpir_ui)) || (val <= (std::numeric_limits<mpir_ui>::max)()))
2234 #else
2235 if ((sizeof(Integer) <= sizeof(long)) || (val <= (std::numeric_limits<unsigned long>::max)()))
2236 #endif
2237 {
2238 return static_cast<Integer>(mpz_tdiv_ui(x.data(), val));
2239 }
2240 else
2241 {
2242 return default_ops::eval_integer_modulus(x, val);
2243 }
2244 }
2245 template <class Integer>
2246 inline typename std::enable_if<boost::multiprecision::detail::is_signed<Integer>::value && boost::multiprecision::detail::is_integral<Integer>::value, Integer>::type eval_integer_modulus(const gmp_int& x, Integer val)
2247 {
2248 return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
2249 }
2250 inline void eval_powm(gmp_int& result, const gmp_int& base, const gmp_int& p, const gmp_int& m)
2251 {
2252 if (eval_get_sign(p) < 0)
2253 {
2254 BOOST_MP_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
2255 }
2256 mpz_powm(result.data(), base.data(), p.data(), m.data());
2257 }
2258
2259 template <class Integer>
2260 inline typename std::enable_if<
2261 boost::multiprecision::detail::is_unsigned<Integer>::value && (sizeof(Integer) <= sizeof(unsigned long))>::type
2262 eval_powm(gmp_int& result, const gmp_int& base, Integer p, const gmp_int& m)
2263 {
2264 mpz_powm_ui(result.data(), base.data(), p, m.data());
2265 }
2266 template <class Integer>
2267 inline typename std::enable_if<boost::multiprecision::detail::is_signed<Integer>::value && boost::multiprecision::detail::is_integral<Integer>::value && (sizeof(Integer) <= sizeof(unsigned long))>::type
2268 eval_powm(gmp_int& result, const gmp_int& base, Integer p, const gmp_int& m)
2269 {
2270 if (p < 0)
2271 {
2272 BOOST_MP_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
2273 }
2274 mpz_powm_ui(result.data(), base.data(), p, m.data());
2275 }
2276
2277 inline std::size_t hash_value(const gmp_int& val)
2278 {
2279 // We should really use mpz_limbs_read here, but that's unsupported on older versions:
2280 std::size_t result = 0;
2281 for (int i = 0; i < std::abs(val.data()[0]._mp_size); ++i)
2282 boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_d[i]);
2283 boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_size);
2284 return result;
2285 }
2286
2287 struct gmp_rational;
2288 void eval_add(gmp_rational& t, const gmp_rational& o);
2289
2290 struct gmp_rational
2291 {
2292 #ifdef BOOST_HAS_LONG_LONG
2293 using signed_types = std::tuple<long, long long> ;
2294 using unsigned_types = std::tuple<unsigned long, unsigned long long>;
2295 #else
2296 using signed_types = std::tuple<long> ;
2297 using unsigned_types = std::tuple<unsigned long>;
2298 #endif
2299 using float_types = std::tuple<double, long double>;
2300
2301 gmp_rational()
2302 {
2303 mpq_init(this->m_data);
2304 }
2305 gmp_rational(const gmp_rational& o)
2306 {
2307 mpq_init(m_data);
2308 if (o.m_data[0]._mp_num._mp_d)
2309 mpq_set(m_data, o.m_data);
2310 }
2311 gmp_rational(const gmp_int& o)
2312 {
2313 mpz_init_set(&m_data[0]._mp_num, o.data());
2314 mpz_init_set_ui(&m_data[0]._mp_den, 1u);
2315 }
2316 gmp_rational(long i)
2317 {
2318 mpz_init_set_si(&m_data[0]._mp_num, i);
2319 mpz_init_set_ui(&m_data[0]._mp_den, 1u);
2320 }
2321 gmp_rational(unsigned long ui)
2322 {
2323 mpz_init_set_ui(&m_data[0]._mp_num, ui);
2324 mpz_init_set_ui(&m_data[0]._mp_den, 1u);
2325 }
2326 // 2-arg constructors:
2327 template <class T, class U>
2328 gmp_rational(const T& a, const U& b, typename std::enable_if<std::is_constructible<gmp_int, T>::value && std::is_constructible<gmp_int, U>::value>::type* = nullptr)
2329 {
2330 gmp_int i(a), j(b);
2331 m_data[0]._mp_num = i.data()[0];
2332 m_data[0]._mp_den = j.data()[0];
2333 mpq_canonicalize(m_data);
2334 i.data()[0]._mp_d = nullptr;
2335 j.data()[0]._mp_d = nullptr;
2336 }
2337 template <class U>
2338 gmp_rational(const gmp_int& a, const U& b, typename std::enable_if<std::is_constructible<gmp_int, U>::value>::type* = nullptr)
2339 {
2340 gmp_int j(b);
2341 mpz_init_set(&m_data[0]._mp_num, a.data());
2342 m_data[0]._mp_den = j.data()[0];
2343 if (boost::multiprecision::detail::unsigned_abs(b) > 1)
2344 mpq_canonicalize(m_data);
2345 j.data()[0]._mp_d = nullptr;
2346 }
2347 template <class U>
2348 gmp_rational(gmp_int&& a, const U& b, typename std::enable_if<std::is_constructible<gmp_int, U>::value>::type* = nullptr)
2349 {
2350 gmp_int j(b);
2351 m_data[0]._mp_num = a.data()[0];
2352 m_data[0]._mp_den = j.data()[0];
2353 if (boost::multiprecision::detail::unsigned_abs(b) > 1)
2354 mpq_canonicalize(m_data);
2355 a.data()[0]._mp_d = nullptr;
2356 j.data()[0]._mp_d = nullptr;
2357 }
2358 template <class T>
2359 gmp_rational(const T& a, const gmp_int& b, typename std::enable_if<std::is_constructible<gmp_int, T>::value>::type* = nullptr)
2360 {
2361 gmp_int i(a);
2362 m_data[0]._mp_num = i.data()[0];
2363 mpz_init_set(&m_data[0]._mp_den, b.data());
2364 if(boost::multiprecision::detail::unsigned_abs(a) > 1)
2365 mpq_canonicalize(m_data);
2366 i.data()[0]._mp_d = nullptr;
2367 }
2368 template <class T>
2369 gmp_rational(const T& a, gmp_int&& b, typename std::enable_if<std::is_constructible<gmp_int, T>::value>::type* = nullptr)
2370 {
2371 gmp_int i(a);
2372 m_data[0]._mp_num = i.data()[0];
2373 m_data[0]._mp_den = b.data()[0];
2374 if(boost::multiprecision::detail::unsigned_abs(a) > 1)
2375 mpq_canonicalize(m_data);
2376 i.data()[0]._mp_d = nullptr;
2377 b.data()[0]._mp_d = nullptr;
2378 }
2379 gmp_rational(const gmp_int& a, const gmp_int& b)
2380 {
2381 mpz_init_set(&m_data[0]._mp_num, a.data());
2382 mpz_init_set(&m_data[0]._mp_den, b.data());
2383 mpq_canonicalize(m_data);
2384 }
2385 gmp_rational(const gmp_int& a, gmp_int&& b)
2386 {
2387 mpz_init_set(&m_data[0]._mp_num, a.data());
2388 m_data[0]._mp_den = b.data()[0];
2389 mpq_canonicalize(m_data);
2390 b.data()[0]._mp_d = nullptr;
2391 }
2392 gmp_rational(gmp_int&& a, const gmp_int& b)
2393 {
2394 m_data[0]._mp_num = a.data()[0];
2395 mpz_init_set(&m_data[0]._mp_den, b.data());
2396 mpq_canonicalize(m_data);
2397 a.data()[0]._mp_d = nullptr;
2398 }
2399 gmp_rational(gmp_int&& a, gmp_int&& b)
2400 {
2401 m_data[0]._mp_num = a.data()[0];
2402 m_data[0]._mp_den = b.data()[0];
2403 mpq_canonicalize(m_data);
2404 a.data()[0]._mp_d = nullptr;
2405 b.data()[0]._mp_d = nullptr;
2406 }
2407 // rvalue copy
2408 gmp_rational(gmp_rational&& o) noexcept
2409 {
2410 m_data[0] = o.m_data[0];
2411 o.m_data[0]._mp_num._mp_d = 0;
2412 o.m_data[0]._mp_den._mp_d = 0;
2413 }
2414 gmp_rational(const mpq_t o)
2415 {
2416 mpq_init(m_data);
2417 mpq_set(m_data, o);
2418 }
2419 gmp_rational(const mpz_t o)
2420 {
2421 mpq_init(m_data);
2422 mpq_set_z(m_data, o);
2423 }
2424 gmp_rational& operator=(const gmp_rational& o)
2425 {
2426 if (m_data[0]._mp_den._mp_d == 0)
2427 mpq_init(m_data);
2428 mpq_set(m_data, o.m_data);
2429 return *this;
2430 }
2431 // rvalue assign
2432 gmp_rational& operator=(gmp_rational&& o) noexcept
2433 {
2434 mpq_swap(m_data, o.m_data);
2435 return *this;
2436 }
2437 #ifdef BOOST_HAS_LONG_LONG
2438 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
2439 gmp_rational& operator=(unsigned long long i)
2440 {
2441 *this = static_cast<unsigned long>(i);
2442 return *this;
2443 }
2444 #else
2445 gmp_rational& operator=(unsigned long long i)
2446 {
2447 if (m_data[0]._mp_den._mp_d == 0)
2448 mpq_init(m_data);
2449 gmp_int zi;
2450 zi = i;
2451 mpq_set_z(m_data, zi.data());
2452 return *this;
2453 }
2454 gmp_rational& operator=(long long i)
2455 {
2456 if (m_data[0]._mp_den._mp_d == 0)
2457 mpq_init(m_data);
2458 bool neg = i < 0;
2459 *this = boost::multiprecision::detail::unsigned_abs(i);
2460 if (neg)
2461 mpq_neg(m_data, m_data);
2462 return *this;
2463 }
2464 #endif
2465 #endif
2466 gmp_rational& operator=(unsigned long i)
2467 {
2468 if (m_data[0]._mp_den._mp_d == 0)
2469 mpq_init(m_data);
2470 mpq_set_ui(m_data, i, 1);
2471 return *this;
2472 }
2473 gmp_rational& operator=(long i)
2474 {
2475 if (m_data[0]._mp_den._mp_d == 0)
2476 mpq_init(m_data);
2477 mpq_set_si(m_data, i, 1);
2478 return *this;
2479 }
2480 gmp_rational& operator=(double d)
2481 {
2482 if (m_data[0]._mp_den._mp_d == 0)
2483 mpq_init(m_data);
2484 mpq_set_d(m_data, d);
2485 return *this;
2486 }
2487 template <class F>
2488 gmp_rational& assign_float(F a)
2489 {
2490 using default_ops::eval_add;
2491 using default_ops::eval_subtract;
2492 BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp;
2493
2494 if (m_data[0]._mp_den._mp_d == 0)
2495 mpq_init(m_data);
2496
2497 if (a == 0)
2498 {
2499 mpq_set_si(m_data, 0, 1);
2500 return *this;
2501 }
2502
2503 if (a == 1)
2504 {
2505 mpq_set_si(m_data, 1, 1);
2506 return *this;
2507 }
2508
2509 BOOST_MP_ASSERT(!BOOST_MP_ISINF(a));
2510 BOOST_MP_ASSERT(!BOOST_MP_ISNAN(a));
2511
2512 int e;
2513 F f, term;
2514 mpq_set_ui(m_data, 0, 1);
2515 mpq_set_ui(m_data, 0u, 1);
2516 gmp_rational t;
2517
2518 f = frexp(a, &e);
2519
2520 constexpr const int shift = std::numeric_limits<int>::digits - 1;
2521
2522 while (f)
2523 {
2524 // extract int sized bits from f:
2525 f = ldexp(f, shift);
2526 term = floor(f);
2527 e -= shift;
2528 mpq_mul_2exp(m_data, m_data, shift);
2529 t = static_cast<long>(term);
2530 eval_add(*this, t);
2531 f -= term;
2532 }
2533 if (e > 0)
2534 mpq_mul_2exp(m_data, m_data, e);
2535 else if (e < 0)
2536 mpq_div_2exp(m_data, m_data, -e);
2537 return *this;
2538 }
2539 gmp_rational& operator=(long double a)
2540 {
2541 return assign_float(a);
2542 }
2543 #ifdef BOOST_HAS_FLOAT128
2544 gmp_rational& operator=(float128_type a)
2545 {
2546 return assign_float(a);
2547 }
2548 #endif
2549 #ifdef BOOST_HAS_INT128
2550 gmp_rational& operator=(uint128_type i)
2551 {
2552 gmp_int gi;
2553 gi = i;
2554 return *this = gi;
2555 }
2556 gmp_rational& operator=(int128_type i)
2557 {
2558 gmp_int gi;
2559 gi = i;
2560 return *this = gi;
2561 }
2562 #endif
2563 gmp_rational& operator=(const char* s)
2564 {
2565 if (m_data[0]._mp_den._mp_d == 0)
2566 mpq_init(m_data);
2567 if (0 != mpq_set_str(m_data, s, 10))
2568 BOOST_MP_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid rational number.")));
2569 return *this;
2570 }
2571 gmp_rational& operator=(const gmp_int& o)
2572 {
2573 if (m_data[0]._mp_den._mp_d == 0)
2574 mpq_init(m_data);
2575 mpq_set_z(m_data, o.data());
2576 return *this;
2577 }
2578 gmp_rational& operator=(const mpq_t o)
2579 {
2580 if (m_data[0]._mp_den._mp_d == 0)
2581 mpq_init(m_data);
2582 mpq_set(m_data, o);
2583 return *this;
2584 }
2585 gmp_rational& operator=(const mpz_t o)
2586 {
2587 if (m_data[0]._mp_den._mp_d == 0)
2588 mpq_init(m_data);
2589 mpq_set_z(m_data, o);
2590 return *this;
2591 }
2592 void swap(gmp_rational& o)
2593 {
2594 mpq_swap(m_data, o.m_data);
2595 }
2596 std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags /*f*/) const
2597 {
2598 BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2599 // TODO make a better job of this including handling of f!!
2600 void* (*alloc_func_ptr)(size_t);
2601 void* (*realloc_func_ptr)(void*, size_t, size_t);
2602 void (*free_func_ptr)(void*, size_t);
2603 const char* ps = mpq_get_str(0, 10, m_data);
2604 std::string s = ps;
2605 mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
2606 (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
2607 return s;
2608 }
2609 ~gmp_rational()
2610 {
2611 if (m_data[0]._mp_num._mp_d || m_data[0]._mp_den._mp_d)
2612 mpq_clear(m_data);
2613 }
2614 void negate()
2615 {
2616 BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2617 mpq_neg(m_data, m_data);
2618 }
2619 int compare(const gmp_rational& o) const
2620 {
2621 BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d && o.m_data[0]._mp_num._mp_d);
2622 return mpq_cmp(m_data, o.m_data);
2623 }
2624 template <class V>
2625 int compare(V v) const
2626 {
2627 gmp_rational d;
2628 d = v;
2629 return compare(d);
2630 }
2631 int compare(unsigned long v) const
2632 {
2633 BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2634 return mpq_cmp_ui(m_data, v, 1);
2635 }
2636 int compare(long v) const
2637 {
2638 BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2639 return mpq_cmp_si(m_data, v, 1);
2640 }
2641 mpq_t& data()
2642 {
2643 BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2644 return m_data;
2645 }
2646 const mpq_t& data() const
2647 {
2648 BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2649 return m_data;
2650 }
2651
2652 protected:
2653 mpq_t m_data;
2654 };
2655
2656 inline bool eval_is_zero(const gmp_rational& val)
2657 {
2658 return mpq_sgn(val.data()) == 0;
2659 }
2660 template <class T>
2661 inline bool eval_eq(gmp_rational& a, const T& b)
2662 {
2663 return a.compare(b) == 0;
2664 }
2665 template <class T>
2666 inline bool eval_lt(gmp_rational& a, const T& b)
2667 {
2668 return a.compare(b) < 0;
2669 }
2670 template <class T>
2671 inline bool eval_gt(gmp_rational& a, const T& b)
2672 {
2673 return a.compare(b) > 0;
2674 }
2675
2676 inline void eval_add(gmp_rational& t, const gmp_rational& o)
2677 {
2678 mpq_add(t.data(), t.data(), o.data());
2679 }
2680 inline void eval_subtract(gmp_rational& t, const gmp_rational& o)
2681 {
2682 mpq_sub(t.data(), t.data(), o.data());
2683 }
2684 inline void eval_multiply(gmp_rational& t, const gmp_rational& o)
2685 {
2686 mpq_mul(t.data(), t.data(), o.data());
2687 }
2688 inline void eval_divide(gmp_rational& t, const gmp_rational& o)
2689 {
2690 if (eval_is_zero(o))
2691 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2692 mpq_div(t.data(), t.data(), o.data());
2693 }
2694 inline void eval_add(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2695 {
2696 mpq_add(t.data(), p.data(), o.data());
2697 }
2698 inline void eval_subtract(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2699 {
2700 mpq_sub(t.data(), p.data(), o.data());
2701 }
2702 inline void eval_multiply(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2703 {
2704 mpq_mul(t.data(), p.data(), o.data());
2705 }
2706 inline void eval_divide(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2707 {
2708 if (eval_is_zero(o))
2709 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2710 mpq_div(t.data(), p.data(), o.data());
2711 }
2712 //
2713 // operator with scalars:
2714 //
2715 inline void eval_add(gmp_rational& result, gmp_rational const& a, gmp_int const& b)
2716 {
2717 // we allow result and a to be the same object here:
2718 if (&a != &result)
2719 {
2720 mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2721 mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2722 }
2723 mpz_addmul(mpq_numref(result.data()), mpq_denref(a.data()), b.data());
2724 // no need to normalize, there can be no common divisor as long as a is already normalized.
2725 }
2726 inline void eval_add(gmp_rational& result, gmp_rational const& a, unsigned long b)
2727 {
2728 // we allow result and a to be the same object here:
2729 if (&a != &result)
2730 {
2731 mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2732 mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2733 }
2734 mpz_addmul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b);
2735 // no need to normalize, there can be no common divisor as long as a is already normalized.
2736 }
2737 inline void eval_add(gmp_rational& result, gmp_rational const& a, long b)
2738 {
2739 // we allow result and a to be the same object here:
2740 if (&a != &result)
2741 {
2742 mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2743 mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2744 }
2745 if(b > 0)
2746 mpz_addmul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b);
2747 else
2748 mpz_submul_ui(mpq_numref(result.data()), mpq_denref(a.data()), boost::multiprecision::detail::unsigned_abs(b));
2749 // no need to normalize, there can be no common divisor as long as a is already normalized.
2750 }
2751 template <class T>
2752 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_add(gmp_rational& result, gmp_rational const& a, const T& b)
2753 {
2754 gmp_int t;
2755 t = b;
2756 eval_add(result, a, t);
2757 }
2758 template <class T>
2759 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_add(gmp_rational& result, const T& b, gmp_rational const& a)
2760 {
2761 eval_add(result, a, b);
2762 }
2763 template <class T>
2764 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_add(gmp_rational& result, const T& b)
2765 {
2766 eval_add(result, result, b);
2767 }
2768 inline void eval_subtract(gmp_rational& result, gmp_rational const& a, gmp_int const& b)
2769 {
2770 // we allow result and a to be the same object here:
2771 if (&a != &result)
2772 {
2773 mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2774 mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2775 }
2776 mpz_submul(mpq_numref(result.data()), mpq_denref(a.data()), b.data());
2777 // no need to normalize, there can be no common divisor as long as a is already normalized.
2778 }
2779 inline void eval_subtract(gmp_rational& result, gmp_rational const& a, unsigned long b)
2780 {
2781 // we allow result and a to be the same object here:
2782 if (&a != &result)
2783 {
2784 mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2785 mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2786 }
2787 mpz_submul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b);
2788 // no need to normalize, there can be no common divisor as long as a is already normalized.
2789 }
2790 inline void eval_subtract(gmp_rational& result, gmp_rational const& a, long b)
2791 {
2792 // we allow result and a to be the same object here:
2793 if (&a != &result)
2794 {
2795 mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2796 mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2797 }
2798 if(b > 0)
2799 mpz_submul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b);
2800 else
2801 mpz_addmul_ui(mpq_numref(result.data()), mpq_denref(a.data()), boost::multiprecision::detail::unsigned_abs(b));
2802 // no need to normalize, there can be no common divisor as long as a is already normalized.
2803 }
2804 template <class T>
2805 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_subtract(gmp_rational& result, gmp_rational const& a, const T& b)
2806 {
2807 gmp_int t;
2808 t = b;
2809 eval_subtract(result, a, t);
2810 }
2811 template <class T>
2812 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_subtract(gmp_rational& result, const T& b, gmp_rational const& a)
2813 {
2814 eval_subtract(result, a, b);
2815 result.negate();
2816 }
2817 template <class T>
2818 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_subtract(gmp_rational& result, const T& b)
2819 {
2820 eval_subtract(result, result, b);
2821 }
2822
2823 inline void eval_multiply(gmp_rational& result, gmp_rational const& a, gmp_int const& b)
2824 {
2825 gmp_int g, t;
2826 mpz_gcd(g.data(), mpq_denref(a.data()), b.data());
2827 if (!mpz_fits_uint_p(g.data()) || (mpz_get_ui(g.data()) != 1))
2828 {
2829 // We get here if the gcd is not unity, this is true if the number is
2830 // too large for an unsigned long, or if we get an unsigned long and check against 1.
2831 eval_divide(t, b, g);
2832 mpz_mul(mpq_numref(result.data()), t.data(), mpq_numref(a.data()));
2833 mpz_divexact(mpq_denref(result.data()), mpq_denref(a.data()), g.data());
2834 }
2835 else
2836 {
2837 // gcd is 1.
2838 mpz_mul(mpq_numref(result.data()), mpq_numref(a.data()), b.data());
2839 if (&result != &a)
2840 mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2841 }
2842 }
2843 inline void eval_multiply(gmp_rational& result, gmp_rational const& a, unsigned long b)
2844 {
2845 if (b == 0)
2846 {
2847 mpq_set_ui(result.data(), b, 1);
2848 return;
2849 }
2850 if (mpz_sgn(mpq_numref(a.data())) == 0)
2851 {
2852 result = a;
2853 return;
2854 }
2855 unsigned long g = mpz_gcd_ui(nullptr, mpq_denref(a.data()), b);
2856 if (g != 1)
2857 {
2858 BOOST_MP_ASSERT(g);
2859 b /= g;
2860 mpz_mul_ui(mpq_numref(result.data()), mpq_numref(a.data()), b);
2861 mpz_divexact_ui(mpq_denref(result.data()), mpq_denref(a.data()), g);
2862 }
2863 else
2864 {
2865 mpz_mul_ui(mpq_numref(result.data()), mpq_numref(a.data()), b);
2866 if (&result != &a)
2867 mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2868 }
2869 }
2870 inline void eval_multiply(gmp_rational& result, gmp_rational const& a, long b)
2871 {
2872 eval_multiply(result, a, boost::multiprecision::detail::unsigned_abs(b));
2873 if (b < 0)
2874 result.negate();
2875 }
2876 template <class T>
2877 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_multiply(gmp_rational& result, gmp_rational const& a, const T& b)
2878 {
2879 gmp_int t;
2880 t = b;
2881 eval_multiply(result, a, t);
2882 }
2883 template <class T>
2884 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_multiply(gmp_rational& result, const T& b, gmp_rational const& a)
2885 {
2886 eval_multiply(result, a, b);
2887 }
2888 template <class T>
2889 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_multiply(gmp_rational& result, const T& b)
2890 {
2891 eval_multiply(result, result, b);
2892 }
2893
2894 inline int eval_get_sign(const gmp_rational& val)
2895 {
2896 return mpq_sgn(val.data());
2897 }
2898 template <class R>
2899 inline typename std::enable_if<number_category<R>::value == number_kind_floating_point>::type eval_convert_to(R* result, const gmp_rational& backend)
2900 {
2901 //
2902 // The generic conversion is as good as anything we can write here:
2903 //
2904 // This does not round correctly:
2905 //
2906 //*result = mpq_get_d(val.data());
2907 //
2908 // This does:
2909 //
2910 ::boost::multiprecision::detail::generic_convert_rational_to_float(*result, backend);
2911 }
2912 #ifdef BOOST_HAS_FLOAT128
2913 inline void eval_convert_to(float128_type* result, const gmp_rational& val)
2914 {
2915 using default_ops::eval_convert_to;
2916
2917 gmp_int n, d;
2918 float128_type fn, fd;
2919 mpz_set(n.data(), mpq_numref(val.data()));
2920 mpz_set(d.data(), mpq_denref(val.data()));
2921
2922 eval_convert_to(&fn, n);
2923 eval_convert_to(&fd, d);
2924
2925 *result = fn / fd;
2926 }
2927 #endif
2928
2929 template <class R>
2930 inline typename std::enable_if<number_category<R>::value == number_kind_integer>::type eval_convert_to(R* result, const gmp_rational& backend)
2931 {
2932 gmp_int n(mpq_numref(backend.data()));
2933 gmp_int d(mpq_denref(backend.data()));
2934 using default_ops::eval_divide;
2935 eval_divide(n, d);
2936 using default_ops::eval_convert_to;
2937 eval_convert_to(result, n);
2938 }
2939
2940 inline void eval_abs(gmp_rational& result, const gmp_rational& val)
2941 {
2942 mpq_abs(result.data(), val.data());
2943 }
2944
2945 inline void assign_components(gmp_rational& result, unsigned long v1, unsigned long v2)
2946 {
2947 mpq_set_ui(result.data(), v1, v2);
2948 mpq_canonicalize(result.data());
2949 }
2950 inline void assign_components(gmp_rational& result, long v1, long v2)
2951 {
2952 mpq_set_si(result.data(), v1, v2);
2953 mpq_canonicalize(result.data());
2954 }
2955 inline void assign_components(gmp_rational& result, gmp_int const& v1, gmp_int const& v2)
2956 {
2957 mpz_set(mpq_numref(result.data()), v1.data());
2958 mpz_set(mpq_denref(result.data()), v2.data());
2959 mpq_canonicalize(result.data());
2960 }
2961 template <class T, class U>
2962 void assign_components(gmp_rational& result, const T& a, const U& b)
2963 {
2964 gmp_int x, y;
2965 x = a;
2966 y = b;
2967 std::swap(result.data()[0]._mp_num, x.data()[0]);
2968 std::swap(result.data()[0]._mp_den, y.data()[0]);
2969 mpq_canonicalize(result.data());
2970 }
2971 template <class U>
2972 void assign_components(gmp_rational& result, const gmp_int& a, const U& b)
2973 {
2974 gmp_int y;
2975 y = b;
2976 mpz_set(&result.data()[0]._mp_num, a.data());
2977 std::swap(result.data()[0]._mp_den, y.data()[0]);
2978 mpq_canonicalize(result.data());
2979 }
2980 template <class T>
2981 void assign_components(gmp_rational& result, const T& a, const gmp_int& b)
2982 {
2983 gmp_int x;
2984 x = a;
2985 std::swap(result.data()[0]._mp_num, x.data()[0]);
2986 mpz_set(&result.data()[0]._mp_den, b.data());
2987 mpq_canonicalize(result.data());
2988 }
2989
2990
2991 inline std::size_t hash_value(const gmp_rational& val)
2992 {
2993 std::size_t result = 0;
2994 for (int i = 0; i < std::abs(val.data()[0]._mp_num._mp_size); ++i)
2995 boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_num._mp_d[i]);
2996 for (int i = 0; i < std::abs(val.data()[0]._mp_den._mp_size); ++i)
2997 boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_den._mp_d[i]);
2998 boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_num._mp_size);
2999 return result;
3000 }
3001
3002 //
3003 // Some useful helpers:
3004 //
3005 inline std::size_t used_gmp_int_bits(const gmp_int& val)
3006 {
3007 return eval_msb(val) - eval_lsb(val) + 1;
3008 }
3009 inline std::size_t used_gmp_rational_bits(const gmp_rational& val)
3010 {
3011 unsigned d2_d = static_cast<unsigned>(mpz_sizeinbase(mpq_denref(val.data()), 2) - mpz_scan1(mpq_denref(val.data()), 0));
3012 unsigned d2_n = static_cast<unsigned>(mpz_sizeinbase(mpq_numref(val.data()), 2) - mpz_scan1(mpq_numref(val.data()), 0));
3013 return (std::max)(d2_d, d2_n);
3014 }
3015
3016 //
3017 // Some member functions that are dependent upon previous code go here:
3018 //
3019 template <unsigned Digits10>
3020 template <unsigned D>
3021 inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename std::enable_if<D <= Digits10>::type*)
3022 {
3023 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3024 mpf_set(this->m_data, o.data());
3025 }
3026 template <unsigned Digits10>
3027 template <unsigned D>
3028 inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename std::enable_if< !(D <= Digits10)>::type*)
3029 {
3030 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3031 mpf_set(this->m_data, o.data());
3032 }
3033 template <unsigned Digits10>
3034 inline gmp_float<Digits10>::gmp_float(const gmp_int& o)
3035 {
3036 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3037 mpf_set_z(this->data(), o.data());
3038 }
3039 template <unsigned Digits10>
3040 inline gmp_float<Digits10>::gmp_float(const gmp_rational& o)
3041 {
3042 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3043 mpf_set_q(this->data(), o.data());
3044 }
3045 template <unsigned Digits10>
3046 template <unsigned D>
3047 inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_float<D>& o)
3048 {
3049 if (this->m_data[0]._mp_d == 0)
3050 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3051 mpf_set(this->m_data, o.data());
3052 return *this;
3053 }
3054 template <unsigned Digits10>
3055 inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_int& o)
3056 {
3057 if (this->m_data[0]._mp_d == 0)
3058 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3059 mpf_set_z(this->data(), o.data());
3060 return *this;
3061 }
3062 template <unsigned Digits10>
3063 inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_rational& o)
3064 {
3065 if (this->m_data[0]._mp_d == 0)
3066 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3067 mpf_set_q(this->data(), o.data());
3068 return *this;
3069 }
3070 inline gmp_float<0>::gmp_float(const gmp_int& o) : requested_precision(get_default_precision())
3071 {
3072 if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3073 {
3074 std::size_t d2 = used_gmp_int_bits(o);
3075 std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(d2);
3076 if (d10 > requested_precision)
3077 requested_precision = static_cast<unsigned>(d10);
3078 }
3079 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
3080 mpf_set_z(this->data(), o.data());
3081 }
3082 inline gmp_float<0>::gmp_float(const gmp_rational& o) : requested_precision(get_default_precision())
3083 {
3084 if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3085 {
3086 std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(used_gmp_rational_bits(o));
3087 if (d10 > requested_precision)
3088 requested_precision = static_cast<unsigned>(d10);
3089 }
3090 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
3091 mpf_set_q(this->data(), o.data());
3092 }
3093 inline gmp_float<0>& gmp_float<0>::operator=(const gmp_int& o)
3094 {
3095 if (this->m_data[0]._mp_d == 0)
3096 {
3097 requested_precision = this->get_default_precision();
3098 if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3099 {
3100 std::size_t d2 = used_gmp_int_bits(o);
3101 std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(d2);
3102 if (d10 > requested_precision)
3103 requested_precision = static_cast<unsigned>(d10);
3104 }
3105 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
3106 }
3107 else if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3108 {
3109 std::size_t d2 = used_gmp_int_bits(o);
3110 std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(d2);
3111 if (d10 > requested_precision)
3112 this->precision(static_cast<unsigned>(d10));
3113 }
3114 mpf_set_z(this->data(), o.data());
3115 return *this;
3116 }
3117 inline gmp_float<0>& gmp_float<0>::operator=(const gmp_rational& o)
3118 {
3119 if (this->m_data[0]._mp_d == 0)
3120 {
3121 requested_precision = this->get_default_precision();
3122 if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3123 {
3124 std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(used_gmp_rational_bits(o));
3125 if (d10 > requested_precision)
3126 requested_precision = static_cast<unsigned>(d10);
3127 }
3128 mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
3129 }
3130 else if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3131 {
3132 std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(used_gmp_rational_bits(o));
3133 if (d10 > requested_precision)
3134 this->precision(static_cast<unsigned>(d10));
3135 }
3136 mpf_set_q(this->data(), o.data());
3137 return *this;
3138 }
3139 inline gmp_int::gmp_int(const gmp_rational& o)
3140 {
3141 mpz_init(this->m_data);
3142 mpz_set_q(this->m_data, o.data());
3143 }
3144 inline gmp_int& gmp_int::operator=(const gmp_rational& o)
3145 {
3146 if (this->m_data[0]._mp_d == 0)
3147 mpz_init(this->m_data);
3148 mpz_set_q(this->m_data, o.data());
3149 return *this;
3150 }
3151
3152 } //namespace backends
3153
3154 using boost::multiprecision::backends::gmp_float;
3155 using boost::multiprecision::backends::gmp_int;
3156 using boost::multiprecision::backends::gmp_rational;
3157
3158 template <expression_template_option ExpressionTemplates>
3159 struct component_type<number<gmp_rational, ExpressionTemplates> >
3160 {
3161 using type = number<gmp_int, ExpressionTemplates>;
3162 };
3163
3164 template <expression_template_option ET>
3165 inline number<gmp_int, ET> numerator(const number<gmp_rational, ET>& val)
3166 {
3167 number<gmp_int, ET> result;
3168 mpz_set(result.backend().data(), (mpq_numref(val.backend().data())));
3169 return result;
3170 }
3171 template <expression_template_option ET>
3172 inline number<gmp_int, ET> denominator(const number<gmp_rational, ET>& val)
3173 {
3174 number<gmp_int, ET> result;
3175 mpz_set(result.backend().data(), (mpq_denref(val.backend().data())));
3176 return result;
3177 }
3178
3179 namespace detail {
3180
3181 template <>
3182 struct digits2<number<gmp_float<0>, et_on> >
3183 {
3184 static long value()
3185 {
3186 return multiprecision::detail::digits10_2_2(gmp_float<0>::thread_default_precision());
3187 }
3188 };
3189
3190 template <>
3191 struct digits2<number<gmp_float<0>, et_off> >
3192 {
3193 static long value()
3194 {
3195 return multiprecision::detail::digits10_2_2(gmp_float<0>::thread_default_precision());
3196 }
3197 };
3198
3199 template <>
3200 struct digits2<number<debug_adaptor<gmp_float<0> >, et_on> >
3201 {
3202 static long value()
3203 {
3204 return multiprecision::detail::digits10_2_2(gmp_float<0>::thread_default_precision());
3205 }
3206 };
3207
3208 template <>
3209 struct digits2<number<debug_adaptor<gmp_float<0> >, et_off> >
3210 {
3211 static long value()
3212 {
3213 return multiprecision::detail::digits10_2_2(gmp_float<0>::thread_default_precision());
3214 }
3215 };
3216
3217 template <unsigned Digits10>
3218 struct transcendental_reduction_type<boost::multiprecision::backends::gmp_float<Digits10> >
3219 {
3220 //
3221 // The type used for trigonometric reduction needs 3 times the precision of the base type.
3222 // This is double the precision of the original type, plus the largest exponent supported.
3223 // As a practical measure the largest argument supported is 1/eps, as supporting larger
3224 // arguments requires the division of argument by PI/2 to also be done at higher precision,
3225 // otherwise the result (an integer) can not be represented exactly.
3226 //
3227 // See ARGUMENT REDUCTION FOR HUGE ARGUMENTS. K C Ng.
3228 //
3229 using type = boost::multiprecision::backends::gmp_float<Digits10 * 3>;
3230 };
3231
3232
3233 } // namespace detail
3234
3235 template <>
3236 struct number_category<detail::canonical<mpz_t, gmp_int>::type> : public std::integral_constant<int, number_kind_integer>
3237 {};
3238 template <>
3239 struct number_category<detail::canonical<mpq_t, gmp_rational>::type> : public std::integral_constant<int, number_kind_rational>
3240 {};
3241 template <>
3242 struct number_category<detail::canonical<mpf_t, gmp_float<0> >::type> : public std::integral_constant<int, number_kind_floating_point>
3243 {};
3244
3245 namespace detail {
3246 template <>
3247 struct is_variable_precision<backends::gmp_float<0> > : public std::integral_constant<bool, true>
3248 {};
3249 } // namespace detail
3250
3251 using mpf_float_50 = number<gmp_float<50> > ;
3252 using mpf_float_100 = number<gmp_float<100> > ;
3253 using mpf_float_500 = number<gmp_float<500> > ;
3254 using mpf_float_1000 = number<gmp_float<1000> >;
3255 using mpf_float = number<gmp_float<0> > ;
3256 using mpz_int = number<gmp_int> ;
3257 using mpq_rational = number<gmp_rational> ;
3258
3259 } // namespace multiprecision
3260
3261 namespace math { namespace tools {
3262
3263 #ifndef BOOST_MP_MATH_AVAILABLE
3264
3265 template <typename T>
3266 inline int digits();
3267
3268 template <typename T>
3269 inline T max_value();
3270
3271 template <typename T>
3272 inline T min_value();
3273
3274 #endif // BOOST_MP_MATH_AVAILABLE
3275
3276 inline void set_output_precision(const boost::multiprecision::mpf_float& val, std::ostream& os)
3277 {
3278 os << std::setprecision(val.precision());
3279 }
3280
3281 template <>
3282 inline int digits<boost::multiprecision::mpf_float>()
3283 #ifdef BOOST_MATH_NOEXCEPT
3284 noexcept
3285 #endif
3286 {
3287 return multiprecision::detail::digits10_2_2(boost::multiprecision::mpf_float::thread_default_precision());
3288 }
3289 template <>
3290 inline int digits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >()
3291 #ifdef BOOST_MATH_NOEXCEPT
3292 noexcept
3293 #endif
3294 {
3295 return multiprecision::detail::digits10_2_2(boost::multiprecision::mpf_float::thread_default_precision());
3296 }
3297
3298 template <>
3299 inline boost::multiprecision::mpf_float
3300 max_value<boost::multiprecision::mpf_float>()
3301 {
3302 boost::multiprecision::mpf_float result(0.5);
3303 mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3304 return result;
3305 }
3306
3307 template <>
3308 inline boost::multiprecision::mpf_float
3309 min_value<boost::multiprecision::mpf_float>()
3310 {
3311 boost::multiprecision::mpf_float result(0.5);
3312 mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3313 return result;
3314 }
3315
3316 template <>
3317 inline boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off>
3318 max_value<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >()
3319 {
3320 boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> result(0.5);
3321 mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3322 return result;
3323 }
3324
3325 template <>
3326 inline boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off>
3327 min_value<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >()
3328 {
3329 boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> result(0.5);
3330 mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3331 return result;
3332 }
3333
3334 template <>
3335 inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >()
3336 #ifdef BOOST_MATH_NOEXCEPT
3337 noexcept
3338 #endif
3339 {
3340 return multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >::thread_default_precision());
3341 }
3342 template <>
3343 inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >()
3344 #ifdef BOOST_MATH_NOEXCEPT
3345 noexcept
3346 #endif
3347 {
3348 return multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >::thread_default_precision());
3349 }
3350
3351 template <>
3352 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >
3353 max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >()
3354 {
3355 return max_value<boost::multiprecision::mpf_float>().backend();
3356 }
3357
3358 template <>
3359 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >
3360 min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >()
3361 {
3362 return min_value<boost::multiprecision::mpf_float>().backend();
3363 }
3364
3365 template <>
3366 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off>
3367 max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >()
3368 {
3369 return max_value<boost::multiprecision::mpf_float>().backend();
3370 }
3371
3372 template <>
3373 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off>
3374 min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >()
3375 {
3376 return min_value<boost::multiprecision::mpf_float>().backend();
3377 }
3378
3379 }} // namespace math::tools
3380
3381 } // namespace boost
3382
3383 namespace std {
3384
3385 //
3386 // numeric_limits [partial] specializations for the types declared in this header:
3387 //
3388 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3389 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >
3390 {
3391 using number_type = boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates>;
3392
3393 //
3394 // min and max values chosen so as to not cause segfaults when calling
3395 // mpf_get_str on 64-bit Linux builds. Possibly we could use larger
3396 // exponent values elsewhere.
3397 //
3398 static number_type calc_min()
3399 {
3400 number_type result(1);
3401 mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3402 return result;
3403 }
3404 static number_type calc_max()
3405 {
3406 number_type result(1);
3407 mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3408 return result;
3409 }
3410 static number_type calc_epsilon()
3411 {
3412 number_type result(1);
3413 mpf_div_2exp(result.backend().data(), result.backend().data(), std::numeric_limits<number_type>::digits - 1);
3414 return result;
3415 }
3416
3417
3418 public:
3419 static constexpr bool is_specialized = true;
3420 static number_type(min)()
3421 {
3422 // rely on C++11 thread safe initialization of statics:
3423 static const number_type value{calc_min()};
3424 return value;
3425 }
3426 static number_type(max)()
3427 {
3428 static number_type value{calc_max()};
3429 return value;
3430 }
3431 static constexpr number_type lowest()
3432 {
3433 return -(max)();
3434 }
3435 static constexpr int digits = static_cast<int>((Digits10 * 1000L) / 301L + ((Digits10 * 1000L) % 301L ? 2 : 1));
3436 static constexpr int digits10 = Digits10;
3437 // Have to allow for a possible extra limb inside the gmp data structure:
3438 static constexpr int max_digits10 = Digits10 + 3 + ((GMP_LIMB_BITS * 301L) / 1000L);
3439 static constexpr bool is_signed = true;
3440 static constexpr bool is_integer = false;
3441 static constexpr bool is_exact = false;
3442 static constexpr int radix = 2;
3443 static number_type epsilon()
3444 {
3445 static const number_type value{calc_epsilon()};
3446 return value;
3447 }
3448 // What value should this be????
3449 static number_type round_error()
3450 {
3451 return 1;
3452 }
3453 static constexpr long min_exponent = LONG_MIN;
3454 static constexpr long min_exponent10 = (LONG_MIN / 1000) * 301L;
3455 static constexpr long max_exponent = LONG_MAX;
3456 static constexpr long max_exponent10 = (LONG_MAX / 1000) * 301L;
3457 static constexpr bool has_infinity = false;
3458 static constexpr bool has_quiet_NaN = false;
3459 static constexpr bool has_signaling_NaN = false;
3460 static constexpr float_denorm_style has_denorm = denorm_absent;
3461 static constexpr bool has_denorm_loss = false;
3462 static constexpr number_type infinity() { return number_type(); }
3463 static constexpr number_type quiet_NaN() { return number_type(); }
3464 static constexpr number_type signaling_NaN() { return number_type(); }
3465 static constexpr number_type denorm_min() { return number_type(); }
3466 static constexpr bool is_iec559 = false;
3467 static constexpr bool is_bounded = true;
3468 static constexpr bool is_modulo = false;
3469 static constexpr bool traps = true;
3470 static constexpr bool tinyness_before = false;
3471 static constexpr float_round_style round_style = round_indeterminate;
3472 };
3473
3474 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3475 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::digits;
3476 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3477 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::digits10;
3478 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3479 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_digits10;
3480 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3481 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_signed;
3482 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3483 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_integer;
3484 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3485 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_exact;
3486 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3487 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::radix;
3488 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3489 constexpr long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::min_exponent;
3490 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3491 constexpr long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::min_exponent10;
3492 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3493 constexpr long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_exponent;
3494 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3495 constexpr long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_exponent10;
3496 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3497 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_infinity;
3498 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3499 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_quiet_NaN;
3500 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3501 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_signaling_NaN;
3502 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3503 constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_denorm;
3504 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3505 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_denorm_loss;
3506 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3507 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_iec559;
3508 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3509 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_bounded;
3510 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3511 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_modulo;
3512 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3513 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::traps;
3514 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3515 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::tinyness_before;
3516 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3517 constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::round_style;
3518
3519 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3520 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >
3521 {
3522 using number_type = boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates>;
3523
3524 public:
3525 static constexpr bool is_specialized = false;
3526 static number_type(min)() { return number_type(); }
3527 static number_type(max)() { return number_type(); }
3528 static number_type lowest() { return number_type(); }
3529 static constexpr int digits = 0;
3530 static constexpr int digits10 = 0;
3531 static constexpr int max_digits10 = 0;
3532 static constexpr bool is_signed = false;
3533 static constexpr bool is_integer = false;
3534 static constexpr bool is_exact = false;
3535 static constexpr int radix = 0;
3536 static number_type epsilon() { return number_type(); }
3537 static number_type round_error() { return number_type(); }
3538 static constexpr int min_exponent = 0;
3539 static constexpr int min_exponent10 = 0;
3540 static constexpr int max_exponent = 0;
3541 static constexpr int max_exponent10 = 0;
3542 static constexpr bool has_infinity = false;
3543 static constexpr bool has_quiet_NaN = false;
3544 static constexpr bool has_signaling_NaN = false;
3545 static constexpr float_denorm_style has_denorm = denorm_absent;
3546 static constexpr bool has_denorm_loss = false;
3547 static number_type infinity() { return number_type(); }
3548 static number_type quiet_NaN() { return number_type(); }
3549 static number_type signaling_NaN() { return number_type(); }
3550 static number_type denorm_min() { return number_type(); }
3551 static constexpr bool is_iec559 = false;
3552 static constexpr bool is_bounded = false;
3553 static constexpr bool is_modulo = false;
3554 static constexpr bool traps = false;
3555 static constexpr bool tinyness_before = false;
3556 static constexpr float_round_style round_style = round_indeterminate;
3557 };
3558
3559 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3560 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::digits;
3561 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3562 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::digits10;
3563 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3564 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_digits10;
3565 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3566 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_signed;
3567 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3568 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_integer;
3569 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3570 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_exact;
3571 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3572 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::radix;
3573 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3574 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::min_exponent;
3575 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3576 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::min_exponent10;
3577 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3578 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_exponent;
3579 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3580 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_exponent10;
3581 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3582 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_infinity;
3583 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3584 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_quiet_NaN;
3585 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3586 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_signaling_NaN;
3587 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3588 constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_denorm;
3589 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3590 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_denorm_loss;
3591 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3592 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_iec559;
3593 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3594 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_bounded;
3595 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3596 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_modulo;
3597 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3598 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::traps;
3599 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3600 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::tinyness_before;
3601 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3602 constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::round_style;
3603
3604 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3605 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >
3606 {
3607 using number_type = boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates>;
3608
3609 public:
3610 static constexpr bool is_specialized = true;
3611 //
3612 // Largest and smallest numbers are bounded only by available memory, set
3613 // to zero:
3614 //
3615 static number_type(min)()
3616 {
3617 return number_type();
3618 }
3619 static number_type(max)()
3620 {
3621 return number_type();
3622 }
3623 static number_type lowest() { return (min)(); }
3624 static constexpr int digits = INT_MAX;
3625 static constexpr int digits10 = (INT_MAX / 1000) * 301L;
3626 static constexpr int max_digits10 = digits10 + 3;
3627 static constexpr bool is_signed = true;
3628 static constexpr bool is_integer = true;
3629 static constexpr bool is_exact = true;
3630 static constexpr int radix = 2;
3631 static number_type epsilon() { return number_type(); }
3632 static number_type round_error() { return number_type(); }
3633 static constexpr int min_exponent = 0;
3634 static constexpr int min_exponent10 = 0;
3635 static constexpr int max_exponent = 0;
3636 static constexpr int max_exponent10 = 0;
3637 static constexpr bool has_infinity = false;
3638 static constexpr bool has_quiet_NaN = false;
3639 static constexpr bool has_signaling_NaN = false;
3640 static constexpr float_denorm_style has_denorm = denorm_absent;
3641 static constexpr bool has_denorm_loss = false;
3642 static number_type infinity() { return number_type(); }
3643 static number_type quiet_NaN() { return number_type(); }
3644 static number_type signaling_NaN() { return number_type(); }
3645 static number_type denorm_min() { return number_type(); }
3646 static constexpr bool is_iec559 = false;
3647 static constexpr bool is_bounded = false;
3648 static constexpr bool is_modulo = false;
3649 static constexpr bool traps = false;
3650 static constexpr bool tinyness_before = false;
3651 static constexpr float_round_style round_style = round_toward_zero;
3652 };
3653
3654 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3655 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::digits;
3656 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3657 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::digits10;
3658 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3659 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_digits10;
3660 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3661 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_signed;
3662 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3663 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_integer;
3664 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3665 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_exact;
3666 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3667 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::radix;
3668 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3669 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::min_exponent;
3670 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3671 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::min_exponent10;
3672 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3673 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_exponent;
3674 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3675 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_exponent10;
3676 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3677 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_infinity;
3678 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3679 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_quiet_NaN;
3680 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3681 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_signaling_NaN;
3682 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3683 constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_denorm;
3684 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3685 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_denorm_loss;
3686 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3687 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_iec559;
3688 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3689 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_bounded;
3690 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3691 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_modulo;
3692 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3693 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::traps;
3694 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3695 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::tinyness_before;
3696 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3697 constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::round_style;
3698
3699 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3700 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >
3701 {
3702 using number_type = boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates>;
3703
3704 public:
3705 static constexpr bool is_specialized = true;
3706 //
3707 // Largest and smallest numbers are bounded only by available memory, set
3708 // to zero:
3709 //
3710 static number_type(min)()
3711 {
3712 return number_type();
3713 }
3714 static number_type(max)()
3715 {
3716 return number_type();
3717 }
3718 static number_type lowest() { return (min)(); }
3719 // Digits are unbounded, use zero for now:
3720 static constexpr int digits = INT_MAX;
3721 static constexpr int digits10 = (INT_MAX / 1000) * 301L;
3722 static constexpr int max_digits10 = digits10 + 3;
3723 static constexpr bool is_signed = true;
3724 static constexpr bool is_integer = false;
3725 static constexpr bool is_exact = true;
3726 static constexpr int radix = 2;
3727 static number_type epsilon() { return number_type(); }
3728 static number_type round_error() { return number_type(); }
3729 static constexpr int min_exponent = 0;
3730 static constexpr int min_exponent10 = 0;
3731 static constexpr int max_exponent = 0;
3732 static constexpr int max_exponent10 = 0;
3733 static constexpr bool has_infinity = false;
3734 static constexpr bool has_quiet_NaN = false;
3735 static constexpr bool has_signaling_NaN = false;
3736 static constexpr float_denorm_style has_denorm = denorm_absent;
3737 static constexpr bool has_denorm_loss = false;
3738 static number_type infinity() { return number_type(); }
3739 static number_type quiet_NaN() { return number_type(); }
3740 static number_type signaling_NaN() { return number_type(); }
3741 static number_type denorm_min() { return number_type(); }
3742 static constexpr bool is_iec559 = false;
3743 static constexpr bool is_bounded = false;
3744 static constexpr bool is_modulo = false;
3745 static constexpr bool traps = false;
3746 static constexpr bool tinyness_before = false;
3747 static constexpr float_round_style round_style = round_toward_zero;
3748 };
3749
3750 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3751 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::digits;
3752 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3753 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::digits10;
3754 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3755 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_digits10;
3756 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3757 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_signed;
3758 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3759 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_integer;
3760 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3761 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_exact;
3762 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3763 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::radix;
3764 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3765 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::min_exponent;
3766 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3767 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::min_exponent10;
3768 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3769 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_exponent;
3770 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3771 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_exponent10;
3772 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3773 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_infinity;
3774 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3775 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_quiet_NaN;
3776 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3777 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_signaling_NaN;
3778 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3779 constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_denorm;
3780 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3781 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_denorm_loss;
3782 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3783 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_iec559;
3784 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3785 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_bounded;
3786 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3787 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_modulo;
3788 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3789 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::traps;
3790 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3791 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::tinyness_before;
3792 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3793 constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::round_style;
3794
3795 #ifdef BOOST_MSVC
3796 #pragma warning(pop)
3797 #endif
3798
3799 } // namespace std
3800
3801 namespace Eigen
3802 {
3803
3804 template <class B1, class B2>
3805 struct NumTraitsImp;
3806
3807 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3808 struct NumTraitsImp<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates>, boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >
3809 {
3810 using self_type = boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates>;
3811 using Real = typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type;
3812 using NonInteger = self_type; // Not correct but we can't do much better??
3813 using Literal = double;
3814 using Nested = self_type;
3815 enum
3816 {
3817 IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex,
3818 IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer,
3819 ReadCost = 1,
3820 AddCost = 4,
3821 MulCost = 8,
3822 IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true,
3823 RequireInitialization = 1,
3824 };
3825
3826 static Real highest() noexcept
3827 {
3828 return boost::math::tools::max_value<Real>();
3829 }
3830 static Real lowest() noexcept
3831 {
3832 return boost::math::tools::min_value<Real>();
3833 }
3834 static int digits() noexcept
3835 {
3836 return boost::math::tools::digits<Real>();
3837 }
3838 static int digits10()
3839 {
3840 return Real::thread_default_precision();
3841 }
3842 static Real epsilon()
3843 {
3844 return ldexp(Real(1), 1 - digits());
3845 }
3846 static Real dummy_precision()
3847 {
3848 return 1000 * epsilon();
3849 }
3850 static constexpr long min_exponent() noexcept
3851 {
3852 return LONG_MIN;
3853 }
3854 static constexpr long max_exponent() noexcept
3855 {
3856 return LONG_MAX;
3857 }
3858 static Real infinity()
3859 {
3860 return Real();
3861 }
3862 static Real quiet_NaN()
3863 {
3864 return Real();
3865 }
3866 };
3867
3868 }
3869
3870
3871 #endif