Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / multiprecision / gmp.hpp
1 ///////////////////////////////////////////////////////////////////////////////
2 //  Copyright 2011 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #ifndef BOOST_MATH_ER_GMP_BACKEND_HPP
7 #define BOOST_MATH_ER_GMP_BACKEND_HPP
8
9 #include <boost/multiprecision/number.hpp>
10 #include <boost/multiprecision/debug_adaptor.hpp>
11 #include <boost/multiprecision/detail/integer_ops.hpp>
12 #include <boost/multiprecision/detail/big_lanczos.hpp>
13 #include <boost/multiprecision/detail/digits.hpp>
14 #include <boost/math/special_functions/fpclassify.hpp>
15 #include <boost/cstdint.hpp>
16 #include <boost/functional/hash_fwd.hpp>
17 //
18 // Some includes we need from Boost.Math, since we rely on that library to provide these functions:
19 //
20 #include <boost/math/special_functions/asinh.hpp>
21 #include <boost/math/special_functions/acosh.hpp>
22 #include <boost/math/special_functions/atanh.hpp>
23 #include <boost/math/special_functions/cbrt.hpp>
24 #include <boost/math/special_functions/expm1.hpp>
25 #include <boost/math/special_functions/gamma.hpp>
26
27 #ifdef BOOST_MSVC
28 #pragma warning(push)
29 #pragma warning(disable : 4127)
30 #endif
31 #include <gmp.h>
32 #ifdef BOOST_MSVC
33 #pragma warning(pop)
34 #endif
35
36 #if defined(__MPIR_VERSION) && defined(__MPIR_VERSION_MINOR) && defined(__MPIR_VERSION_PATCHLEVEL)
37 #define BOOST_MP_MPIR_VERSION (__MPIR_VERSION * 10000 + __MPIR_VERSION_MINOR * 100 + __MPIR_VERSION_PATCHLEVEL)
38 #else
39 #define BOOST_MP_MPIR_VERSION 0
40 #endif
41
42 #include <cctype>
43 #include <cmath>
44 #include <limits>
45 #include <climits>
46
47 namespace boost {
48 namespace multiprecision {
49 namespace backends {
50
51 #ifdef BOOST_MSVC
52 // warning C4127: conditional expression is constant
53 #pragma warning(push)
54 #pragma warning(disable : 4127)
55 #endif
56
57 template <unsigned digits10>
58 struct gmp_float;
59 struct gmp_int;
60 struct gmp_rational;
61
62 } // namespace backends
63
64 template <>
65 struct number_category<backends::gmp_int> : public mpl::int_<number_kind_integer>
66 {};
67 template <>
68 struct number_category<backends::gmp_rational> : public mpl::int_<number_kind_rational>
69 {};
70 template <unsigned digits10>
71 struct number_category<backends::gmp_float<digits10> > : public mpl::int_<number_kind_floating_point>
72 {};
73
74 namespace backends {
75 //
76 // Within this file, the only functions we mark as noexcept are those that manipulate
77 // (but don't create) an mpf_t.  All other types may allocate at pretty much any time
78 // via a user-supplied allocator, and therefore throw.
79 //
80 namespace detail {
81
82 template <unsigned digits10>
83 struct gmp_float_imp
84 {
85 #ifdef BOOST_HAS_LONG_LONG
86    typedef mpl::list<long, boost::long_long_type>           signed_types;
87    typedef mpl::list<unsigned long, boost::ulong_long_type> unsigned_types;
88 #else
89    typedef mpl::list<long>          signed_types;
90    typedef mpl::list<unsigned long> unsigned_types;
91 #endif
92    typedef mpl::list<double, long double> float_types;
93    typedef long                           exponent_type;
94
95    gmp_float_imp() BOOST_NOEXCEPT
96    {
97       m_data[0]._mp_d = 0; // uninitialized m_data
98    }
99
100    gmp_float_imp(const gmp_float_imp& o)
101    {
102       //
103       // We have to do an init followed by a set here, otherwise *this may be at
104       // a lower precision than o: seems like mpf_init_set copies just enough bits
105       // to get the right value, but if it's then used in further calculations
106       // things go badly wrong!!
107       //
108       mpf_init2(m_data, mpf_get_prec(o.data()));
109       if (o.m_data[0]._mp_d)
110          mpf_set(m_data, o.m_data);
111    }
112 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
113    gmp_float_imp(gmp_float_imp&& o) BOOST_NOEXCEPT
114    {
115       m_data[0]         = o.m_data[0];
116       o.m_data[0]._mp_d = 0;
117    }
118 #endif
119    gmp_float_imp& operator=(const gmp_float_imp& o)
120    {
121       if (m_data[0]._mp_d == 0)
122          mpf_init2(m_data, mpf_get_prec(o.data()));
123       if (mpf_get_prec(data()) != mpf_get_prec(o.data()))
124       {
125          mpf_t t;
126          mpf_init2(t, mpf_get_prec(o.data()));
127          mpf_set(t, o.data());
128          mpf_swap(data(), t);
129          mpf_clear(t);
130       }
131       else
132       {
133          if (o.m_data[0]._mp_d)
134             mpf_set(m_data, o.m_data);
135       }
136       return *this;
137    }
138 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
139    gmp_float_imp& operator=(gmp_float_imp&& o) BOOST_NOEXCEPT
140    {
141       mpf_swap(m_data, o.m_data);
142       return *this;
143    }
144 #endif
145
146 #ifdef BOOST_HAS_LONG_LONG
147 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
148    gmp_float_imp& operator=(boost::ulong_long_type i)
149    {
150       *this = static_cast<unsigned long>(i);
151       return *this;
152    }
153 #else
154    gmp_float_imp& operator=(boost::ulong_long_type i)
155    {
156       if (m_data[0]._mp_d == 0)
157          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision()));
158       boost::ulong_long_type mask  = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
159       unsigned               shift = 0;
160       mpf_t                  t;
161       mpf_init2(t, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision()));
162       mpf_set_ui(m_data, 0);
163       while (i)
164       {
165          mpf_set_ui(t, static_cast<unsigned long>(i & mask));
166          if (shift)
167             mpf_mul_2exp(t, t, shift);
168          mpf_add(m_data, m_data, t);
169          shift += std::numeric_limits<unsigned long>::digits;
170          i >>= std::numeric_limits<unsigned long>::digits;
171       }
172       mpf_clear(t);
173       return *this;
174    }
175 #endif
176    gmp_float_imp& operator=(boost::long_long_type i)
177    {
178       if (m_data[0]._mp_d == 0)
179          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision()));
180       bool neg = i < 0;
181       *this    = static_cast<boost::ulong_long_type>(boost::multiprecision::detail::unsigned_abs(i));
182       if (neg)
183          mpf_neg(m_data, m_data);
184       return *this;
185    }
186 #endif
187    gmp_float_imp& operator=(unsigned long i)
188    {
189       if (m_data[0]._mp_d == 0)
190          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision()));
191       mpf_set_ui(m_data, i);
192       return *this;
193    }
194    gmp_float_imp& operator=(long i)
195    {
196       if (m_data[0]._mp_d == 0)
197          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision()));
198       mpf_set_si(m_data, i);
199       return *this;
200    }
201    gmp_float_imp& operator=(double d)
202    {
203       if (m_data[0]._mp_d == 0)
204          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision()));
205       mpf_set_d(m_data, d);
206       return *this;
207    }
208    gmp_float_imp& operator=(long double a)
209    {
210       using std::floor;
211       using std::frexp;
212       using std::ldexp;
213
214       if (m_data[0]._mp_d == 0)
215          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision()));
216
217       if (a == 0)
218       {
219          mpf_set_si(m_data, 0);
220          return *this;
221       }
222
223       if (a == 1)
224       {
225          mpf_set_si(m_data, 1);
226          return *this;
227       }
228
229       BOOST_ASSERT(!(boost::math::isinf)(a));
230       BOOST_ASSERT(!(boost::math::isnan)(a));
231
232       int         e;
233       long double f, term;
234       mpf_set_ui(m_data, 0u);
235
236       f = frexp(a, &e);
237
238       static const int shift = std::numeric_limits<int>::digits - 1;
239
240       while (f)
241       {
242          // extract int sized bits from f:
243          f    = ldexp(f, shift);
244          term = floor(f);
245          e -= shift;
246          mpf_mul_2exp(m_data, m_data, shift);
247          if (term > 0)
248             mpf_add_ui(m_data, m_data, static_cast<unsigned>(term));
249          else
250             mpf_sub_ui(m_data, m_data, static_cast<unsigned>(-term));
251          f -= term;
252       }
253       if (e > 0)
254          mpf_mul_2exp(m_data, m_data, e);
255       else if (e < 0)
256          mpf_div_2exp(m_data, m_data, -e);
257       return *this;
258    }
259    gmp_float_imp& operator=(const char* s)
260    {
261       if (m_data[0]._mp_d == 0)
262          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision()));
263       if (0 != mpf_set_str(m_data, s, 10))
264          BOOST_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid floating point number.")));
265       return *this;
266    }
267    void swap(gmp_float_imp& o) BOOST_NOEXCEPT
268    {
269       mpf_swap(m_data, o.m_data);
270    }
271    std::string str(std::streamsize digits, std::ios_base::fmtflags f) const
272    {
273       BOOST_ASSERT(m_data[0]._mp_d);
274
275       bool            scientific = (f & std::ios_base::scientific) == std::ios_base::scientific;
276       bool            fixed      = (f & std::ios_base::fixed) == std::ios_base::fixed;
277       std::streamsize org_digits(digits);
278
279       if (scientific && digits)
280          ++digits;
281
282       std::string result;
283       mp_exp_t    e;
284       void* (*alloc_func_ptr)(size_t);
285       void* (*realloc_func_ptr)(void*, size_t, size_t);
286       void (*free_func_ptr)(void*, size_t);
287       mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
288
289       if (mpf_sgn(m_data) == 0)
290       {
291          e      = 0;
292          result = "0";
293          if (fixed && digits)
294             ++digits;
295       }
296       else
297       {
298          char* ps = mpf_get_str(0, &e, 10, static_cast<std::size_t>(digits), m_data);
299          --e; // To match with what our formatter expects.
300          if (fixed && e != -1)
301          {
302             // Oops we actually need a different number of digits to what we asked for:
303             (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
304             digits += e + 1;
305             if (digits == 0)
306             {
307                // We need to get *all* the digits and then possibly round up,
308                // we end up with either "0" or "1" as the result.
309                ps = mpf_get_str(0, &e, 10, 0, m_data);
310                --e;
311                unsigned offset = *ps == '-' ? 1 : 0;
312                if (ps[offset] > '5')
313                {
314                   ++e;
315                   ps[offset]     = '1';
316                   ps[offset + 1] = 0;
317                }
318                else if (ps[offset] == '5')
319                {
320                   unsigned i        = offset + 1;
321                   bool     round_up = false;
322                   while (ps[i] != 0)
323                   {
324                      if (ps[i] != '0')
325                      {
326                         round_up = true;
327                         break;
328                      }
329                      ++i;
330                   }
331                   if (round_up)
332                   {
333                      ++e;
334                      ps[offset]     = '1';
335                      ps[offset + 1] = 0;
336                   }
337                   else
338                   {
339                      ps[offset]     = '0';
340                      ps[offset + 1] = 0;
341                   }
342                }
343                else
344                {
345                   ps[offset]     = '0';
346                   ps[offset + 1] = 0;
347                }
348             }
349             else if (digits > 0)
350             {
351                mp_exp_t old_e = e;
352                ps             = mpf_get_str(0, &e, 10, static_cast<std::size_t>(digits), m_data);
353                --e; // To match with what our formatter expects.
354                if (old_e > e)
355                {
356                   // in some cases, when we ask for more digits of precision, it will
357                   // change the number of digits to the left of the decimal, if that
358                   // happens, account for it here.
359                   // example: cout << fixed << setprecision(3) << mpf_float_50("99.9809")
360                   digits -= old_e - e;
361                   ps = mpf_get_str(0, &e, 10, static_cast<std::size_t>(digits), m_data);
362                   --e; // To match with what our formatter expects.
363                }
364             }
365             else
366             {
367                ps = mpf_get_str(0, &e, 10, 1, m_data);
368                --e;
369                unsigned offset = *ps == '-' ? 1 : 0;
370                ps[offset]      = '0';
371                ps[offset + 1]  = 0;
372             }
373          }
374          result = ps;
375          (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
376       }
377       boost::multiprecision::detail::format_float_string(result, e, org_digits, f, mpf_sgn(m_data) == 0);
378       return result;
379    }
380    ~gmp_float_imp() BOOST_NOEXCEPT
381    {
382       if (m_data[0]._mp_d)
383          mpf_clear(m_data);
384    }
385    void negate() BOOST_NOEXCEPT
386    {
387       BOOST_ASSERT(m_data[0]._mp_d);
388       mpf_neg(m_data, m_data);
389    }
390    int compare(const gmp_float<digits10>& o) const BOOST_NOEXCEPT
391    {
392       BOOST_ASSERT(m_data[0]._mp_d && o.m_data[0]._mp_d);
393       return mpf_cmp(m_data, o.m_data);
394    }
395    int compare(long i) const BOOST_NOEXCEPT
396    {
397       BOOST_ASSERT(m_data[0]._mp_d);
398       return mpf_cmp_si(m_data, i);
399    }
400    int compare(unsigned long i) const BOOST_NOEXCEPT
401    {
402       BOOST_ASSERT(m_data[0]._mp_d);
403       return mpf_cmp_ui(m_data, i);
404    }
405    template <class V>
406    typename enable_if<is_arithmetic<V>, int>::type compare(V v) const
407    {
408       gmp_float<digits10> d;
409       d = v;
410       return compare(d);
411    }
412    mpf_t& data() BOOST_NOEXCEPT
413    {
414       BOOST_ASSERT(m_data[0]._mp_d);
415       return m_data;
416    }
417    const mpf_t& data() const BOOST_NOEXCEPT
418    {
419       BOOST_ASSERT(m_data[0]._mp_d);
420       return m_data;
421    }
422
423  protected:
424    mpf_t            m_data;
425    static unsigned& get_default_precision() BOOST_NOEXCEPT
426    {
427       static unsigned val = 50;
428       return val;
429    }
430 };
431
432 } // namespace detail
433
434 struct gmp_int;
435 struct gmp_rational;
436
437 template <unsigned digits10>
438 struct gmp_float : public detail::gmp_float_imp<digits10>
439 {
440    gmp_float()
441    {
442       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
443    }
444    gmp_float(const gmp_float& o) : detail::gmp_float_imp<digits10>(o) {}
445    template <unsigned D>
446    gmp_float(const gmp_float<D>& o, typename enable_if_c<D <= digits10>::type* = 0);
447    template <unsigned D>
448    explicit gmp_float(const gmp_float<D>& o, typename disable_if_c<D <= digits10>::type* = 0);
449    gmp_float(const gmp_int& o);
450    gmp_float(const gmp_rational& o);
451    gmp_float(const mpf_t val)
452    {
453       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
454       mpf_set(this->m_data, val);
455    }
456    gmp_float(const mpz_t val)
457    {
458       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
459       mpf_set_z(this->m_data, val);
460    }
461    gmp_float(const mpq_t val)
462    {
463       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
464       mpf_set_q(this->m_data, val);
465    }
466 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
467    gmp_float(gmp_float&& o) BOOST_NOEXCEPT : detail::gmp_float_imp<digits10>(static_cast<detail::gmp_float_imp<digits10>&&>(o))
468    {}
469 #endif
470    gmp_float& operator=(const gmp_float& o)
471    {
472       *static_cast<detail::gmp_float_imp<digits10>*>(this) = static_cast<detail::gmp_float_imp<digits10> const&>(o);
473       return *this;
474    }
475 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
476    gmp_float& operator=(gmp_float&& o) BOOST_NOEXCEPT
477    {
478       *static_cast<detail::gmp_float_imp<digits10>*>(this) = static_cast<detail::gmp_float_imp<digits10>&&>(o);
479       return *this;
480    }
481 #endif
482    template <unsigned D>
483    gmp_float& operator=(const gmp_float<D>& o);
484    gmp_float& operator=(const gmp_int& o);
485    gmp_float& operator=(const gmp_rational& o);
486    gmp_float& operator=(const mpf_t val)
487    {
488       if (this->m_data[0]._mp_d == 0)
489          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
490       mpf_set(this->m_data, val);
491       return *this;
492    }
493    gmp_float& operator=(const mpz_t val)
494    {
495       if (this->m_data[0]._mp_d == 0)
496          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
497       mpf_set_z(this->m_data, val);
498       return *this;
499    }
500    gmp_float& operator=(const mpq_t val)
501    {
502       if (this->m_data[0]._mp_d == 0)
503          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
504       mpf_set_q(this->m_data, val);
505       return *this;
506    }
507    template <class V>
508    gmp_float& operator=(const V& v)
509    {
510       *static_cast<detail::gmp_float_imp<digits10>*>(this) = v;
511       return *this;
512    }
513 };
514
515 template <>
516 struct gmp_float<0> : public detail::gmp_float_imp<0>
517 {
518    gmp_float()
519    {
520       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision()));
521    }
522    gmp_float(const mpf_t val)
523    {
524       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision()));
525       mpf_set(this->m_data, val);
526    }
527    gmp_float(const mpz_t val)
528    {
529       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision()));
530       mpf_set_z(this->m_data, val);
531    }
532    gmp_float(const mpq_t val)
533    {
534       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision()));
535       mpf_set_q(this->m_data, val);
536    }
537    gmp_float(const gmp_float& o) : detail::gmp_float_imp<0>(o) {}
538    template <unsigned D>
539    gmp_float(const gmp_float<D>& o)
540    {
541       mpf_init2(this->m_data, mpf_get_prec(o.data()));
542       mpf_set(this->m_data, o.data());
543    }
544 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
545    gmp_float(gmp_float&& o) BOOST_NOEXCEPT : detail::gmp_float_imp<0>(static_cast<detail::gmp_float_imp<0>&&>(o))
546    {}
547 #endif
548    gmp_float(const gmp_int& o);
549    gmp_float(const gmp_rational& o);
550    gmp_float(const gmp_float& o, unsigned digits10)
551    {
552       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
553       mpf_set(this->m_data, o.data());
554    }
555    template <class V>
556    gmp_float(const V& o, unsigned digits10)
557    {
558       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
559       *this = o;
560    }
561
562 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
563    //
564    // Support for new types in C++17
565    //
566    template <class Traits>
567    gmp_float(const std::basic_string_view<char, Traits>& o, unsigned digits10)
568    {
569       using default_ops::assign_from_string_view;
570       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
571       assign_from_string_view(*this, o);
572    }
573 #endif
574    gmp_float& operator=(const gmp_float& o)
575    {
576       *static_cast<detail::gmp_float_imp<0>*>(this) = static_cast<detail::gmp_float_imp<0> const&>(o);
577       return *this;
578    }
579 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
580    gmp_float& operator=(gmp_float&& o) BOOST_NOEXCEPT
581    {
582       *static_cast<detail::gmp_float_imp<0>*>(this) = static_cast<detail::gmp_float_imp<0>&&>(o);
583       return *this;
584    }
585 #endif
586    template <unsigned D>
587    gmp_float& operator=(const gmp_float<D>& o)
588    {
589       if (this->m_data[0]._mp_d == 0)
590       {
591          mpf_init2(this->m_data, mpf_get_prec(o.data()));
592       }
593       else
594       {
595          mpf_set_prec(this->m_data, mpf_get_prec(o.data()));
596       }
597       mpf_set(this->m_data, o.data());
598       return *this;
599    }
600    gmp_float& operator=(const gmp_int& o);
601    gmp_float& operator=(const gmp_rational& o);
602    gmp_float& operator=(const mpf_t val)
603    {
604       if (this->m_data[0]._mp_d == 0)
605          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision()));
606       mpf_set(this->m_data, val);
607       return *this;
608    }
609    gmp_float& operator=(const mpz_t val)
610    {
611       if (this->m_data[0]._mp_d == 0)
612          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision()));
613       mpf_set_z(this->m_data, val);
614       return *this;
615    }
616    gmp_float& operator=(const mpq_t val)
617    {
618       if (this->m_data[0]._mp_d == 0)
619          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision()));
620       mpf_set_q(this->m_data, val);
621       return *this;
622    }
623    template <class V>
624    gmp_float& operator=(const V& v)
625    {
626       *static_cast<detail::gmp_float_imp<0>*>(this) = v;
627       return *this;
628    }
629    static unsigned default_precision() BOOST_NOEXCEPT
630    {
631       return get_default_precision();
632    }
633    static void default_precision(unsigned v) BOOST_NOEXCEPT
634    {
635       get_default_precision() = v;
636    }
637    unsigned precision() const BOOST_NOEXCEPT
638    {
639       return static_cast<unsigned>(multiprecision::detail::digits2_2_10(static_cast<unsigned long>(mpf_get_prec(this->m_data))));
640    }
641    void precision(unsigned digits10) BOOST_NOEXCEPT
642    {
643       mpf_set_prec(this->m_data, multiprecision::detail::digits10_2_2(digits10));
644    }
645 };
646
647 template <unsigned digits10, class T>
648 inline typename enable_if_c<is_arithmetic<T>::value, bool>::type eval_eq(const gmp_float<digits10>& a, const T& b) BOOST_NOEXCEPT
649 {
650    return a.compare(b) == 0;
651 }
652 template <unsigned digits10, class T>
653 inline typename enable_if_c<is_arithmetic<T>::value, bool>::type eval_lt(const gmp_float<digits10>& a, const T& b) BOOST_NOEXCEPT
654 {
655    return a.compare(b) < 0;
656 }
657 template <unsigned digits10, class T>
658 inline typename enable_if_c<is_arithmetic<T>::value, bool>::type eval_gt(const gmp_float<digits10>& a, const T& b) BOOST_NOEXCEPT
659 {
660    return a.compare(b) > 0;
661 }
662
663 template <unsigned D1, unsigned D2>
664 inline void eval_add(gmp_float<D1>& result, const gmp_float<D2>& o)
665 {
666    mpf_add(result.data(), result.data(), o.data());
667 }
668 template <unsigned D1, unsigned D2>
669 inline void eval_subtract(gmp_float<D1>& result, const gmp_float<D2>& o)
670 {
671    mpf_sub(result.data(), result.data(), o.data());
672 }
673 template <unsigned D1, unsigned D2>
674 inline void eval_multiply(gmp_float<D1>& result, const gmp_float<D2>& o)
675 {
676    mpf_mul(result.data(), result.data(), o.data());
677 }
678 template <unsigned digits10>
679 inline bool eval_is_zero(const gmp_float<digits10>& val) BOOST_NOEXCEPT
680 {
681    return mpf_sgn(val.data()) == 0;
682 }
683 template <unsigned D1, unsigned D2>
684 inline void eval_divide(gmp_float<D1>& result, const gmp_float<D2>& o)
685 {
686    if (eval_is_zero(o))
687       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
688    mpf_div(result.data(), result.data(), o.data());
689 }
690 template <unsigned digits10>
691 inline void eval_add(gmp_float<digits10>& result, unsigned long i)
692 {
693    mpf_add_ui(result.data(), result.data(), i);
694 }
695 template <unsigned digits10>
696 inline void eval_subtract(gmp_float<digits10>& result, unsigned long i)
697 {
698    mpf_sub_ui(result.data(), result.data(), i);
699 }
700 template <unsigned digits10>
701 inline void eval_multiply(gmp_float<digits10>& result, unsigned long i)
702 {
703    mpf_mul_ui(result.data(), result.data(), i);
704 }
705 template <unsigned digits10>
706 inline void eval_divide(gmp_float<digits10>& result, unsigned long i)
707 {
708    if (i == 0)
709       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
710    mpf_div_ui(result.data(), result.data(), i);
711 }
712 template <unsigned digits10>
713 inline void eval_add(gmp_float<digits10>& result, long i)
714 {
715    if (i > 0)
716       mpf_add_ui(result.data(), result.data(), i);
717    else
718       mpf_sub_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
719 }
720 template <unsigned digits10>
721 inline void eval_subtract(gmp_float<digits10>& result, long i)
722 {
723    if (i > 0)
724       mpf_sub_ui(result.data(), result.data(), i);
725    else
726       mpf_add_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
727 }
728 template <unsigned digits10>
729 inline void eval_multiply(gmp_float<digits10>& result, long i)
730 {
731    mpf_mul_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
732    if (i < 0)
733       mpf_neg(result.data(), result.data());
734 }
735 template <unsigned digits10>
736 inline void eval_divide(gmp_float<digits10>& result, long i)
737 {
738    if (i == 0)
739       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
740    mpf_div_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
741    if (i < 0)
742       mpf_neg(result.data(), result.data());
743 }
744 //
745 // Specialised 3 arg versions of the basic operators:
746 //
747 template <unsigned D1, unsigned D2, unsigned D3>
748 inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
749 {
750    mpf_add(a.data(), x.data(), y.data());
751 }
752 template <unsigned D1, unsigned D2>
753 inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
754 {
755    mpf_add_ui(a.data(), x.data(), y);
756 }
757 template <unsigned D1, unsigned D2>
758 inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
759 {
760    if (y < 0)
761       mpf_sub_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
762    else
763       mpf_add_ui(a.data(), x.data(), y);
764 }
765 template <unsigned D1, unsigned D2>
766 inline void eval_add(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
767 {
768    mpf_add_ui(a.data(), y.data(), x);
769 }
770 template <unsigned D1, unsigned D2>
771 inline void eval_add(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
772 {
773    if (x < 0)
774    {
775       mpf_ui_sub(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data());
776       mpf_neg(a.data(), a.data());
777    }
778    else
779       mpf_add_ui(a.data(), y.data(), x);
780 }
781 template <unsigned D1, unsigned D2, unsigned D3>
782 inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
783 {
784    mpf_sub(a.data(), x.data(), y.data());
785 }
786 template <unsigned D1, unsigned D2>
787 inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
788 {
789    mpf_sub_ui(a.data(), x.data(), y);
790 }
791 template <unsigned D1, unsigned D2>
792 inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
793 {
794    if (y < 0)
795       mpf_add_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
796    else
797       mpf_sub_ui(a.data(), x.data(), y);
798 }
799 template <unsigned D1, unsigned D2>
800 inline void eval_subtract(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
801 {
802    mpf_ui_sub(a.data(), x, y.data());
803 }
804 template <unsigned D1, unsigned D2>
805 inline void eval_subtract(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
806 {
807    if (x < 0)
808    {
809       mpf_add_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x));
810       mpf_neg(a.data(), a.data());
811    }
812    else
813       mpf_ui_sub(a.data(), x, y.data());
814 }
815
816 template <unsigned D1, unsigned D2, unsigned D3>
817 inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
818 {
819    mpf_mul(a.data(), x.data(), y.data());
820 }
821 template <unsigned D1, unsigned D2>
822 inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
823 {
824    mpf_mul_ui(a.data(), x.data(), y);
825 }
826 template <unsigned D1, unsigned D2>
827 inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
828 {
829    if (y < 0)
830    {
831       mpf_mul_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
832       a.negate();
833    }
834    else
835       mpf_mul_ui(a.data(), x.data(), y);
836 }
837 template <unsigned D1, unsigned D2>
838 inline void eval_multiply(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
839 {
840    mpf_mul_ui(a.data(), y.data(), x);
841 }
842 template <unsigned D1, unsigned D2>
843 inline void eval_multiply(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
844 {
845    if (x < 0)
846    {
847       mpf_mul_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x));
848       mpf_neg(a.data(), a.data());
849    }
850    else
851       mpf_mul_ui(a.data(), y.data(), x);
852 }
853
854 template <unsigned D1, unsigned D2, unsigned D3>
855 inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
856 {
857    if (eval_is_zero(y))
858       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
859    mpf_div(a.data(), x.data(), y.data());
860 }
861 template <unsigned D1, unsigned D2>
862 inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
863 {
864    if (y == 0)
865       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
866    mpf_div_ui(a.data(), x.data(), y);
867 }
868 template <unsigned D1, unsigned D2>
869 inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
870 {
871    if (y == 0)
872       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
873    if (y < 0)
874    {
875       mpf_div_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
876       a.negate();
877    }
878    else
879       mpf_div_ui(a.data(), x.data(), y);
880 }
881 template <unsigned D1, unsigned D2>
882 inline void eval_divide(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
883 {
884    if (eval_is_zero(y))
885       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
886    mpf_ui_div(a.data(), x, y.data());
887 }
888 template <unsigned D1, unsigned D2>
889 inline void eval_divide(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
890 {
891    if (eval_is_zero(y))
892       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
893    if (x < 0)
894    {
895       mpf_ui_div(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data());
896       mpf_neg(a.data(), a.data());
897    }
898    else
899       mpf_ui_div(a.data(), x, y.data());
900 }
901
902 template <unsigned digits10>
903 inline int eval_get_sign(const gmp_float<digits10>& val) BOOST_NOEXCEPT
904 {
905    return mpf_sgn(val.data());
906 }
907
908 template <unsigned digits10>
909 inline void eval_convert_to(unsigned long* result, const gmp_float<digits10>& val) BOOST_NOEXCEPT
910 {
911    if (0 == mpf_fits_ulong_p(val.data()))
912       *result = (std::numeric_limits<unsigned long>::max)();
913    else
914       *result = (unsigned long)mpf_get_ui(val.data());
915 }
916 template <unsigned digits10>
917 inline void eval_convert_to(long* result, const gmp_float<digits10>& val) BOOST_NOEXCEPT
918 {
919    if (0 == mpf_fits_slong_p(val.data()))
920    {
921       *result = (std::numeric_limits<long>::max)();
922       *result *= mpf_sgn(val.data());
923    }
924    else
925       *result = (long)mpf_get_si(val.data());
926 }
927 template <unsigned digits10>
928 inline void eval_convert_to(double* result, const gmp_float<digits10>& val) BOOST_NOEXCEPT
929 {
930    *result = mpf_get_d(val.data());
931 }
932 #ifdef BOOST_HAS_LONG_LONG
933 template <unsigned digits10>
934 inline void eval_convert_to(boost::long_long_type* result, const gmp_float<digits10>& val)
935 {
936    gmp_float<digits10> t(val);
937    if (eval_get_sign(t) < 0)
938       t.negate();
939
940    long digits = std::numeric_limits<boost::long_long_type>::digits - std::numeric_limits<long>::digits;
941
942    if (digits > 0)
943       mpf_div_2exp(t.data(), t.data(), digits);
944
945    if (!mpf_fits_slong_p(t.data()))
946    {
947       if (eval_get_sign(val) < 0)
948          *result = (std::numeric_limits<boost::long_long_type>::min)();
949       else
950          *result = (std::numeric_limits<boost::long_long_type>::max)();
951       return;
952    };
953
954    *result = mpf_get_si(t.data());
955    while (digits > 0)
956    {
957       *result <<= digits;
958       digits -= std::numeric_limits<unsigned long>::digits;
959       mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits<unsigned long>::digits : std::numeric_limits<unsigned long>::digits + digits);
960       unsigned long l = (unsigned long)mpf_get_ui(t.data());
961       if (digits < 0)
962          l >>= -digits;
963       *result |= l;
964    }
965    if (eval_get_sign(val) < 0)
966       *result = -*result;
967 }
968 template <unsigned digits10>
969 inline void eval_convert_to(boost::ulong_long_type* result, const gmp_float<digits10>& val)
970 {
971    gmp_float<digits10> t(val);
972
973    long digits = std::numeric_limits<boost::long_long_type>::digits - std::numeric_limits<long>::digits;
974
975    if (digits > 0)
976       mpf_div_2exp(t.data(), t.data(), digits);
977
978    if (!mpf_fits_ulong_p(t.data()))
979    {
980       *result = (std::numeric_limits<boost::long_long_type>::max)();
981       return;
982    }
983
984    *result = mpf_get_ui(t.data());
985    while (digits > 0)
986    {
987       *result <<= digits;
988       digits -= std::numeric_limits<unsigned long>::digits;
989       mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits<unsigned long>::digits : std::numeric_limits<unsigned long>::digits + digits);
990       unsigned long l = (unsigned long)mpf_get_ui(t.data());
991       if (digits < 0)
992          l >>= -digits;
993       *result |= l;
994    }
995 }
996 #endif
997
998 //
999 // Native non-member operations:
1000 //
1001 template <unsigned Digits10>
1002 inline void eval_sqrt(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1003 {
1004    mpf_sqrt(result.data(), val.data());
1005 }
1006
1007 template <unsigned Digits10>
1008 inline void eval_abs(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1009 {
1010    mpf_abs(result.data(), val.data());
1011 }
1012
1013 template <unsigned Digits10>
1014 inline void eval_fabs(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1015 {
1016    mpf_abs(result.data(), val.data());
1017 }
1018 template <unsigned Digits10>
1019 inline void eval_ceil(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1020 {
1021    mpf_ceil(result.data(), val.data());
1022 }
1023 template <unsigned Digits10>
1024 inline void eval_floor(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1025 {
1026    mpf_floor(result.data(), val.data());
1027 }
1028 template <unsigned Digits10>
1029 inline void eval_trunc(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1030 {
1031    mpf_trunc(result.data(), val.data());
1032 }
1033 template <unsigned Digits10>
1034 inline void eval_ldexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, long e)
1035 {
1036    if (e > 0)
1037       mpf_mul_2exp(result.data(), val.data(), e);
1038    else if (e < 0)
1039       mpf_div_2exp(result.data(), val.data(), -e);
1040    else
1041       result = val;
1042 }
1043 template <unsigned Digits10>
1044 inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, int* e)
1045 {
1046 #if (BOOST_MP_MPIR_VERSION >= 20600) && (BOOST_MP_MPIR_VERSION < 30000)
1047    mpir_si v;
1048    mpf_get_d_2exp(&v, val.data());
1049 #else
1050    long                             v;
1051    mpf_get_d_2exp(&v, val.data());
1052 #endif
1053    *e = v;
1054    eval_ldexp(result, val, -v);
1055 }
1056 template <unsigned Digits10>
1057 inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, long* e)
1058 {
1059 #if (BOOST_MP_MPIR_VERSION >= 20600) && (BOOST_MP_MPIR_VERSION < 30000)
1060    mpir_si v;
1061    mpf_get_d_2exp(&v, val.data());
1062    *e = v;
1063    eval_ldexp(result, val, -v);
1064 #else
1065    mpf_get_d_2exp(e, val.data());
1066    eval_ldexp(result, val, -*e);
1067 #endif
1068 }
1069
1070 template <unsigned Digits10>
1071 inline std::size_t hash_value(const gmp_float<Digits10>& val)
1072 {
1073    std::size_t result = 0;
1074    for (int i = 0; i < std::abs(val.data()[0]._mp_size); ++i)
1075       boost::hash_combine(result, val.data()[0]._mp_d[i]);
1076    boost::hash_combine(result, val.data()[0]._mp_exp);
1077    boost::hash_combine(result, val.data()[0]._mp_size);
1078    return result;
1079 }
1080
1081 struct gmp_int
1082 {
1083 #ifdef BOOST_HAS_LONG_LONG
1084    typedef mpl::list<long, boost::long_long_type>           signed_types;
1085    typedef mpl::list<unsigned long, boost::ulong_long_type> unsigned_types;
1086 #else
1087    typedef mpl::list<long>          signed_types;
1088    typedef mpl::list<unsigned long> unsigned_types;
1089 #endif
1090    typedef mpl::list<double, long double> float_types;
1091
1092    gmp_int()
1093    {
1094       mpz_init(this->m_data);
1095    }
1096    gmp_int(const gmp_int& o)
1097    {
1098       if (o.m_data[0]._mp_d)
1099          mpz_init_set(m_data, o.m_data);
1100       else
1101          mpz_init(this->m_data);
1102    }
1103 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
1104    gmp_int(gmp_int&& o) BOOST_NOEXCEPT
1105    {
1106       m_data[0]         = o.m_data[0];
1107       o.m_data[0]._mp_d = 0;
1108    }
1109 #endif
1110    explicit gmp_int(const mpf_t val)
1111    {
1112       mpz_init(this->m_data);
1113       mpz_set_f(this->m_data, val);
1114    }
1115    gmp_int(const mpz_t val)
1116    {
1117       mpz_init_set(this->m_data, val);
1118    }
1119    explicit gmp_int(const mpq_t val)
1120    {
1121       mpz_init(this->m_data);
1122       mpz_set_q(this->m_data, val);
1123    }
1124    template <unsigned Digits10>
1125    explicit gmp_int(const gmp_float<Digits10>& o)
1126    {
1127       mpz_init(this->m_data);
1128       mpz_set_f(this->m_data, o.data());
1129    }
1130    explicit gmp_int(const gmp_rational& o);
1131    gmp_int& operator=(const gmp_int& o)
1132    {
1133       if (m_data[0]._mp_d == 0)
1134          mpz_init(this->m_data);
1135       mpz_set(m_data, o.m_data);
1136       return *this;
1137    }
1138 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
1139    gmp_int& operator=(gmp_int&& o) BOOST_NOEXCEPT
1140    {
1141       mpz_swap(m_data, o.m_data);
1142       return *this;
1143    }
1144 #endif
1145 #ifdef BOOST_HAS_LONG_LONG
1146 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
1147    gmp_int& operator=(boost::ulong_long_type i)
1148    {
1149       *this = static_cast<unsigned long>(i);
1150       return *this;
1151    }
1152 #else
1153    gmp_int& operator=(boost::ulong_long_type i)
1154    {
1155       if (m_data[0]._mp_d == 0)
1156          mpz_init(this->m_data);
1157       boost::ulong_long_type mask  = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
1158       unsigned               shift = 0;
1159       mpz_t                  t;
1160       mpz_set_ui(m_data, 0);
1161       mpz_init_set_ui(t, 0);
1162       while (i)
1163       {
1164          mpz_set_ui(t, static_cast<unsigned long>(i & mask));
1165          if (shift)
1166             mpz_mul_2exp(t, t, shift);
1167          mpz_add(m_data, m_data, t);
1168          shift += std::numeric_limits<unsigned long>::digits;
1169          i >>= std::numeric_limits<unsigned long>::digits;
1170       }
1171       mpz_clear(t);
1172       return *this;
1173    }
1174 #endif
1175    gmp_int& operator=(boost::long_long_type i)
1176    {
1177       if (m_data[0]._mp_d == 0)
1178          mpz_init(this->m_data);
1179       bool neg = i < 0;
1180       *this    = boost::multiprecision::detail::unsigned_abs(i);
1181       if (neg)
1182          mpz_neg(m_data, m_data);
1183       return *this;
1184    }
1185 #endif
1186    gmp_int& operator=(unsigned long i)
1187    {
1188       if (m_data[0]._mp_d == 0)
1189          mpz_init(this->m_data);
1190       mpz_set_ui(m_data, i);
1191       return *this;
1192    }
1193    gmp_int& operator=(long i)
1194    {
1195       if (m_data[0]._mp_d == 0)
1196          mpz_init(this->m_data);
1197       mpz_set_si(m_data, i);
1198       return *this;
1199    }
1200    gmp_int& operator=(double d)
1201    {
1202       if (m_data[0]._mp_d == 0)
1203          mpz_init(this->m_data);
1204       mpz_set_d(m_data, d);
1205       return *this;
1206    }
1207    gmp_int& operator=(long double a)
1208    {
1209       using std::floor;
1210       using std::frexp;
1211       using std::ldexp;
1212
1213       if (m_data[0]._mp_d == 0)
1214          mpz_init(this->m_data);
1215
1216       if (a == 0)
1217       {
1218          mpz_set_si(m_data, 0);
1219          return *this;
1220       }
1221
1222       if (a == 1)
1223       {
1224          mpz_set_si(m_data, 1);
1225          return *this;
1226       }
1227
1228       BOOST_ASSERT(!(boost::math::isinf)(a));
1229       BOOST_ASSERT(!(boost::math::isnan)(a));
1230
1231       int         e;
1232       long double f, term;
1233       mpz_set_ui(m_data, 0u);
1234
1235       f = frexp(a, &e);
1236
1237       static const int shift = std::numeric_limits<int>::digits - 1;
1238
1239       while (f)
1240       {
1241          // extract int sized bits from f:
1242          f    = ldexp(f, shift);
1243          term = floor(f);
1244          e -= shift;
1245          mpz_mul_2exp(m_data, m_data, shift);
1246          if (term > 0)
1247             mpz_add_ui(m_data, m_data, static_cast<unsigned>(term));
1248          else
1249             mpz_sub_ui(m_data, m_data, static_cast<unsigned>(-term));
1250          f -= term;
1251       }
1252       if (e > 0)
1253          mpz_mul_2exp(m_data, m_data, e);
1254       else if (e < 0)
1255          mpz_div_2exp(m_data, m_data, -e);
1256       return *this;
1257    }
1258    gmp_int& operator=(const char* s)
1259    {
1260       if (m_data[0]._mp_d == 0)
1261          mpz_init(this->m_data);
1262       std::size_t n     = s ? std::strlen(s) : 0;
1263       int         radix = 10;
1264       if (n && (*s == '0'))
1265       {
1266          if ((n > 1) && ((s[1] == 'x') || (s[1] == 'X')))
1267          {
1268             radix = 16;
1269             s += 2;
1270             n -= 2;
1271          }
1272          else
1273          {
1274             radix = 8;
1275             n -= 1;
1276          }
1277       }
1278       if (n)
1279       {
1280          if (0 != mpz_set_str(m_data, s, radix))
1281             BOOST_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid integer.")));
1282       }
1283       else
1284          mpz_set_ui(m_data, 0);
1285       return *this;
1286    }
1287    gmp_int& operator=(const mpf_t val)
1288    {
1289       if (m_data[0]._mp_d == 0)
1290          mpz_init(this->m_data);
1291       mpz_set_f(this->m_data, val);
1292       return *this;
1293    }
1294    gmp_int& operator=(const mpz_t val)
1295    {
1296       if (m_data[0]._mp_d == 0)
1297          mpz_init(this->m_data);
1298       mpz_set(this->m_data, val);
1299       return *this;
1300    }
1301    gmp_int& operator=(const mpq_t val)
1302    {
1303       if (m_data[0]._mp_d == 0)
1304          mpz_init(this->m_data);
1305       mpz_set_q(this->m_data, val);
1306       return *this;
1307    }
1308    template <unsigned Digits10>
1309    gmp_int& operator=(const gmp_float<Digits10>& o)
1310    {
1311       if (m_data[0]._mp_d == 0)
1312          mpz_init(this->m_data);
1313       mpz_set_f(this->m_data, o.data());
1314       return *this;
1315    }
1316    gmp_int& operator=(const gmp_rational& o);
1317    void     swap(gmp_int& o)
1318    {
1319       mpz_swap(m_data, o.m_data);
1320    }
1321    std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags f) const
1322    {
1323       BOOST_ASSERT(m_data[0]._mp_d);
1324
1325       int base = 10;
1326       if ((f & std::ios_base::oct) == std::ios_base::oct)
1327          base = 8;
1328       else if ((f & std::ios_base::hex) == std::ios_base::hex)
1329          base = 16;
1330       //
1331       // sanity check, bases 8 and 16 are only available for positive numbers:
1332       //
1333       if ((base != 10) && (mpz_sgn(m_data) < 0))
1334          BOOST_THROW_EXCEPTION(std::runtime_error("Formatted output in bases 8 or 16 is only available for positive numbers"));
1335       void* (*alloc_func_ptr)(size_t);
1336       void* (*realloc_func_ptr)(void*, size_t, size_t);
1337       void (*free_func_ptr)(void*, size_t);
1338       const char* ps = mpz_get_str(0, base, m_data);
1339       std::string s  = ps;
1340       mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
1341       (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
1342       if (f & std::ios_base::uppercase)
1343          for (size_t i = 0; i < s.length(); ++i)
1344             s[i] = std::toupper(s[i]);
1345       if ((base != 10) && (f & std::ios_base::showbase))
1346       {
1347          int         pos = s[0] == '-' ? 1 : 0;
1348          const char* pp  = base == 8 ? "0" : (f & std::ios_base::uppercase) ? "0X" : "0x";
1349          s.insert(static_cast<std::string::size_type>(pos), pp);
1350       }
1351       if ((f & std::ios_base::showpos) && (s[0] != '-'))
1352          s.insert(static_cast<std::string::size_type>(0), 1, '+');
1353
1354       return s;
1355    }
1356    ~gmp_int() BOOST_NOEXCEPT
1357    {
1358       if (m_data[0]._mp_d)
1359          mpz_clear(m_data);
1360    }
1361    void negate() BOOST_NOEXCEPT
1362    {
1363       BOOST_ASSERT(m_data[0]._mp_d);
1364       mpz_neg(m_data, m_data);
1365    }
1366    int compare(const gmp_int& o) const BOOST_NOEXCEPT
1367    {
1368       BOOST_ASSERT(m_data[0]._mp_d && o.m_data[0]._mp_d);
1369       return mpz_cmp(m_data, o.m_data);
1370    }
1371    int compare(long i) const BOOST_NOEXCEPT
1372    {
1373       BOOST_ASSERT(m_data[0]._mp_d);
1374       return mpz_cmp_si(m_data, i);
1375    }
1376    int compare(unsigned long i) const BOOST_NOEXCEPT
1377    {
1378       BOOST_ASSERT(m_data[0]._mp_d);
1379       return mpz_cmp_ui(m_data, i);
1380    }
1381    template <class V>
1382    int compare(V v) const
1383    {
1384       gmp_int d;
1385       d = v;
1386       return compare(d);
1387    }
1388    mpz_t& data() BOOST_NOEXCEPT
1389    {
1390       BOOST_ASSERT(m_data[0]._mp_d);
1391       return m_data;
1392    }
1393    const mpz_t& data() const BOOST_NOEXCEPT
1394    {
1395       BOOST_ASSERT(m_data[0]._mp_d);
1396       return m_data;
1397    }
1398
1399  protected:
1400    mpz_t m_data;
1401 };
1402
1403 template <class T>
1404 inline typename enable_if<is_arithmetic<T>, bool>::type eval_eq(const gmp_int& a, const T& b)
1405 {
1406    return a.compare(b) == 0;
1407 }
1408 template <class T>
1409 inline typename enable_if<is_arithmetic<T>, bool>::type eval_lt(const gmp_int& a, const T& b)
1410 {
1411    return a.compare(b) < 0;
1412 }
1413 template <class T>
1414 inline typename enable_if<is_arithmetic<T>, bool>::type eval_gt(const gmp_int& a, const T& b)
1415 {
1416    return a.compare(b) > 0;
1417 }
1418
1419 inline bool eval_is_zero(const gmp_int& val)
1420 {
1421    return mpz_sgn(val.data()) == 0;
1422 }
1423 inline void eval_add(gmp_int& t, const gmp_int& o)
1424 {
1425    mpz_add(t.data(), t.data(), o.data());
1426 }
1427 inline void eval_multiply_add(gmp_int& t, const gmp_int& a, const gmp_int& b)
1428 {
1429    mpz_addmul(t.data(), a.data(), b.data());
1430 }
1431 inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, const gmp_int& b)
1432 {
1433    mpz_submul(t.data(), a.data(), b.data());
1434 }
1435 inline void eval_subtract(gmp_int& t, const gmp_int& o)
1436 {
1437    mpz_sub(t.data(), t.data(), o.data());
1438 }
1439 inline void eval_multiply(gmp_int& t, const gmp_int& o)
1440 {
1441    mpz_mul(t.data(), t.data(), o.data());
1442 }
1443 inline void eval_divide(gmp_int& t, const gmp_int& o)
1444 {
1445    if (eval_is_zero(o))
1446       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1447    mpz_tdiv_q(t.data(), t.data(), o.data());
1448 }
1449 inline void eval_modulus(gmp_int& t, const gmp_int& o)
1450 {
1451    mpz_tdiv_r(t.data(), t.data(), o.data());
1452 }
1453 inline void eval_add(gmp_int& t, unsigned long i)
1454 {
1455    mpz_add_ui(t.data(), t.data(), i);
1456 }
1457 inline void eval_multiply_add(gmp_int& t, const gmp_int& a, unsigned long i)
1458 {
1459    mpz_addmul_ui(t.data(), a.data(), i);
1460 }
1461 inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, unsigned long i)
1462 {
1463    mpz_submul_ui(t.data(), a.data(), i);
1464 }
1465 inline void eval_subtract(gmp_int& t, unsigned long i)
1466 {
1467    mpz_sub_ui(t.data(), t.data(), i);
1468 }
1469 inline void eval_multiply(gmp_int& t, unsigned long i)
1470 {
1471    mpz_mul_ui(t.data(), t.data(), i);
1472 }
1473 inline void eval_modulus(gmp_int& t, unsigned long i)
1474 {
1475    mpz_tdiv_r_ui(t.data(), t.data(), i);
1476 }
1477 inline void eval_divide(gmp_int& t, unsigned long i)
1478 {
1479    if (i == 0)
1480       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1481    mpz_tdiv_q_ui(t.data(), t.data(), i);
1482 }
1483 inline void eval_add(gmp_int& t, long i)
1484 {
1485    if (i > 0)
1486       mpz_add_ui(t.data(), t.data(), i);
1487    else
1488       mpz_sub_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1489 }
1490 inline void eval_multiply_add(gmp_int& t, const gmp_int& a, long i)
1491 {
1492    if (i > 0)
1493       mpz_addmul_ui(t.data(), a.data(), i);
1494    else
1495       mpz_submul_ui(t.data(), a.data(), boost::multiprecision::detail::unsigned_abs(i));
1496 }
1497 inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, long i)
1498 {
1499    if (i > 0)
1500       mpz_submul_ui(t.data(), a.data(), i);
1501    else
1502       mpz_addmul_ui(t.data(), a.data(), boost::multiprecision::detail::unsigned_abs(i));
1503 }
1504 inline void eval_subtract(gmp_int& t, long i)
1505 {
1506    if (i > 0)
1507       mpz_sub_ui(t.data(), t.data(), i);
1508    else
1509       mpz_add_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1510 }
1511 inline void eval_multiply(gmp_int& t, long i)
1512 {
1513    mpz_mul_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1514    if (i < 0)
1515       mpz_neg(t.data(), t.data());
1516 }
1517 inline void eval_modulus(gmp_int& t, long i)
1518 {
1519    mpz_tdiv_r_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1520 }
1521 inline void eval_divide(gmp_int& t, long i)
1522 {
1523    if (i == 0)
1524       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1525    mpz_tdiv_q_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i));
1526    if (i < 0)
1527       mpz_neg(t.data(), t.data());
1528 }
1529 template <class UI>
1530 inline void eval_left_shift(gmp_int& t, UI i)
1531 {
1532    mpz_mul_2exp(t.data(), t.data(), static_cast<unsigned long>(i));
1533 }
1534 template <class UI>
1535 inline void eval_right_shift(gmp_int& t, UI i)
1536 {
1537    mpz_fdiv_q_2exp(t.data(), t.data(), static_cast<unsigned long>(i));
1538 }
1539 template <class UI>
1540 inline void eval_left_shift(gmp_int& t, const gmp_int& v, UI i)
1541 {
1542    mpz_mul_2exp(t.data(), v.data(), static_cast<unsigned long>(i));
1543 }
1544 template <class UI>
1545 inline void eval_right_shift(gmp_int& t, const gmp_int& v, UI i)
1546 {
1547    mpz_fdiv_q_2exp(t.data(), v.data(), static_cast<unsigned long>(i));
1548 }
1549
1550 inline void eval_bitwise_and(gmp_int& result, const gmp_int& v)
1551 {
1552    mpz_and(result.data(), result.data(), v.data());
1553 }
1554
1555 inline void eval_bitwise_or(gmp_int& result, const gmp_int& v)
1556 {
1557    mpz_ior(result.data(), result.data(), v.data());
1558 }
1559
1560 inline void eval_bitwise_xor(gmp_int& result, const gmp_int& v)
1561 {
1562    mpz_xor(result.data(), result.data(), v.data());
1563 }
1564
1565 inline void eval_add(gmp_int& t, const gmp_int& p, const gmp_int& o)
1566 {
1567    mpz_add(t.data(), p.data(), o.data());
1568 }
1569 inline void eval_subtract(gmp_int& t, const gmp_int& p, const gmp_int& o)
1570 {
1571    mpz_sub(t.data(), p.data(), o.data());
1572 }
1573 inline void eval_multiply(gmp_int& t, const gmp_int& p, const gmp_int& o)
1574 {
1575    mpz_mul(t.data(), p.data(), o.data());
1576 }
1577 inline void eval_divide(gmp_int& t, const gmp_int& p, const gmp_int& o)
1578 {
1579    if (eval_is_zero(o))
1580       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1581    mpz_tdiv_q(t.data(), p.data(), o.data());
1582 }
1583 inline void eval_modulus(gmp_int& t, const gmp_int& p, const gmp_int& o)
1584 {
1585    mpz_tdiv_r(t.data(), p.data(), o.data());
1586 }
1587 inline void eval_add(gmp_int& t, const gmp_int& p, unsigned long i)
1588 {
1589    mpz_add_ui(t.data(), p.data(), i);
1590 }
1591 inline void eval_subtract(gmp_int& t, const gmp_int& p, unsigned long i)
1592 {
1593    mpz_sub_ui(t.data(), p.data(), i);
1594 }
1595 inline void eval_multiply(gmp_int& t, const gmp_int& p, unsigned long i)
1596 {
1597    mpz_mul_ui(t.data(), p.data(), i);
1598 }
1599 inline void eval_modulus(gmp_int& t, const gmp_int& p, unsigned long i)
1600 {
1601    mpz_tdiv_r_ui(t.data(), p.data(), i);
1602 }
1603 inline void eval_divide(gmp_int& t, const gmp_int& p, unsigned long i)
1604 {
1605    if (i == 0)
1606       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1607    mpz_tdiv_q_ui(t.data(), p.data(), i);
1608 }
1609 inline void eval_add(gmp_int& t, const gmp_int& p, long i)
1610 {
1611    if (i > 0)
1612       mpz_add_ui(t.data(), p.data(), i);
1613    else
1614       mpz_sub_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1615 }
1616 inline void eval_subtract(gmp_int& t, const gmp_int& p, long i)
1617 {
1618    if (i > 0)
1619       mpz_sub_ui(t.data(), p.data(), i);
1620    else
1621       mpz_add_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1622 }
1623 inline void eval_multiply(gmp_int& t, const gmp_int& p, long i)
1624 {
1625    mpz_mul_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1626    if (i < 0)
1627       mpz_neg(t.data(), t.data());
1628 }
1629 inline void eval_modulus(gmp_int& t, const gmp_int& p, long i)
1630 {
1631    mpz_tdiv_r_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1632 }
1633 inline void eval_divide(gmp_int& t, const gmp_int& p, long i)
1634 {
1635    if (i == 0)
1636       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1637    mpz_tdiv_q_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
1638    if (i < 0)
1639       mpz_neg(t.data(), t.data());
1640 }
1641
1642 inline void eval_bitwise_and(gmp_int& result, const gmp_int& u, const gmp_int& v)
1643 {
1644    mpz_and(result.data(), u.data(), v.data());
1645 }
1646
1647 inline void eval_bitwise_or(gmp_int& result, const gmp_int& u, const gmp_int& v)
1648 {
1649    mpz_ior(result.data(), u.data(), v.data());
1650 }
1651
1652 inline void eval_bitwise_xor(gmp_int& result, const gmp_int& u, const gmp_int& v)
1653 {
1654    mpz_xor(result.data(), u.data(), v.data());
1655 }
1656
1657 inline void eval_complement(gmp_int& result, const gmp_int& u)
1658 {
1659    mpz_com(result.data(), u.data());
1660 }
1661
1662 inline int eval_get_sign(const gmp_int& val)
1663 {
1664    return mpz_sgn(val.data());
1665 }
1666 inline void eval_convert_to(unsigned long* result, const gmp_int& val)
1667 {
1668    if (mpz_sgn(val.data()) < 0)
1669    {
1670       BOOST_THROW_EXCEPTION(std::range_error("Conversion from negative integer to an unsigned type results in undefined behaviour"));
1671    }
1672    else
1673       *result = (unsigned long)mpz_get_ui(val.data());
1674 }
1675 inline void eval_convert_to(long* result, const gmp_int& val)
1676 {
1677    if (0 == mpz_fits_slong_p(val.data()))
1678    {
1679       *result = mpz_sgn(val.data()) < 0 ? (std::numeric_limits<long>::min)() : (std::numeric_limits<long>::max)();
1680    }
1681    else
1682       *result = (signed long)mpz_get_si(val.data());
1683 }
1684 inline void eval_convert_to(double* result, const gmp_int& val)
1685 {
1686    *result = mpz_get_d(val.data());
1687 }
1688
1689 inline void eval_abs(gmp_int& result, const gmp_int& val)
1690 {
1691    mpz_abs(result.data(), val.data());
1692 }
1693
1694 inline void eval_gcd(gmp_int& result, const gmp_int& a, const gmp_int& b)
1695 {
1696    mpz_gcd(result.data(), a.data(), b.data());
1697 }
1698 inline void eval_lcm(gmp_int& result, const gmp_int& a, const gmp_int& b)
1699 {
1700    mpz_lcm(result.data(), a.data(), b.data());
1701 }
1702 template <class I>
1703 inline typename enable_if_c<(is_unsigned<I>::value && (sizeof(I) <= sizeof(unsigned long)))>::type eval_gcd(gmp_int& result, const gmp_int& a, const I b)
1704 {
1705    mpz_gcd_ui(result.data(), a.data(), b);
1706 }
1707 template <class I>
1708 inline typename enable_if_c<(is_unsigned<I>::value && (sizeof(I) <= sizeof(unsigned long)))>::type eval_lcm(gmp_int& result, const gmp_int& a, const I b)
1709 {
1710    mpz_lcm_ui(result.data(), a.data(), b);
1711 }
1712 template <class I>
1713 inline typename enable_if_c<(is_signed<I>::value && (sizeof(I) <= sizeof(long)))>::type eval_gcd(gmp_int& result, const gmp_int& a, const I b)
1714 {
1715    mpz_gcd_ui(result.data(), a.data(), boost::multiprecision::detail::unsigned_abs(b));
1716 }
1717 template <class I>
1718 inline typename enable_if_c<is_signed<I>::value && ((sizeof(I) <= sizeof(long)))>::type eval_lcm(gmp_int& result, const gmp_int& a, const I b)
1719 {
1720    mpz_lcm_ui(result.data(), a.data(), boost::multiprecision::detail::unsigned_abs(b));
1721 }
1722
1723 inline void eval_integer_sqrt(gmp_int& s, gmp_int& r, const gmp_int& x)
1724 {
1725    mpz_sqrtrem(s.data(), r.data(), x.data());
1726 }
1727
1728 inline unsigned eval_lsb(const gmp_int& val)
1729 {
1730    int c = eval_get_sign(val);
1731    if (c == 0)
1732    {
1733       BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
1734    }
1735    if (c < 0)
1736    {
1737       BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
1738    }
1739    return static_cast<unsigned>(mpz_scan1(val.data(), 0));
1740 }
1741
1742 inline unsigned eval_msb(const gmp_int& val)
1743 {
1744    int c = eval_get_sign(val);
1745    if (c == 0)
1746    {
1747       BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
1748    }
1749    if (c < 0)
1750    {
1751       BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
1752    }
1753    return static_cast<unsigned>(mpz_sizeinbase(val.data(), 2) - 1);
1754 }
1755
1756 inline bool eval_bit_test(const gmp_int& val, unsigned index)
1757 {
1758    return mpz_tstbit(val.data(), index) ? true : false;
1759 }
1760
1761 inline void eval_bit_set(gmp_int& val, unsigned index)
1762 {
1763    mpz_setbit(val.data(), index);
1764 }
1765
1766 inline void eval_bit_unset(gmp_int& val, unsigned index)
1767 {
1768    mpz_clrbit(val.data(), index);
1769 }
1770
1771 inline void eval_bit_flip(gmp_int& val, unsigned index)
1772 {
1773    mpz_combit(val.data(), index);
1774 }
1775
1776 inline void eval_qr(const gmp_int& x, const gmp_int& y,
1777                     gmp_int& q, gmp_int& r)
1778 {
1779    mpz_tdiv_qr(q.data(), r.data(), x.data(), y.data());
1780 }
1781
1782 template <class Integer>
1783 inline typename enable_if<is_unsigned<Integer>, Integer>::type eval_integer_modulus(const gmp_int& x, Integer val)
1784 {
1785 #if defined(__MPIR_VERSION) && (__MPIR_VERSION >= 3)
1786    if ((sizeof(Integer) <= sizeof(mpir_ui)) || (val <= (std::numeric_limits<mpir_ui>::max)()))
1787 #else
1788    if ((sizeof(Integer) <= sizeof(long)) || (val <= (std::numeric_limits<unsigned long>::max)()))
1789 #endif
1790    {
1791       return static_cast<Integer>(mpz_tdiv_ui(x.data(), val));
1792    }
1793    else
1794    {
1795       return default_ops::eval_integer_modulus(x, val);
1796    }
1797 }
1798 template <class Integer>
1799 inline typename enable_if<is_signed<Integer>, Integer>::type eval_integer_modulus(const gmp_int& x, Integer val)
1800 {
1801    return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
1802 }
1803 inline void eval_powm(gmp_int& result, const gmp_int& base, const gmp_int& p, const gmp_int& m)
1804 {
1805    if (eval_get_sign(p) < 0)
1806    {
1807       BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
1808    }
1809    mpz_powm(result.data(), base.data(), p.data(), m.data());
1810 }
1811
1812 template <class Integer>
1813 inline typename enable_if<
1814     mpl::and_<
1815         is_unsigned<Integer>,
1816         mpl::bool_<sizeof(Integer) <= sizeof(unsigned long)> > >::type
1817 eval_powm(gmp_int& result, const gmp_int& base, Integer p, const gmp_int& m)
1818 {
1819    mpz_powm_ui(result.data(), base.data(), p, m.data());
1820 }
1821 template <class Integer>
1822 inline typename enable_if<
1823     mpl::and_<
1824         is_signed<Integer>,
1825         mpl::bool_<sizeof(Integer) <= sizeof(unsigned long)> > >::type
1826 eval_powm(gmp_int& result, const gmp_int& base, Integer p, const gmp_int& m)
1827 {
1828    if (p < 0)
1829    {
1830       BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
1831    }
1832    mpz_powm_ui(result.data(), base.data(), p, m.data());
1833 }
1834
1835 inline std::size_t hash_value(const gmp_int& val)
1836 {
1837    // We should really use mpz_limbs_read here, but that's unsupported on older versions:
1838    std::size_t result = 0;
1839    for (int i = 0; i < std::abs(val.data()[0]._mp_size); ++i)
1840       boost::hash_combine(result, val.data()[0]._mp_d[i]);
1841    boost::hash_combine(result, val.data()[0]._mp_size);
1842    return result;
1843 }
1844
1845 struct gmp_rational;
1846 void eval_add(gmp_rational& t, const gmp_rational& o);
1847
1848 struct gmp_rational
1849 {
1850 #ifdef BOOST_HAS_LONG_LONG
1851    typedef mpl::list<long, boost::long_long_type>           signed_types;
1852    typedef mpl::list<unsigned long, boost::ulong_long_type> unsigned_types;
1853 #else
1854    typedef mpl::list<long>          signed_types;
1855    typedef mpl::list<unsigned long> unsigned_types;
1856 #endif
1857    typedef mpl::list<double, long double> float_types;
1858
1859    gmp_rational()
1860    {
1861       mpq_init(this->m_data);
1862    }
1863    gmp_rational(const gmp_rational& o)
1864    {
1865       mpq_init(m_data);
1866       if (o.m_data[0]._mp_num._mp_d)
1867          mpq_set(m_data, o.m_data);
1868    }
1869    gmp_rational(const gmp_int& o)
1870    {
1871       mpq_init(m_data);
1872       mpq_set_z(m_data, o.data());
1873    }
1874 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
1875    gmp_rational(gmp_rational&& o) BOOST_NOEXCEPT
1876    {
1877       m_data[0]                 = o.m_data[0];
1878       o.m_data[0]._mp_num._mp_d = 0;
1879       o.m_data[0]._mp_den._mp_d = 0;
1880    }
1881 #endif
1882    gmp_rational(const mpq_t o)
1883    {
1884       mpq_init(m_data);
1885       mpq_set(m_data, o);
1886    }
1887    gmp_rational(const mpz_t o)
1888    {
1889       mpq_init(m_data);
1890       mpq_set_z(m_data, o);
1891    }
1892    gmp_rational& operator=(const gmp_rational& o)
1893    {
1894       if (m_data[0]._mp_den._mp_d == 0)
1895          mpq_init(m_data);
1896       mpq_set(m_data, o.m_data);
1897       return *this;
1898    }
1899 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
1900    gmp_rational& operator=(gmp_rational&& o) BOOST_NOEXCEPT
1901    {
1902       mpq_swap(m_data, o.m_data);
1903       return *this;
1904    }
1905 #endif
1906 #ifdef BOOST_HAS_LONG_LONG
1907 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
1908    gmp_rational& operator=(boost::ulong_long_type i)
1909    {
1910       *this = static_cast<unsigned long>(i);
1911       return *this;
1912    }
1913 #else
1914    gmp_rational& operator=(boost::ulong_long_type i)
1915    {
1916       if (m_data[0]._mp_den._mp_d == 0)
1917          mpq_init(m_data);
1918       gmp_int zi;
1919       zi = i;
1920       mpq_set_z(m_data, zi.data());
1921       return *this;
1922    }
1923    gmp_rational& operator=(boost::long_long_type i)
1924    {
1925       if (m_data[0]._mp_den._mp_d == 0)
1926          mpq_init(m_data);
1927       bool neg = i < 0;
1928       *this    = boost::multiprecision::detail::unsigned_abs(i);
1929       if (neg)
1930          mpq_neg(m_data, m_data);
1931       return *this;
1932    }
1933 #endif
1934 #endif
1935    gmp_rational& operator=(unsigned long i)
1936    {
1937       if (m_data[0]._mp_den._mp_d == 0)
1938          mpq_init(m_data);
1939       mpq_set_ui(m_data, i, 1);
1940       return *this;
1941    }
1942    gmp_rational& operator=(long i)
1943    {
1944       if (m_data[0]._mp_den._mp_d == 0)
1945          mpq_init(m_data);
1946       mpq_set_si(m_data, i, 1);
1947       return *this;
1948    }
1949    gmp_rational& operator=(double d)
1950    {
1951       if (m_data[0]._mp_den._mp_d == 0)
1952          mpq_init(m_data);
1953       mpq_set_d(m_data, d);
1954       return *this;
1955    }
1956    gmp_rational& operator=(long double a)
1957    {
1958       using default_ops::eval_add;
1959       using default_ops::eval_subtract;
1960       using std::floor;
1961       using std::frexp;
1962       using std::ldexp;
1963
1964       if (m_data[0]._mp_den._mp_d == 0)
1965          mpq_init(m_data);
1966
1967       if (a == 0)
1968       {
1969          mpq_set_si(m_data, 0, 1);
1970          return *this;
1971       }
1972
1973       if (a == 1)
1974       {
1975          mpq_set_si(m_data, 1, 1);
1976          return *this;
1977       }
1978
1979       BOOST_ASSERT(!(boost::math::isinf)(a));
1980       BOOST_ASSERT(!(boost::math::isnan)(a));
1981
1982       int         e;
1983       long double f, term;
1984       mpq_set_ui(m_data, 0, 1);
1985       mpq_set_ui(m_data, 0u, 1);
1986       gmp_rational t;
1987
1988       f = frexp(a, &e);
1989
1990       static const int shift = std::numeric_limits<int>::digits - 1;
1991
1992       while (f)
1993       {
1994          // extract int sized bits from f:
1995          f    = ldexp(f, shift);
1996          term = floor(f);
1997          e -= shift;
1998          mpq_mul_2exp(m_data, m_data, shift);
1999          t = static_cast<long>(term);
2000          eval_add(*this, t);
2001          f -= term;
2002       }
2003       if (e > 0)
2004          mpq_mul_2exp(m_data, m_data, e);
2005       else if (e < 0)
2006          mpq_div_2exp(m_data, m_data, -e);
2007       return *this;
2008    }
2009    gmp_rational& operator=(const char* s)
2010    {
2011       if (m_data[0]._mp_den._mp_d == 0)
2012          mpq_init(m_data);
2013       if (0 != mpq_set_str(m_data, s, 10))
2014          BOOST_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid rational number.")));
2015       return *this;
2016    }
2017    gmp_rational& operator=(const gmp_int& o)
2018    {
2019       if (m_data[0]._mp_den._mp_d == 0)
2020          mpq_init(m_data);
2021       mpq_set_z(m_data, o.data());
2022       return *this;
2023    }
2024    gmp_rational& operator=(const mpq_t o)
2025    {
2026       if (m_data[0]._mp_den._mp_d == 0)
2027          mpq_init(m_data);
2028       mpq_set(m_data, o);
2029       return *this;
2030    }
2031    gmp_rational& operator=(const mpz_t o)
2032    {
2033       if (m_data[0]._mp_den._mp_d == 0)
2034          mpq_init(m_data);
2035       mpq_set_z(m_data, o);
2036       return *this;
2037    }
2038    void swap(gmp_rational& o)
2039    {
2040       mpq_swap(m_data, o.m_data);
2041    }
2042    std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags /*f*/) const
2043    {
2044       BOOST_ASSERT(m_data[0]._mp_num._mp_d);
2045       // TODO make a better job of this including handling of f!!
2046       void* (*alloc_func_ptr)(size_t);
2047       void* (*realloc_func_ptr)(void*, size_t, size_t);
2048       void (*free_func_ptr)(void*, size_t);
2049       const char* ps = mpq_get_str(0, 10, m_data);
2050       std::string s  = ps;
2051       mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
2052       (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
2053       return s;
2054    }
2055    ~gmp_rational()
2056    {
2057       if (m_data[0]._mp_num._mp_d || m_data[0]._mp_den._mp_d)
2058          mpq_clear(m_data);
2059    }
2060    void negate()
2061    {
2062       BOOST_ASSERT(m_data[0]._mp_num._mp_d);
2063       mpq_neg(m_data, m_data);
2064    }
2065    int compare(const gmp_rational& o) const
2066    {
2067       BOOST_ASSERT(m_data[0]._mp_num._mp_d && o.m_data[0]._mp_num._mp_d);
2068       return mpq_cmp(m_data, o.m_data);
2069    }
2070    template <class V>
2071    int compare(V v) const
2072    {
2073       gmp_rational d;
2074       d = v;
2075       return compare(d);
2076    }
2077    int compare(unsigned long v) const
2078    {
2079       BOOST_ASSERT(m_data[0]._mp_num._mp_d);
2080       return mpq_cmp_ui(m_data, v, 1);
2081    }
2082    int compare(long v) const
2083    {
2084       BOOST_ASSERT(m_data[0]._mp_num._mp_d);
2085       return mpq_cmp_si(m_data, v, 1);
2086    }
2087    mpq_t& data()
2088    {
2089       BOOST_ASSERT(m_data[0]._mp_num._mp_d);
2090       return m_data;
2091    }
2092    const mpq_t& data() const
2093    {
2094       BOOST_ASSERT(m_data[0]._mp_num._mp_d);
2095       return m_data;
2096    }
2097
2098  protected:
2099    mpq_t m_data;
2100 };
2101
2102 inline bool eval_is_zero(const gmp_rational& val)
2103 {
2104    return mpq_sgn(val.data()) == 0;
2105 }
2106 template <class T>
2107 inline bool eval_eq(gmp_rational& a, const T& b)
2108 {
2109    return a.compare(b) == 0;
2110 }
2111 template <class T>
2112 inline bool eval_lt(gmp_rational& a, const T& b)
2113 {
2114    return a.compare(b) < 0;
2115 }
2116 template <class T>
2117 inline bool eval_gt(gmp_rational& a, const T& b)
2118 {
2119    return a.compare(b) > 0;
2120 }
2121
2122 inline void eval_add(gmp_rational& t, const gmp_rational& o)
2123 {
2124    mpq_add(t.data(), t.data(), o.data());
2125 }
2126 inline void eval_subtract(gmp_rational& t, const gmp_rational& o)
2127 {
2128    mpq_sub(t.data(), t.data(), o.data());
2129 }
2130 inline void eval_multiply(gmp_rational& t, const gmp_rational& o)
2131 {
2132    mpq_mul(t.data(), t.data(), o.data());
2133 }
2134 inline void eval_divide(gmp_rational& t, const gmp_rational& o)
2135 {
2136    if (eval_is_zero(o))
2137       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2138    mpq_div(t.data(), t.data(), o.data());
2139 }
2140 inline void eval_add(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2141 {
2142    mpq_add(t.data(), p.data(), o.data());
2143 }
2144 inline void eval_subtract(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2145 {
2146    mpq_sub(t.data(), p.data(), o.data());
2147 }
2148 inline void eval_multiply(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2149 {
2150    mpq_mul(t.data(), p.data(), o.data());
2151 }
2152 inline void eval_divide(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2153 {
2154    if (eval_is_zero(o))
2155       BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2156    mpq_div(t.data(), p.data(), o.data());
2157 }
2158
2159 inline int eval_get_sign(const gmp_rational& val)
2160 {
2161    return mpq_sgn(val.data());
2162 }
2163 inline void eval_convert_to(double* result, const gmp_rational& val)
2164 {
2165    //
2166    // This does not round correctly:
2167    //
2168    //*result = mpq_get_d(val.data());
2169    //
2170    // This does:
2171    //
2172    boost::multiprecision::detail::generic_convert_rational_to_float(*result, val);
2173 }
2174
2175 inline void eval_convert_to(long* result, const gmp_rational& val)
2176 {
2177    double r;
2178    eval_convert_to(&r, val);
2179    *result = static_cast<long>(r);
2180 }
2181
2182 inline void eval_convert_to(unsigned long* result, const gmp_rational& val)
2183 {
2184    double r;
2185    eval_convert_to(&r, val);
2186    *result = static_cast<long>(r);
2187 }
2188
2189 inline void eval_abs(gmp_rational& result, const gmp_rational& val)
2190 {
2191    mpq_abs(result.data(), val.data());
2192 }
2193
2194 inline void assign_components(gmp_rational& result, unsigned long v1, unsigned long v2)
2195 {
2196    mpq_set_ui(result.data(), v1, v2);
2197    mpq_canonicalize(result.data());
2198 }
2199 inline void assign_components(gmp_rational& result, long v1, long v2)
2200 {
2201    mpq_set_si(result.data(), v1, v2);
2202    mpq_canonicalize(result.data());
2203 }
2204 inline void assign_components(gmp_rational& result, gmp_int const& v1, gmp_int const& v2)
2205 {
2206    mpz_set(mpq_numref(result.data()), v1.data());
2207    mpz_set(mpq_denref(result.data()), v2.data());
2208    mpq_canonicalize(result.data());
2209 }
2210
2211 inline std::size_t hash_value(const gmp_rational& val)
2212 {
2213    std::size_t result = 0;
2214    for (int i = 0; i < std::abs(val.data()[0]._mp_num._mp_size); ++i)
2215       boost::hash_combine(result, val.data()[0]._mp_num._mp_d[i]);
2216    for (int i = 0; i < std::abs(val.data()[0]._mp_den._mp_size); ++i)
2217       boost::hash_combine(result, val.data()[0]._mp_den._mp_d[i]);
2218    boost::hash_combine(result, val.data()[0]._mp_num._mp_size);
2219    return result;
2220 }
2221
2222 //
2223 // Some member functions that are dependent upon previous code go here:
2224 //
2225 template <unsigned Digits10>
2226 template <unsigned D>
2227 inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename enable_if_c<D <= Digits10>::type*)
2228 {
2229    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision()));
2230    mpf_set(this->m_data, o.data());
2231 }
2232 template <unsigned Digits10>
2233 template <unsigned D>
2234 inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename disable_if_c<D <= Digits10>::type*)
2235 {
2236    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision()));
2237    mpf_set(this->m_data, o.data());
2238 }
2239 template <unsigned Digits10>
2240 inline gmp_float<Digits10>::gmp_float(const gmp_int& o)
2241 {
2242    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision()));
2243    mpf_set_z(this->data(), o.data());
2244 }
2245 template <unsigned Digits10>
2246 inline gmp_float<Digits10>::gmp_float(const gmp_rational& o)
2247 {
2248    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision()));
2249    mpf_set_q(this->data(), o.data());
2250 }
2251 template <unsigned Digits10>
2252 template <unsigned D>
2253 inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_float<D>& o)
2254 {
2255    if (this->m_data[0]._mp_d == 0)
2256       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision()));
2257    mpf_set(this->m_data, o.data());
2258    return *this;
2259 }
2260 template <unsigned Digits10>
2261 inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_int& o)
2262 {
2263    if (this->m_data[0]._mp_d == 0)
2264       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision()));
2265    mpf_set_z(this->data(), o.data());
2266    return *this;
2267 }
2268 template <unsigned Digits10>
2269 inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_rational& o)
2270 {
2271    if (this->m_data[0]._mp_d == 0)
2272       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision()));
2273    mpf_set_q(this->data(), o.data());
2274    return *this;
2275 }
2276 inline gmp_float<0>::gmp_float(const gmp_int& o)
2277 {
2278    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision()));
2279    mpf_set_z(this->data(), o.data());
2280 }
2281 inline gmp_float<0>::gmp_float(const gmp_rational& o)
2282 {
2283    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision()));
2284    mpf_set_q(this->data(), o.data());
2285 }
2286 inline gmp_float<0>& gmp_float<0>::operator=(const gmp_int& o)
2287 {
2288    if (this->m_data[0]._mp_d == 0)
2289       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(this->get_default_precision()));
2290    mpf_set_z(this->data(), o.data());
2291    return *this;
2292 }
2293 inline gmp_float<0>& gmp_float<0>::operator=(const gmp_rational& o)
2294 {
2295    if (this->m_data[0]._mp_d == 0)
2296       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(this->get_default_precision()));
2297    mpf_set_q(this->data(), o.data());
2298    return *this;
2299 }
2300 inline gmp_int::gmp_int(const gmp_rational& o)
2301 {
2302    mpz_init(this->m_data);
2303    mpz_set_q(this->m_data, o.data());
2304 }
2305 inline gmp_int& gmp_int::operator=(const gmp_rational& o)
2306 {
2307    if (this->m_data[0]._mp_d == 0)
2308       mpz_init(this->m_data);
2309    mpz_set_q(this->m_data, o.data());
2310    return *this;
2311 }
2312
2313 } //namespace backends
2314
2315 using boost::multiprecision::backends::gmp_float;
2316 using boost::multiprecision::backends::gmp_int;
2317 using boost::multiprecision::backends::gmp_rational;
2318
2319 template <expression_template_option ExpressionTemplates>
2320 struct component_type<number<gmp_rational, ExpressionTemplates> >
2321 {
2322    typedef number<gmp_int, ExpressionTemplates> type;
2323 };
2324
2325 template <expression_template_option ET>
2326 inline number<gmp_int, ET> numerator(const number<gmp_rational, ET>& val)
2327 {
2328    number<gmp_int, ET> result;
2329    mpz_set(result.backend().data(), (mpq_numref(val.backend().data())));
2330    return result;
2331 }
2332 template <expression_template_option ET>
2333 inline number<gmp_int, ET> denominator(const number<gmp_rational, ET>& val)
2334 {
2335    number<gmp_int, ET> result;
2336    mpz_set(result.backend().data(), (mpq_denref(val.backend().data())));
2337    return result;
2338 }
2339
2340 namespace detail {
2341
2342 #ifdef BOOST_NO_SFINAE_EXPR
2343
2344 template <>
2345 struct is_explicitly_convertible<canonical<mpf_t, gmp_int>::type, gmp_int> : public mpl::true_
2346 {};
2347 template <>
2348 struct is_explicitly_convertible<canonical<mpq_t, gmp_int>::type, gmp_int> : public mpl::true_
2349 {};
2350 template <unsigned Digits10>
2351 struct is_explicitly_convertible<gmp_float<Digits10>, gmp_int> : public mpl::true_
2352 {};
2353 template <>
2354 struct is_explicitly_convertible<gmp_rational, gmp_int> : public mpl::true_
2355 {};
2356 template <unsigned D1, unsigned D2>
2357 struct is_explicitly_convertible<gmp_float<D1>, gmp_float<D2> > : public mpl::true_
2358 {};
2359
2360 #endif
2361
2362 template <>
2363 struct digits2<number<gmp_float<0>, et_on> >
2364 {
2365    static long value()
2366    {
2367       return multiprecision::detail::digits10_2_2(gmp_float<0>::default_precision());
2368    }
2369 };
2370
2371 template <>
2372 struct digits2<number<gmp_float<0>, et_off> >
2373 {
2374    static long value()
2375    {
2376       return multiprecision::detail::digits10_2_2(gmp_float<0>::default_precision());
2377    }
2378 };
2379
2380 template <>
2381 struct digits2<number<debug_adaptor<gmp_float<0> >, et_on> >
2382 {
2383    static long value()
2384    {
2385       return multiprecision::detail::digits10_2_2(gmp_float<0>::default_precision());
2386    }
2387 };
2388
2389 template <>
2390 struct digits2<number<debug_adaptor<gmp_float<0> >, et_off> >
2391 {
2392    static long value()
2393    {
2394       return multiprecision::detail::digits10_2_2(gmp_float<0>::default_precision());
2395    }
2396 };
2397
2398 } // namespace detail
2399
2400 template <>
2401 struct number_category<detail::canonical<mpz_t, gmp_int>::type> : public mpl::int_<number_kind_integer>
2402 {};
2403 template <>
2404 struct number_category<detail::canonical<mpq_t, gmp_rational>::type> : public mpl::int_<number_kind_rational>
2405 {};
2406 template <>
2407 struct number_category<detail::canonical<mpf_t, gmp_float<0> >::type> : public mpl::int_<number_kind_floating_point>
2408 {};
2409
2410 namespace detail {
2411 template <>
2412 struct is_variable_precision<backends::gmp_float<0> > : public true_type
2413 {};
2414 } // namespace detail
2415
2416 typedef number<gmp_float<50> >   mpf_float_50;
2417 typedef number<gmp_float<100> >  mpf_float_100;
2418 typedef number<gmp_float<500> >  mpf_float_500;
2419 typedef number<gmp_float<1000> > mpf_float_1000;
2420 typedef number<gmp_float<0> >    mpf_float;
2421 typedef number<gmp_int>          mpz_int;
2422 typedef number<gmp_rational>     mpq_rational;
2423
2424 } // namespace multiprecision
2425
2426 namespace math { namespace tools {
2427
2428 template <>
2429 inline int digits<boost::multiprecision::mpf_float>()
2430 #ifdef BOOST_MATH_NOEXCEPT
2431     BOOST_NOEXCEPT
2432 #endif
2433 {
2434    return multiprecision::detail::digits10_2_2(boost::multiprecision::mpf_float::default_precision());
2435 }
2436 template <>
2437 inline int digits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >()
2438 #ifdef BOOST_MATH_NOEXCEPT
2439     BOOST_NOEXCEPT
2440 #endif
2441 {
2442    return multiprecision::detail::digits10_2_2(boost::multiprecision::mpf_float::default_precision());
2443 }
2444
2445 template <>
2446 inline boost::multiprecision::mpf_float
2447 max_value<boost::multiprecision::mpf_float>()
2448 {
2449    boost::multiprecision::mpf_float result(0.5);
2450    mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
2451    return result;
2452 }
2453
2454 template <>
2455 inline boost::multiprecision::mpf_float
2456 min_value<boost::multiprecision::mpf_float>()
2457 {
2458    boost::multiprecision::mpf_float result(0.5);
2459    mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::min)() / 64 + 1);
2460    return result;
2461 }
2462
2463 template <>
2464 inline boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off>
2465 max_value<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >()
2466 {
2467    boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> result(0.5);
2468    mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
2469    return result;
2470 }
2471
2472 template <>
2473 inline boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off>
2474 min_value<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >()
2475 {
2476    boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> result(0.5);
2477    mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
2478    return result;
2479 }
2480
2481 template <>
2482 inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >()
2483 #ifdef BOOST_MATH_NOEXCEPT
2484     BOOST_NOEXCEPT
2485 #endif
2486 {
2487    return multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >::default_precision());
2488 }
2489 template <>
2490 inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >()
2491 #ifdef BOOST_MATH_NOEXCEPT
2492     BOOST_NOEXCEPT
2493 #endif
2494 {
2495    return multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >::default_precision());
2496 }
2497
2498 template <>
2499 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >
2500 max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >()
2501 {
2502    return max_value<boost::multiprecision::mpf_float>().backend();
2503 }
2504
2505 template <>
2506 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >
2507 min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >()
2508 {
2509    return min_value<boost::multiprecision::mpf_float>().backend();
2510 }
2511
2512 template <>
2513 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off>
2514 max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >()
2515 {
2516    return max_value<boost::multiprecision::mpf_float>().backend();
2517 }
2518
2519 template <>
2520 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off>
2521 min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >()
2522 {
2523    return min_value<boost::multiprecision::mpf_float>().backend();
2524 }
2525
2526 }} // namespace math::tools
2527
2528 } // namespace boost
2529
2530 namespace std {
2531
2532 //
2533 // numeric_limits [partial] specializations for the types declared in this header:
2534 //
2535 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2536 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >
2537 {
2538    typedef boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> number_type;
2539
2540  public:
2541    BOOST_STATIC_CONSTEXPR bool is_specialized = true;
2542    //
2543    // min and max values chosen so as to not cause segfaults when calling
2544    // mpf_get_str on 64-bit Linux builds.  Possibly we could use larger
2545    // exponent values elsewhere.
2546    //
2547    static number_type(min)()
2548    {
2549       initializer.do_nothing();
2550       static std::pair<bool, number_type> value;
2551       if (!value.first)
2552       {
2553          value.first  = true;
2554          value.second = 1;
2555          mpf_div_2exp(value.second.backend().data(), value.second.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
2556       }
2557       return value.second;
2558    }
2559    static number_type(max)()
2560    {
2561       initializer.do_nothing();
2562       static std::pair<bool, number_type> value;
2563       if (!value.first)
2564       {
2565          value.first  = true;
2566          value.second = 1;
2567          mpf_mul_2exp(value.second.backend().data(), value.second.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
2568       }
2569       return value.second;
2570    }
2571    BOOST_STATIC_CONSTEXPR number_type lowest()
2572    {
2573       return -(max)();
2574    }
2575    BOOST_STATIC_CONSTEXPR int digits   = static_cast<int>((Digits10 * 1000L) / 301L + ((Digits10 * 1000L) % 301L ? 2 : 1));
2576    BOOST_STATIC_CONSTEXPR int digits10 = Digits10;
2577    // Have to allow for a possible extra limb inside the gmp data structure:
2578    BOOST_STATIC_CONSTEXPR int  max_digits10 = Digits10 + 3 + ((GMP_LIMB_BITS * 301L) / 1000L);
2579    BOOST_STATIC_CONSTEXPR bool is_signed    = true;
2580    BOOST_STATIC_CONSTEXPR bool is_integer   = false;
2581    BOOST_STATIC_CONSTEXPR bool is_exact     = false;
2582    BOOST_STATIC_CONSTEXPR int  radix        = 2;
2583    static number_type          epsilon()
2584    {
2585       initializer.do_nothing();
2586       static std::pair<bool, number_type> value;
2587       if (!value.first)
2588       {
2589          value.first  = true;
2590          value.second = 1;
2591          mpf_div_2exp(value.second.backend().data(), value.second.backend().data(), std::numeric_limits<number_type>::digits - 1);
2592       }
2593       return value.second;
2594    }
2595    // What value should this be????
2596    static number_type round_error()
2597    {
2598       // returns epsilon/2
2599       initializer.do_nothing();
2600       static std::pair<bool, number_type> value;
2601       if (!value.first)
2602       {
2603          value.first  = true;
2604          value.second = 1;
2605       }
2606       return value.second;
2607    }
2608    BOOST_STATIC_CONSTEXPR long min_exponent                  = LONG_MIN;
2609    BOOST_STATIC_CONSTEXPR long min_exponent10                = (LONG_MIN / 1000) * 301L;
2610    BOOST_STATIC_CONSTEXPR long max_exponent                  = LONG_MAX;
2611    BOOST_STATIC_CONSTEXPR long max_exponent10                = (LONG_MAX / 1000) * 301L;
2612    BOOST_STATIC_CONSTEXPR bool has_infinity                  = false;
2613    BOOST_STATIC_CONSTEXPR bool has_quiet_NaN                 = false;
2614    BOOST_STATIC_CONSTEXPR bool has_signaling_NaN             = false;
2615    BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm      = denorm_absent;
2616    BOOST_STATIC_CONSTEXPR bool               has_denorm_loss = false;
2617    BOOST_STATIC_CONSTEXPR number_type infinity() { return number_type(); }
2618    BOOST_STATIC_CONSTEXPR number_type quiet_NaN() { return number_type(); }
2619    BOOST_STATIC_CONSTEXPR number_type signaling_NaN() { return number_type(); }
2620    BOOST_STATIC_CONSTEXPR number_type denorm_min() { return number_type(); }
2621    BOOST_STATIC_CONSTEXPR bool        is_iec559         = false;
2622    BOOST_STATIC_CONSTEXPR bool        is_bounded        = true;
2623    BOOST_STATIC_CONSTEXPR bool        is_modulo         = false;
2624    BOOST_STATIC_CONSTEXPR bool        traps             = true;
2625    BOOST_STATIC_CONSTEXPR bool        tinyness_before   = false;
2626    BOOST_STATIC_CONSTEXPR float_round_style round_style = round_indeterminate;
2627
2628  private:
2629    struct data_initializer
2630    {
2631       data_initializer()
2632       {
2633          std::numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<digits10> > >::epsilon();
2634          std::numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<digits10> > >::round_error();
2635          (std::numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<digits10> > >::min)();
2636          (std::numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<digits10> > >::max)();
2637       }
2638       void do_nothing() const {}
2639    };
2640    static const data_initializer initializer;
2641 };
2642
2643 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2644 const typename numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::data_initializer numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::initializer;
2645
2646 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
2647
2648 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2649 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::digits;
2650 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2651 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::digits10;
2652 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2653 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_digits10;
2654 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2655 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_signed;
2656 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2657 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_integer;
2658 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2659 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_exact;
2660 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2661 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::radix;
2662 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2663 BOOST_CONSTEXPR_OR_CONST long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::min_exponent;
2664 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2665 BOOST_CONSTEXPR_OR_CONST long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::min_exponent10;
2666 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2667 BOOST_CONSTEXPR_OR_CONST long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_exponent;
2668 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2669 BOOST_CONSTEXPR_OR_CONST long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_exponent10;
2670 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2671 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_infinity;
2672 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2673 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_quiet_NaN;
2674 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2675 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_signaling_NaN;
2676 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2677 BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_denorm;
2678 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2679 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_denorm_loss;
2680 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2681 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_iec559;
2682 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2683 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_bounded;
2684 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2685 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_modulo;
2686 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2687 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::traps;
2688 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2689 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::tinyness_before;
2690 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
2691 BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::round_style;
2692
2693 #endif
2694
2695 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2696 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >
2697 {
2698    typedef boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> number_type;
2699
2700  public:
2701    BOOST_STATIC_CONSTEXPR bool is_specialized = false;
2702    static number_type(min)() { return number_type(); }
2703    static number_type(max)() { return number_type(); }
2704    static number_type          lowest() { return number_type(); }
2705    BOOST_STATIC_CONSTEXPR int  digits       = 0;
2706    BOOST_STATIC_CONSTEXPR int  digits10     = 0;
2707    BOOST_STATIC_CONSTEXPR int  max_digits10 = 0;
2708    BOOST_STATIC_CONSTEXPR bool is_signed    = false;
2709    BOOST_STATIC_CONSTEXPR bool is_integer   = false;
2710    BOOST_STATIC_CONSTEXPR bool is_exact     = false;
2711    BOOST_STATIC_CONSTEXPR int  radix        = 0;
2712    static number_type          epsilon() { return number_type(); }
2713    static number_type          round_error() { return number_type(); }
2714    BOOST_STATIC_CONSTEXPR int  min_exponent                  = 0;
2715    BOOST_STATIC_CONSTEXPR int  min_exponent10                = 0;
2716    BOOST_STATIC_CONSTEXPR int  max_exponent                  = 0;
2717    BOOST_STATIC_CONSTEXPR int  max_exponent10                = 0;
2718    BOOST_STATIC_CONSTEXPR bool has_infinity                  = false;
2719    BOOST_STATIC_CONSTEXPR bool has_quiet_NaN                 = false;
2720    BOOST_STATIC_CONSTEXPR bool has_signaling_NaN             = false;
2721    BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm      = denorm_absent;
2722    BOOST_STATIC_CONSTEXPR bool               has_denorm_loss = false;
2723    static number_type                        infinity() { return number_type(); }
2724    static number_type                        quiet_NaN() { return number_type(); }
2725    static number_type                        signaling_NaN() { return number_type(); }
2726    static number_type                        denorm_min() { return number_type(); }
2727    BOOST_STATIC_CONSTEXPR bool               is_iec559       = false;
2728    BOOST_STATIC_CONSTEXPR bool               is_bounded      = false;
2729    BOOST_STATIC_CONSTEXPR bool               is_modulo       = false;
2730    BOOST_STATIC_CONSTEXPR bool               traps           = false;
2731    BOOST_STATIC_CONSTEXPR bool               tinyness_before = false;
2732    BOOST_STATIC_CONSTEXPR float_round_style round_style      = round_indeterminate;
2733 };
2734
2735 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
2736
2737 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2738 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::digits;
2739 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2740 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::digits10;
2741 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2742 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_digits10;
2743 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2744 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_signed;
2745 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2746 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_integer;
2747 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2748 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_exact;
2749 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2750 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::radix;
2751 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2752 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::min_exponent;
2753 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2754 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::min_exponent10;
2755 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2756 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_exponent;
2757 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2758 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_exponent10;
2759 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2760 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_infinity;
2761 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2762 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_quiet_NaN;
2763 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2764 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_signaling_NaN;
2765 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2766 BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_denorm;
2767 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2768 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_denorm_loss;
2769 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2770 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_iec559;
2771 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2772 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_bounded;
2773 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2774 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_modulo;
2775 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2776 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::traps;
2777 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2778 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::tinyness_before;
2779 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2780 BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::round_style;
2781
2782 #endif
2783
2784 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2785 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >
2786 {
2787    typedef boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> number_type;
2788
2789  public:
2790    BOOST_STATIC_CONSTEXPR bool is_specialized = true;
2791    //
2792    // Largest and smallest numbers are bounded only by available memory, set
2793    // to zero:
2794    //
2795    static number_type(min)()
2796    {
2797       return number_type();
2798    }
2799    static number_type(max)()
2800    {
2801       return number_type();
2802    }
2803    static number_type          lowest() { return (min)(); }
2804    BOOST_STATIC_CONSTEXPR int  digits       = INT_MAX;
2805    BOOST_STATIC_CONSTEXPR int  digits10     = (INT_MAX / 1000) * 301L;
2806    BOOST_STATIC_CONSTEXPR int  max_digits10 = digits10 + 3;
2807    BOOST_STATIC_CONSTEXPR bool is_signed    = true;
2808    BOOST_STATIC_CONSTEXPR bool is_integer   = true;
2809    BOOST_STATIC_CONSTEXPR bool is_exact     = true;
2810    BOOST_STATIC_CONSTEXPR int  radix        = 2;
2811    static number_type          epsilon() { return number_type(); }
2812    static number_type          round_error() { return number_type(); }
2813    BOOST_STATIC_CONSTEXPR int  min_exponent                  = 0;
2814    BOOST_STATIC_CONSTEXPR int  min_exponent10                = 0;
2815    BOOST_STATIC_CONSTEXPR int  max_exponent                  = 0;
2816    BOOST_STATIC_CONSTEXPR int  max_exponent10                = 0;
2817    BOOST_STATIC_CONSTEXPR bool has_infinity                  = false;
2818    BOOST_STATIC_CONSTEXPR bool has_quiet_NaN                 = false;
2819    BOOST_STATIC_CONSTEXPR bool has_signaling_NaN             = false;
2820    BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm      = denorm_absent;
2821    BOOST_STATIC_CONSTEXPR bool               has_denorm_loss = false;
2822    static number_type                        infinity() { return number_type(); }
2823    static number_type                        quiet_NaN() { return number_type(); }
2824    static number_type                        signaling_NaN() { return number_type(); }
2825    static number_type                        denorm_min() { return number_type(); }
2826    BOOST_STATIC_CONSTEXPR bool               is_iec559       = false;
2827    BOOST_STATIC_CONSTEXPR bool               is_bounded      = false;
2828    BOOST_STATIC_CONSTEXPR bool               is_modulo       = false;
2829    BOOST_STATIC_CONSTEXPR bool               traps           = false;
2830    BOOST_STATIC_CONSTEXPR bool               tinyness_before = false;
2831    BOOST_STATIC_CONSTEXPR float_round_style round_style      = round_toward_zero;
2832 };
2833
2834 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
2835
2836 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2837 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::digits;
2838 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2839 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::digits10;
2840 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2841 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_digits10;
2842 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2843 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_signed;
2844 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2845 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_integer;
2846 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2847 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_exact;
2848 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2849 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::radix;
2850 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2851 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::min_exponent;
2852 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2853 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::min_exponent10;
2854 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2855 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_exponent;
2856 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2857 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_exponent10;
2858 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2859 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_infinity;
2860 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2861 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_quiet_NaN;
2862 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2863 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_signaling_NaN;
2864 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2865 BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_denorm;
2866 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2867 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_denorm_loss;
2868 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2869 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_iec559;
2870 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2871 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_bounded;
2872 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2873 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_modulo;
2874 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2875 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::traps;
2876 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2877 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::tinyness_before;
2878 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2879 BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::round_style;
2880
2881 #endif
2882
2883 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2884 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >
2885 {
2886    typedef boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> number_type;
2887
2888  public:
2889    BOOST_STATIC_CONSTEXPR bool is_specialized = true;
2890    //
2891    // Largest and smallest numbers are bounded only by available memory, set
2892    // to zero:
2893    //
2894    static number_type(min)()
2895    {
2896       return number_type();
2897    }
2898    static number_type(max)()
2899    {
2900       return number_type();
2901    }
2902    static number_type lowest() { return (min)(); }
2903    // Digits are unbounded, use zero for now:
2904    BOOST_STATIC_CONSTEXPR int  digits       = INT_MAX;
2905    BOOST_STATIC_CONSTEXPR int  digits10     = (INT_MAX / 1000) * 301L;
2906    BOOST_STATIC_CONSTEXPR int  max_digits10 = digits10 + 3;
2907    BOOST_STATIC_CONSTEXPR bool is_signed    = true;
2908    BOOST_STATIC_CONSTEXPR bool is_integer   = false;
2909    BOOST_STATIC_CONSTEXPR bool is_exact     = true;
2910    BOOST_STATIC_CONSTEXPR int  radix        = 2;
2911    static number_type          epsilon() { return number_type(); }
2912    static number_type          round_error() { return number_type(); }
2913    BOOST_STATIC_CONSTEXPR int  min_exponent                  = 0;
2914    BOOST_STATIC_CONSTEXPR int  min_exponent10                = 0;
2915    BOOST_STATIC_CONSTEXPR int  max_exponent                  = 0;
2916    BOOST_STATIC_CONSTEXPR int  max_exponent10                = 0;
2917    BOOST_STATIC_CONSTEXPR bool has_infinity                  = false;
2918    BOOST_STATIC_CONSTEXPR bool has_quiet_NaN                 = false;
2919    BOOST_STATIC_CONSTEXPR bool has_signaling_NaN             = false;
2920    BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm      = denorm_absent;
2921    BOOST_STATIC_CONSTEXPR bool               has_denorm_loss = false;
2922    static number_type                        infinity() { return number_type(); }
2923    static number_type                        quiet_NaN() { return number_type(); }
2924    static number_type                        signaling_NaN() { return number_type(); }
2925    static number_type                        denorm_min() { return number_type(); }
2926    BOOST_STATIC_CONSTEXPR bool               is_iec559       = false;
2927    BOOST_STATIC_CONSTEXPR bool               is_bounded      = false;
2928    BOOST_STATIC_CONSTEXPR bool               is_modulo       = false;
2929    BOOST_STATIC_CONSTEXPR bool               traps           = false;
2930    BOOST_STATIC_CONSTEXPR bool               tinyness_before = false;
2931    BOOST_STATIC_CONSTEXPR float_round_style round_style      = round_toward_zero;
2932 };
2933
2934 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
2935
2936 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2937 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::digits;
2938 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2939 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::digits10;
2940 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2941 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_digits10;
2942 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2943 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_signed;
2944 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2945 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_integer;
2946 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2947 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_exact;
2948 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2949 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::radix;
2950 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2951 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::min_exponent;
2952 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2953 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::min_exponent10;
2954 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2955 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_exponent;
2956 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2957 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_exponent10;
2958 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2959 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_infinity;
2960 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2961 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_quiet_NaN;
2962 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2963 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_signaling_NaN;
2964 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2965 BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_denorm;
2966 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2967 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_denorm_loss;
2968 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2969 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_iec559;
2970 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2971 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_bounded;
2972 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2973 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_modulo;
2974 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2975 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::traps;
2976 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2977 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::tinyness_before;
2978 template <boost::multiprecision::expression_template_option ExpressionTemplates>
2979 BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::round_style;
2980
2981 #endif
2982
2983 #ifdef BOOST_MSVC
2984 #pragma warning(pop)
2985 #endif
2986
2987 } // namespace std
2988
2989 #endif