Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:42:31

0001 ///////////////////////////////////////////////////////////////////////////////
0002 //  Copyright 2011 John Maddock.
0003 //  Copyright 2021 Matt Borland. Distributed under the Boost
0004 //  Software License, Version 1.0. (See accompanying file
0005 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_MP_GMP_HPP
0008 #define BOOST_MP_GMP_HPP
0009 
0010 #include <boost/multiprecision/detail/standalone_config.hpp>
0011 #include <boost/multiprecision/number.hpp>
0012 #include <boost/multiprecision/debug_adaptor.hpp>
0013 #include <boost/multiprecision/detail/integer_ops.hpp>
0014 #include <boost/multiprecision/detail/float128_functions.hpp>
0015 #include <boost/multiprecision/detail/digits.hpp>
0016 #include <boost/multiprecision/detail/atomic.hpp>
0017 #include <boost/multiprecision/detail/hash.hpp>
0018 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0019 #include <boost/multiprecision/detail/assert.hpp>
0020 #include <boost/multiprecision/detail/fpclassify.hpp>
0021 #include <boost/multiprecision/detail/string_helpers.hpp>
0022 #include <algorithm>
0023 #include <cctype>
0024 #include <cfloat>
0025 #include <climits>
0026 #include <clocale>
0027 #include <cmath>
0028 #include <cstdint>
0029 #include <cstdlib>
0030 #include <cstring>
0031 #include <iomanip>
0032 #include <iostream>
0033 #include <limits>
0034 #include <memory>
0035 #include <type_traits>
0036 #include <utility>
0037 
0038 //
0039 // Some includes we need from Boost.Math, since we rely on that library to provide these functions:
0040 //
0041 #ifdef BOOST_MP_MATH_AVAILABLE
0042 #include <boost/math/special_functions/asinh.hpp>
0043 #include <boost/math/special_functions/acosh.hpp>
0044 #include <boost/math/special_functions/atanh.hpp>
0045 #include <boost/math/special_functions/cbrt.hpp>
0046 #include <boost/math/special_functions/expm1.hpp>
0047 #include <boost/math/special_functions/gamma.hpp>
0048 #endif
0049 
0050 #ifdef BOOST_MSVC
0051 #pragma warning(push)
0052 #pragma warning(disable : 4127)
0053 #endif
0054 #include <gmp.h>
0055 #ifdef BOOST_MSVC
0056 #pragma warning(pop)
0057 #endif
0058 
0059 #if defined(__MPIR_VERSION) && defined(__MPIR_VERSION_MINOR) && defined(__MPIR_VERSION_PATCHLEVEL)
0060 #define BOOST_MP_MPIR_VERSION (__MPIR_VERSION * 10000 + __MPIR_VERSION_MINOR * 100 + __MPIR_VERSION_PATCHLEVEL)
0061 #else
0062 #define BOOST_MP_MPIR_VERSION 0
0063 #endif
0064 
0065 namespace boost {
0066 namespace multiprecision {
0067 namespace backends {
0068 
0069 #ifdef BOOST_MSVC
0070 // warning C4127: conditional expression is constant
0071 #pragma warning(push)
0072 //#pragma warning(disable : 4127)
0073 #endif
0074 
0075 template <unsigned digits10>
0076 struct gmp_float;
0077 struct gmp_int;
0078 struct gmp_rational;
0079 
0080 } // namespace backends
0081 
0082 template <>
0083 struct number_category<backends::gmp_int> : public std::integral_constant<int, number_kind_integer>
0084 {};
0085 template <>
0086 struct number_category<backends::gmp_rational> : public std::integral_constant<int, number_kind_rational>
0087 {};
0088 template <unsigned digits10>
0089 struct number_category<backends::gmp_float<digits10> > : public std::integral_constant<int, number_kind_floating_point>
0090 {};
0091 
0092 namespace backends {
0093 //
0094 // Within this file, the only functions we mark as noexcept are those that manipulate
0095 // (but don't create) an mpf_t.  All other types may allocate at pretty much any time
0096 // via a user-supplied allocator, and therefore throw.
0097 //
0098 namespace detail {
0099 
0100 template <unsigned digits10>
0101 struct gmp_float_imp
0102 {
0103 #ifdef BOOST_HAS_LONG_LONG
0104    using signed_types = std::tuple<long, long long>          ;
0105    using unsigned_types = std::tuple<unsigned long, unsigned long long>;
0106 #else
0107    using signed_types = std::tuple<long>         ;
0108    using unsigned_types = std::tuple<unsigned long>;
0109 #endif
0110    using float_types = std::tuple<double, long double>;
0111    using exponent_type = long                          ;
0112 
0113    gmp_float_imp() noexcept
0114    {
0115       m_data[0]._mp_d = nullptr; // uninitialized m_data
0116       m_data[0]._mp_prec = 1;
0117    }
0118 
0119    gmp_float_imp(const gmp_float_imp& o)
0120    {
0121       //
0122       // We have to do an init followed by a set here, otherwise *this may be at
0123       // a lower precision than o: seems like mpf_init_set copies just enough bits
0124       // to get the right value, but if it's then used in further calculations
0125       // things go badly wrong!!
0126       //
0127       mpf_init2(m_data, preserve_source_precision() ? mpf_get_prec(o.data()) : boost::multiprecision::detail::digits10_2_2(get_default_precision()));
0128       if (o.m_data[0]._mp_d)
0129          mpf_set(m_data, o.m_data);
0130    }
0131    // rvalue copy
0132    gmp_float_imp(gmp_float_imp&& o) noexcept
0133    {
0134       if ((this->get_default_options() == variable_precision_options::preserve_target_precision) && (mpf_get_prec(o.data()) != boost::multiprecision::detail::digits10_2_2(get_default_precision())))
0135       {
0136          mpf_init2(m_data, boost::multiprecision::detail::digits10_2_2(get_default_precision()));
0137          *this = static_cast<const gmp_float_imp&>(o);
0138       }
0139       else
0140       {
0141          m_data[0] = o.m_data[0];
0142          o.m_data[0]._mp_d = nullptr;
0143       }
0144    }
0145 
0146    gmp_float_imp& operator=(const gmp_float_imp& o)
0147    {
0148       if (m_data[0]._mp_d == nullptr)
0149       {
0150          mpf_init2(m_data, preserve_source_precision() ? mpf_get_prec(o.data()) : boost::multiprecision::detail::digits10_2_2(get_default_precision()));
0151          mpf_set(m_data, o.m_data);
0152       }
0153       else if (preserve_source_precision() && (mpf_get_prec(data()) != mpf_get_prec(o.data())))
0154       {
0155          mpf_t t;
0156          mpf_init2(t, mpf_get_prec(o.data()));
0157          mpf_set(t, o.data());
0158          mpf_swap(data(), t);
0159          mpf_clear(t);
0160       }
0161       else
0162       {
0163          mpf_set(m_data, o.m_data);
0164       }
0165       return *this;
0166    }
0167    // rvalue assign
0168    gmp_float_imp& operator=(gmp_float_imp&& o) noexcept
0169    {
0170       if ((this->get_default_options() == variable_precision_options::preserve_target_precision) && (mpf_get_prec(o.data()) != mpf_get_prec(data())))
0171          *this = static_cast<const gmp_float_imp&>(o);
0172       else
0173       {
0174          mpf_swap(m_data, o.m_data);
0175       }
0176       return *this;
0177    }
0178 
0179 #ifdef BOOST_HAS_LONG_LONG
0180 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
0181    gmp_float_imp& operator=(unsigned long long i)
0182    {
0183       *this = static_cast<unsigned long>(i);
0184       return *this;
0185    }
0186 #else
0187    gmp_float_imp& operator=(unsigned long long i)
0188    {
0189       if (m_data[0]._mp_d == nullptr)
0190       {
0191          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0192       }
0193       unsigned long long mask  = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
0194       unsigned               shift = 0;
0195       mpf_t                  t;
0196       mpf_init2(t, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0197       mpf_set_ui(m_data, 0);
0198       while (i)
0199       {
0200          mpf_set_ui(t, static_cast<unsigned long>(i & mask));
0201          if (shift)
0202             mpf_mul_2exp(t, t, shift);
0203          mpf_add(m_data, m_data, t);
0204          shift += std::numeric_limits<unsigned long>::digits;
0205          i >>= std::numeric_limits<unsigned long>::digits;
0206       }
0207       mpf_clear(t);
0208       return *this;
0209    }
0210 #endif
0211    gmp_float_imp& operator=(long long i)
0212    {
0213       if (m_data[0]._mp_d == nullptr)
0214       {
0215          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0216       }
0217       bool neg = i < 0;
0218       *this    = static_cast<unsigned long long>(boost::multiprecision::detail::unsigned_abs(i));
0219       if (neg)
0220          mpf_neg(m_data, m_data);
0221       return *this;
0222    }
0223 #endif
0224    gmp_float_imp& operator=(unsigned long i)
0225    {
0226       if (m_data[0]._mp_d == nullptr)
0227       {
0228          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0229       }
0230       mpf_set_ui(m_data, i);
0231       return *this;
0232    }
0233    gmp_float_imp& operator=(long i)
0234    {
0235       if (m_data[0]._mp_d == nullptr)
0236       {
0237          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0238       }
0239       mpf_set_si(m_data, i);
0240       return *this;
0241    }
0242 #ifdef BOOST_HAS_INT128
0243    gmp_float_imp& operator=(uint128_type i)
0244    {
0245       if (m_data[0]._mp_d == nullptr)
0246       {
0247          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0248       }
0249       unsigned long      mask  = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
0250       unsigned           shift = 0;
0251       mpf_t              t;
0252       mpf_init2(t, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0253       mpf_set_ui(m_data, 0);
0254       while (i)
0255       {
0256          mpf_set_ui(t, static_cast<unsigned long>(i & mask));
0257          if (shift)
0258             mpf_mul_2exp(t, t, shift);
0259          mpf_add(m_data, m_data, t);
0260          shift += std::numeric_limits<unsigned long>::digits;
0261          i >>= std::numeric_limits<unsigned long>::digits;
0262       }
0263       mpf_clear(t);
0264       return *this;
0265    }
0266    gmp_float_imp& operator=(int128_type i)
0267    {
0268       if (m_data[0]._mp_d == nullptr)
0269       {
0270          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0271       }
0272       bool neg = i < 0;
0273       *this    = static_cast<uint128_type>(boost::multiprecision::detail::unsigned_abs(i));
0274       if (neg)
0275          mpf_neg(m_data, m_data);
0276       return *this;
0277    }
0278 #endif
0279    gmp_float_imp& operator=(double d)
0280    {
0281       if (m_data[0]._mp_d == nullptr)
0282       {
0283          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0284       }
0285       mpf_set_d(m_data, d);
0286       return *this;
0287    }
0288    template <class F>
0289    gmp_float_imp& assign_float(F a)
0290    {
0291       BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp;
0292 
0293       if (m_data[0]._mp_d == nullptr)
0294       {
0295          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0296       }
0297 
0298       if (a == 0)
0299       {
0300          mpf_set_si(m_data, 0);
0301          return *this;
0302       }
0303 
0304       if (a == 1)
0305       {
0306          mpf_set_si(m_data, 1);
0307          return *this;
0308       }
0309 
0310       BOOST_MP_ASSERT(!BOOST_MP_ISINF(a));
0311       BOOST_MP_ASSERT(!BOOST_MP_ISNAN(a));
0312 
0313       int         e;
0314       F f, term;
0315       mpf_set_ui(m_data, 0u);
0316 
0317       f = frexp(a, &e);
0318 
0319       constexpr int shift = std::numeric_limits<int>::digits - 1;
0320 
0321       while (f)
0322       {
0323          // extract int sized bits from f:
0324          f    = ldexp(f, shift);
0325          term = floor(f);
0326          e -= shift;
0327          mpf_mul_2exp(m_data, m_data, shift);
0328          if (term > 0)
0329             mpf_add_ui(m_data, m_data, static_cast<unsigned>(term));
0330          else
0331             mpf_sub_ui(m_data, m_data, static_cast<unsigned>(-term));
0332          f -= term;
0333       }
0334       if (e > 0)
0335          mpf_mul_2exp(m_data, m_data, e);
0336       else if (e < 0)
0337          mpf_div_2exp(m_data, m_data, -e);
0338       return *this;
0339    }
0340    gmp_float_imp& operator=(long double a)
0341    {
0342       return assign_float(a);
0343    }
0344 #ifdef BOOST_HAS_FLOAT128
0345    gmp_float_imp& operator= (float128_type a)
0346    {
0347       return assign_float(a);
0348    }
0349 #endif
0350    gmp_float_imp& operator=(const char* s)
0351    {
0352       if (m_data[0]._mp_d == nullptr)
0353       {
0354          mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
0355       }
0356       if (s && (*s == '+'))
0357          ++s;  // Leading "+" sign not supported by mpf_set_str:
0358       //
0359       // Validate the string as mpf_set_str does a poor job of this:
0360       //
0361       static const char* digits = "0123456789";
0362       const char* p = s;
0363       if (*s == '-')
0364          ++s;
0365       s += boost::multiprecision::detail::find_first_not_of(s, s + std::strlen(s), digits);
0366       std::lconv const* l = std::localeconv();
0367       std::size_t len = strlen(l->decimal_point);
0368       if (std::find(l->decimal_point, l->decimal_point + len, *s) != l->decimal_point + len)
0369       {
0370          ++s;
0371          s += boost::multiprecision::detail::find_first_not_of(s, s + std::strlen(s), digits);
0372       }
0373       if ((*s == 'e') || (*s == 'E'))
0374       {
0375          ++s;
0376          if ((*s == '+') || (*s == '-'))
0377             ++s;
0378          s += boost::multiprecision::detail::find_first_not_of(s, s + std::strlen(s), digits);
0379       }
0380       if(*s)
0381          BOOST_MP_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid floating point number.")));
0382 
0383       s = p;
0384 
0385       if (0 != mpf_set_str(m_data, s, 10))
0386          BOOST_MP_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid floating point number.")));
0387       return *this;
0388    }
0389    void swap(gmp_float_imp& o) noexcept
0390    {
0391       mpf_swap(m_data, o.m_data);
0392    }
0393    std::string str(std::streamsize digits, std::ios_base::fmtflags f) const
0394    {
0395       BOOST_MP_ASSERT(m_data[0]._mp_d);
0396 
0397       bool            scientific = (f & std::ios_base::scientific) == std::ios_base::scientific;
0398       bool            fixed      = (f & std::ios_base::fixed) == std::ios_base::fixed;
0399       std::streamsize org_digits(digits);
0400 
0401       if (scientific && digits)
0402          ++digits;
0403 
0404       std::string result;
0405       mp_exp_t    e;
0406       void* (*alloc_func_ptr)(size_t);
0407       void* (*realloc_func_ptr)(void*, size_t, size_t);
0408       void (*free_func_ptr)(void*, size_t);
0409       mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
0410 
0411       if (mpf_sgn(m_data) == 0)
0412       {
0413          e      = 0;
0414          result = "0";
0415          if (fixed && digits)
0416             ++digits;
0417       }
0418       else
0419       {
0420          char* ps = mpf_get_str(nullptr, &e, 10, static_cast<std::size_t>(digits), m_data);
0421          --e; // To match with what our formatter expects.
0422          if (fixed)
0423          {
0424             // Oops we actually need a different number of digits to what we asked for:
0425             (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
0426             digits += e + 1;
0427             if (digits == 0)
0428             {
0429                // We need to get *all* the digits and then possibly round up,
0430                // we end up with either "0" or "1" as the result.
0431                ps = mpf_get_str(nullptr, &e, 10, 0, m_data);
0432                --e;
0433                unsigned offset = *ps == '-' ? 1 : 0;
0434                if (ps[offset] > '5')
0435                {
0436                   ++e;
0437                   ps[offset]     = '1';
0438                   ps[offset + 1] = 0;
0439                }
0440                else if (ps[offset] == '5')
0441                {
0442                   unsigned i        = offset + 1;
0443                   bool     round_up = false;
0444                   while (ps[i] != 0)
0445                   {
0446                      if (ps[i] != '0')
0447                      {
0448                         round_up = true;
0449                         break;
0450                      }
0451                      ++i;
0452                   }
0453                   if (round_up)
0454                   {
0455                      ++e;
0456                      ps[offset]     = '1';
0457                      ps[offset + 1] = 0;
0458                   }
0459                   else
0460                   {
0461                      ps[offset]     = '0';
0462                      ps[offset + 1] = 0;
0463                   }
0464                }
0465                else
0466                {
0467                   ps[offset]     = '0';
0468                   ps[offset + 1] = 0;
0469                }
0470             }
0471             else if (digits > 0)
0472             {
0473                mp_exp_t old_e = e;
0474                ps             = mpf_get_str(nullptr, &e, 10, static_cast<std::size_t>(digits), m_data);
0475                --e; // To match with what our formatter expects.
0476                if (old_e > e)
0477                {
0478                   // in some cases, when we ask for more digits of precision, it will
0479                   // change the number of digits to the left of the decimal, if that
0480                   // happens, account for it here.
0481                   // example: cout << fixed << setprecision(3) << mpf_float_50("99.9809")
0482                   digits -= old_e - e;
0483                   (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
0484                   ps = mpf_get_str(nullptr, &e, 10, static_cast<std::size_t>(digits), m_data);
0485                   --e; // To match with what our formatter expects.
0486                }
0487             }
0488             else
0489             {
0490                ps = mpf_get_str(nullptr, &e, 10, 1, m_data);
0491                --e;
0492                unsigned offset = *ps == '-' ? 1 : 0;
0493                ps[offset]      = '0';
0494                ps[offset + 1]  = 0;
0495             }
0496          }
0497          result = ps;
0498          (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
0499       }
0500       boost::multiprecision::detail::format_float_string(result, e, org_digits, f, mpf_sgn(m_data) == 0);
0501       return result;
0502    }
0503    ~gmp_float_imp() noexcept
0504    {
0505       if (m_data[0]._mp_d)
0506       {
0507          mpf_clear(m_data);
0508       }
0509    }
0510    void negate() noexcept
0511    {
0512       BOOST_MP_ASSERT(m_data[0]._mp_d);
0513       mpf_neg(m_data, m_data);
0514    }
0515    int compare(const gmp_float<digits10>& o) const noexcept
0516    {
0517       BOOST_MP_ASSERT(m_data[0]._mp_d && o.m_data[0]._mp_d);
0518       return mpf_cmp(m_data, o.m_data);
0519    }
0520    int compare(long i) const noexcept
0521    {
0522       BOOST_MP_ASSERT(m_data[0]._mp_d);
0523       return mpf_cmp_si(m_data, i);
0524    }
0525    int compare(unsigned long i) const noexcept
0526    {
0527       BOOST_MP_ASSERT(m_data[0]._mp_d);
0528       return mpf_cmp_ui(m_data, i);
0529    }
0530    template <class V>
0531    typename std::enable_if<boost::multiprecision::detail::is_arithmetic<V>::value, int>::type compare(V v) const
0532    {
0533       gmp_float<digits10> d;
0534       d = v;
0535       return compare(d);
0536    }
0537    mpf_t& data() noexcept
0538    {
0539       BOOST_MP_ASSERT(m_data[0]._mp_d);
0540       return m_data;
0541    }
0542    const mpf_t& data() const noexcept
0543    {
0544       BOOST_MP_ASSERT(m_data[0]._mp_d);
0545       return m_data;
0546    }
0547 
0548  protected:
0549    mpf_t            m_data;
0550    static unsigned& get_default_precision() noexcept
0551    {
0552       static BOOST_MP_THREAD_LOCAL unsigned val(get_global_default_precision());
0553       return val;
0554    }
0555    static boost::multiprecision::detail::precision_type& get_global_default_precision() noexcept
0556    {
0557       static boost::multiprecision::detail::precision_type val(50);
0558       return val;
0559    }
0560 #ifndef BOOST_MT_NO_ATOMIC_INT
0561    static std::atomic<variable_precision_options>& get_global_default_options() noexcept
0562 #else
0563    static variable_precision_options& get_global_default_options() noexcept
0564 #endif
0565    {
0566 #ifndef BOOST_MT_NO_ATOMIC_INT
0567       static std::atomic<variable_precision_options> val{variable_precision_options::preserve_related_precision};
0568 #else
0569       static variable_precision_options val{variable_precision_options::preserve_related_precision};
0570 #endif
0571       return val;
0572    }
0573    static variable_precision_options& get_default_options()noexcept
0574    {
0575       static BOOST_MP_THREAD_LOCAL variable_precision_options val(get_global_default_options());
0576       return val;
0577    }
0578    static bool preserve_source_precision() noexcept
0579    {
0580       return get_default_options() >= variable_precision_options::preserve_source_precision;
0581    }
0582 };
0583 
0584 class gmp_char_ptr
0585 {
0586 private:
0587    char* ptr_val;
0588    void* (*alloc_func_ptr)(size_t);
0589    void* (*realloc_func_ptr)(void*, size_t, size_t);
0590    void  (*free_func_ptr)(void*, size_t);
0591 
0592 public:
0593    gmp_char_ptr() = delete;
0594    explicit gmp_char_ptr(char* val_) : ptr_val {val_}
0595    {
0596       mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
0597    }
0598    ~gmp_char_ptr() noexcept
0599    {
0600       (*free_func_ptr)((void*)ptr_val, sizeof(*ptr_val));
0601       ptr_val = nullptr;
0602    }
0603    inline char* get() noexcept { return ptr_val; }
0604 };
0605 
0606 } // namespace detail
0607 
0608 template <unsigned digits10>
0609 struct gmp_float : public detail::gmp_float_imp<digits10>
0610 {
0611    gmp_float()
0612    {
0613       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0614    }
0615    gmp_float(const gmp_float& o) : detail::gmp_float_imp<digits10>(o) {}
0616    template <unsigned D>
0617    gmp_float(const gmp_float<D>& o, typename std::enable_if<D <= digits10>::type* = nullptr);
0618    template <unsigned D>
0619    explicit gmp_float(const gmp_float<D>& o, typename std::enable_if<!(D <= digits10)>::type* = nullptr);
0620    gmp_float(const gmp_int& o);
0621    gmp_float(const gmp_rational& o);
0622    gmp_float(const mpf_t val)
0623    {
0624       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0625       mpf_set(this->m_data, val);
0626    }
0627    gmp_float(const mpz_t val)
0628    {
0629       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0630       mpf_set_z(this->m_data, val);
0631    }
0632    gmp_float(const mpq_t val)
0633    {
0634       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0635       mpf_set_q(this->m_data, val);
0636    }
0637    // rvalue copy
0638    gmp_float(gmp_float&& o) noexcept : detail::gmp_float_imp<digits10>(static_cast<detail::gmp_float_imp<digits10>&&>(o))
0639    {}
0640    gmp_float& operator=(const gmp_float& o)
0641    {
0642       *static_cast<detail::gmp_float_imp<digits10>*>(this) = static_cast<detail::gmp_float_imp<digits10> const&>(o);
0643       return *this;
0644    }
0645    gmp_float& operator=(gmp_float&& o) noexcept
0646    {
0647       *static_cast<detail::gmp_float_imp<digits10>*>(this) = static_cast<detail::gmp_float_imp<digits10>&&>(o);
0648       return *this;
0649    }
0650    template <unsigned D>
0651    gmp_float& operator=(const gmp_float<D>& o);
0652    gmp_float& operator=(const gmp_int& o);
0653    gmp_float& operator=(const gmp_rational& o);
0654    gmp_float& operator=(const mpf_t val)
0655    {
0656       if (this->m_data[0]._mp_d == nullptr)
0657          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0658       mpf_set(this->m_data, val);
0659       return *this;
0660    }
0661    gmp_float& operator=(const mpz_t val)
0662    {
0663       if (this->m_data[0]._mp_d == nullptr)
0664          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0665       mpf_set_z(this->m_data, val);
0666       return *this;
0667    }
0668    gmp_float& operator=(const mpq_t val)
0669    {
0670       if (this->m_data[0]._mp_d == nullptr)
0671          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0672       mpf_set_q(this->m_data, val);
0673       return *this;
0674    }
0675    template <class V>
0676    typename std::enable_if<std::is_assignable<detail::gmp_float_imp<digits10>, V>::value, gmp_float&>::type operator=(const V& v)
0677    {
0678       *static_cast<detail::gmp_float_imp<digits10>*>(this) = v;
0679       return *this;
0680    }
0681 };
0682 
0683 template <>
0684 struct gmp_float<0> : public detail::gmp_float_imp<0>
0685 {
0686    //
0687    // We have a problem with mpf_t in that the precision we request isn't what we get.
0688    // As a result the front end can end up chasing it's tail trying to create a variable
0689    // with the the correct precision to hold the result of an expression.
0690    // See: https://github.com/boostorg/multiprecision/issues/164
0691    // The problem is made worse by the fact that our conversions from base10 to 2 and
0692    // vice-versa do not exactly round trip (and probably never will).
0693    // The workaround is to keep track of the precision requested, and always return
0694    // that as the current actual precision.
0695    //
0696  private:
0697    unsigned requested_precision;
0698 
0699  public:
0700    gmp_float() : requested_precision(get_default_precision())
0701    {
0702       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
0703    }
0704    gmp_float(const mpf_t val) : requested_precision(get_default_precision())
0705    {
0706       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
0707       mpf_set(this->m_data, val);
0708    }
0709    gmp_float(const mpz_t val) : requested_precision(get_default_precision())
0710    {
0711       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
0712       mpf_set_z(this->m_data, val);
0713    }
0714    gmp_float(const mpq_t val) : requested_precision(get_default_precision())
0715    {
0716       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
0717       mpf_set_q(this->m_data, val);
0718    }
0719    gmp_float(const gmp_float& o) : detail::gmp_float_imp<0>(o), requested_precision(preserve_source_precision() ? o.requested_precision : get_default_precision()) {}
0720    template <unsigned D>
0721    gmp_float(const gmp_float<D>& o)
0722    {
0723       mpf_init2(this->m_data, preserve_related_precision() ? mpf_get_prec(o.data()) : multiprecision::detail::digits10_2_2(get_default_precision()));
0724       mpf_set(this->m_data, o.data());
0725       requested_precision = preserve_related_precision() ? D : get_default_precision();
0726    }
0727    // rvalue copy
0728    gmp_float(gmp_float&& o) noexcept : detail::gmp_float_imp<0>(static_cast<detail::gmp_float_imp<0>&&>(o)), requested_precision((this->get_default_options() != variable_precision_options::preserve_target_precision) ? o.requested_precision : get_default_precision())
0729    {}
0730    gmp_float(const gmp_int& o);
0731    gmp_float(const gmp_rational& o);
0732    gmp_float(const gmp_float& o, unsigned digits10) : requested_precision(digits10)
0733    {
0734       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0735       mpf_set(this->m_data, o.data());
0736    }
0737    template <class V>
0738    gmp_float(const V& o, unsigned digits10) : requested_precision(digits10)
0739    {
0740       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0741       *this = o;
0742    }
0743 
0744 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
0745    //
0746    // Support for new types in C++17
0747    //
0748    template <class Traits>
0749    gmp_float(const std::basic_string_view<char, Traits>& o, unsigned digits10) : requested_precision(digits10)
0750    {
0751       using default_ops::assign_from_string_view;
0752       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
0753       assign_from_string_view(*this, o);
0754    }
0755 #endif
0756    gmp_float& operator=(const gmp_float& o)
0757    {
0758       *static_cast<detail::gmp_float_imp<0>*>(this) = static_cast<detail::gmp_float_imp<0> const&>(o);
0759       if(preserve_source_precision())
0760          requested_precision = o.requested_precision;
0761       return *this;
0762    }
0763    // rvalue copy
0764    gmp_float& operator=(gmp_float&& o) noexcept
0765    {
0766       *static_cast<detail::gmp_float_imp<0>*>(this) = static_cast<detail::gmp_float_imp<0>&&>(o);
0767       if ((this->get_default_options() != variable_precision_options::preserve_target_precision))
0768          requested_precision = o.requested_precision;
0769       return *this;
0770    }
0771    template <unsigned D>
0772    gmp_float& operator=(const gmp_float<D>& o)
0773    {
0774       if (this->m_data[0]._mp_d == nullptr)
0775       {
0776          mpf_init2(this->m_data, preserve_related_precision() ? mpf_get_prec(o.data()) : multiprecision::detail::digits10_2_2(get_default_precision()));
0777       }
0778       else if(preserve_related_precision())
0779       {
0780          mpf_set_prec(this->m_data, mpf_get_prec(o.data()));
0781       }
0782       mpf_set(this->m_data, o.data());
0783       if (preserve_related_precision())
0784          requested_precision = D;
0785       return *this;
0786    }
0787    gmp_float& operator=(const gmp_int& o);
0788    gmp_float& operator=(const gmp_rational& o);
0789    gmp_float& operator=(const mpf_t val)
0790    {
0791       if (this->m_data[0]._mp_d == nullptr)
0792       {
0793          requested_precision = get_default_precision();
0794          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
0795       }
0796       mpf_set(this->m_data, val);
0797       return *this;
0798    }
0799    gmp_float& operator=(const mpz_t val)
0800    {
0801       if (this->m_data[0]._mp_d == nullptr)
0802       {
0803          requested_precision = get_default_precision();
0804          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
0805       }
0806       mpf_set_z(this->m_data, val);
0807       return *this;
0808    }
0809    gmp_float& operator=(const mpq_t val)
0810    {
0811       if (this->m_data[0]._mp_d == nullptr)
0812       {
0813          requested_precision = get_default_precision();
0814          mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
0815       }
0816       mpf_set_q(this->m_data, val);
0817       return *this;
0818    }
0819    template <class V>
0820    typename std::enable_if<std::is_assignable<detail::gmp_float_imp<0>, V>::value, gmp_float&>::type operator=(const V& v)
0821    {
0822       constexpr unsigned d10 = std::is_floating_point<V>::value ?
0823          std::numeric_limits<V>::digits10 :
0824          std::numeric_limits<V>::digits10 ? 1 + std::numeric_limits<V>::digits10 :
0825          1 + boost::multiprecision::detail::digits2_2_10(std::numeric_limits<V>::digits);
0826       if((thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision) && (precision() < d10))
0827          this->precision(d10);
0828       *static_cast<detail::gmp_float_imp<0>*>(this) = v;
0829       return *this;
0830    }
0831    static unsigned default_precision() noexcept
0832    {
0833       return get_global_default_precision();
0834    }
0835    static void default_precision(unsigned v) noexcept
0836    {
0837       get_global_default_precision() = v;
0838    }
0839    static unsigned thread_default_precision() noexcept
0840    {
0841       return get_default_precision();
0842    }
0843    static void thread_default_precision(unsigned v) noexcept
0844    {
0845       get_default_precision() = v;
0846    }
0847    unsigned precision() const noexcept
0848    {
0849       return requested_precision;
0850    }
0851    void precision(unsigned digits10) noexcept
0852    {
0853       requested_precision = digits10;
0854       mpf_set_prec(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
0855    }
0856    //
0857    // Variable precision options:
0858    //
0859    static variable_precision_options default_variable_precision_options()noexcept
0860    {
0861       return get_global_default_options();
0862    }
0863    static variable_precision_options thread_default_variable_precision_options()noexcept
0864    {
0865       return get_default_options();
0866    }
0867    static void default_variable_precision_options(variable_precision_options opts)
0868    {
0869       get_global_default_options() = opts;
0870    }
0871    static void thread_default_variable_precision_options(variable_precision_options opts)
0872    {
0873       get_default_options() = opts;
0874    }
0875    static bool preserve_source_precision()
0876    {
0877       return get_default_options() >= variable_precision_options::preserve_source_precision;
0878    }
0879    static bool preserve_related_precision()
0880    {
0881       return get_default_options() >= variable_precision_options::preserve_related_precision;
0882    }
0883    static bool preserve_all_precision()
0884    {
0885       return get_default_options() >= variable_precision_options::preserve_all_precision;
0886    }
0887    //
0888    // swap:
0889    //
0890    void swap(gmp_float& o)
0891    {
0892       std::swap(requested_precision, o.requested_precision);
0893       gmp_float_imp<0>::swap(o);
0894    }
0895 };
0896 
0897 template <unsigned digits10, class T>
0898 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_eq(const gmp_float<digits10>& a, const T& b) noexcept
0899 {
0900    return a.compare(b) == 0;
0901 }
0902 template <unsigned digits10, class T>
0903 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_lt(const gmp_float<digits10>& a, const T& b) noexcept
0904 {
0905    return a.compare(b) < 0;
0906 }
0907 template <unsigned digits10, class T>
0908 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_gt(const gmp_float<digits10>& a, const T& b) noexcept
0909 {
0910    return a.compare(b) > 0;
0911 }
0912 
0913 template <unsigned D1, unsigned D2>
0914 inline void eval_add(gmp_float<D1>& result, const gmp_float<D2>& o)
0915 {
0916    mpf_add(result.data(), result.data(), o.data());
0917 }
0918 template <unsigned D1, unsigned D2>
0919 inline void eval_subtract(gmp_float<D1>& result, const gmp_float<D2>& o)
0920 {
0921    mpf_sub(result.data(), result.data(), o.data());
0922 }
0923 template <unsigned D1, unsigned D2>
0924 inline void eval_multiply(gmp_float<D1>& result, const gmp_float<D2>& o)
0925 {
0926    mpf_mul(result.data(), result.data(), o.data());
0927 }
0928 template <unsigned digits10>
0929 inline bool eval_is_zero(const gmp_float<digits10>& val) noexcept
0930 {
0931    return mpf_sgn(val.data()) == 0;
0932 }
0933 template <unsigned D1, unsigned D2>
0934 inline void eval_divide(gmp_float<D1>& result, const gmp_float<D2>& o)
0935 {
0936    if (eval_is_zero(o))
0937       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
0938    mpf_div(result.data(), result.data(), o.data());
0939 }
0940 template <unsigned digits10>
0941 inline void eval_add(gmp_float<digits10>& result, unsigned long i)
0942 {
0943    mpf_add_ui(result.data(), result.data(), i);
0944 }
0945 template <unsigned digits10>
0946 inline void eval_subtract(gmp_float<digits10>& result, unsigned long i)
0947 {
0948    mpf_sub_ui(result.data(), result.data(), i);
0949 }
0950 template <unsigned digits10>
0951 inline void eval_multiply(gmp_float<digits10>& result, unsigned long i)
0952 {
0953    mpf_mul_ui(result.data(), result.data(), i);
0954 }
0955 template <unsigned digits10>
0956 inline void eval_divide(gmp_float<digits10>& result, unsigned long i)
0957 {
0958    if (i == 0)
0959       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
0960    mpf_div_ui(result.data(), result.data(), i);
0961 }
0962 template <unsigned digits10>
0963 inline void eval_add(gmp_float<digits10>& result, long i)
0964 {
0965    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
0966 
0967    if (i > 0)
0968       mpf_add_ui(result.data(), result.data(), static_cast<local_uint_type>(i));
0969    else if (i < 0)
0970       mpf_sub_ui(result.data(), result.data(), static_cast<local_uint_type>(-i));
0971 }
0972 template <unsigned digits10>
0973 inline void eval_subtract(gmp_float<digits10>& result, long i)
0974 {
0975    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
0976 
0977    if (i > 0)
0978       mpf_sub_ui(result.data(), result.data(), static_cast<local_uint_type>(i));
0979    else if (i < 0)
0980       mpf_add_ui(result.data(), result.data(), static_cast<local_uint_type>(-i));
0981 }
0982 template <unsigned digits10>
0983 inline void eval_multiply(gmp_float<digits10>& result, long i)
0984 {
0985    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
0986 
0987    mpf_mul_ui(result.data(), result.data(), static_cast<local_uint_type>(boost::multiprecision::detail::unsigned_abs(i)));
0988 
0989    if (i < 0)
0990       mpf_neg(result.data(), result.data());
0991 }
0992 template <unsigned digits10>
0993 inline void eval_divide(gmp_float<digits10>& result, long i)
0994 {
0995    if (i == 0)
0996       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
0997 
0998    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
0999 
1000    mpf_div_ui(result.data(), result.data(), static_cast<local_uint_type>(boost::multiprecision::detail::unsigned_abs(i)));
1001 
1002    if (i < 0)
1003       mpf_neg(result.data(), result.data());
1004 }
1005 //
1006 // Specialised 3 arg versions of the basic operators:
1007 //
1008 template <unsigned D1, unsigned D2, unsigned D3>
1009 inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
1010 {
1011    mpf_add(a.data(), x.data(), y.data());
1012 }
1013 template <unsigned D1, unsigned D2>
1014 inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
1015 {
1016    mpf_add_ui(a.data(), x.data(), y);
1017 }
1018 template <unsigned D1, unsigned D2>
1019 inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
1020 {
1021    if (y < 0)
1022       mpf_sub_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
1023    else
1024       mpf_add_ui(a.data(), x.data(), y);
1025 }
1026 template <unsigned D1, unsigned D2>
1027 inline void eval_add(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
1028 {
1029    mpf_add_ui(a.data(), y.data(), x);
1030 }
1031 template <unsigned D1, unsigned D2>
1032 inline void eval_add(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
1033 {
1034    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1035 
1036    if (x < 0)
1037    {
1038       mpf_ui_sub(a.data(), static_cast<local_uint_type>(-x), y.data());
1039       mpf_neg(a.data(), a.data());
1040    }
1041    else
1042       mpf_add_ui(a.data(), y.data(), static_cast<local_uint_type>(x));
1043 }
1044 template <unsigned D1, unsigned D2, unsigned D3>
1045 inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
1046 {
1047    mpf_sub(a.data(), x.data(), y.data());
1048 }
1049 template <unsigned D1, unsigned D2>
1050 inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
1051 {
1052    mpf_sub_ui(a.data(), x.data(), y);
1053 }
1054 template <unsigned D1, unsigned D2>
1055 inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
1056 {
1057    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1058 
1059    if (y < 0)
1060       mpf_add_ui(a.data(), x.data(), static_cast<local_uint_type>(-y));
1061    else
1062       mpf_sub_ui(a.data(), x.data(), static_cast<local_uint_type>(y));
1063 }
1064 template <unsigned D1, unsigned D2>
1065 inline void eval_subtract(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
1066 {
1067    mpf_ui_sub(a.data(), x, y.data());
1068 }
1069 template <unsigned D1, unsigned D2>
1070 inline void eval_subtract(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
1071 {
1072    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1073 
1074    if (x < 0)
1075    {
1076       mpf_add_ui(a.data(), y.data(), static_cast<local_uint_type>(-x));
1077       mpf_neg(a.data(), a.data());
1078    }
1079    else
1080       mpf_ui_sub(a.data(), static_cast<local_uint_type>(x), y.data());
1081 }
1082 
1083 template <unsigned D1, unsigned D2, unsigned D3>
1084 inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
1085 {
1086    mpf_mul(a.data(), x.data(), y.data());
1087 }
1088 template <unsigned D1, unsigned D2>
1089 inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
1090 {
1091    mpf_mul_ui(a.data(), x.data(), y);
1092 }
1093 template <unsigned D1, unsigned D2>
1094 inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
1095 {
1096    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1097 
1098    if (y < 0)
1099    {
1100       mpf_mul_ui(a.data(), x.data(), static_cast<local_uint_type>(-y));
1101       a.negate();
1102    }
1103    else
1104       mpf_mul_ui(a.data(), x.data(), static_cast<local_uint_type>(y));
1105 }
1106 template <unsigned D1, unsigned D2>
1107 inline void eval_multiply(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
1108 {
1109    mpf_mul_ui(a.data(), y.data(), x);
1110 }
1111 template <unsigned D1, unsigned D2>
1112 inline void eval_multiply(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
1113 {
1114    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1115 
1116    if (x < 0)
1117    {
1118       mpf_mul_ui(a.data(), y.data(), static_cast<local_uint_type>(-x));
1119       mpf_neg(a.data(), a.data());
1120    }
1121    else
1122       mpf_mul_ui(a.data(), y.data(), static_cast<local_uint_type>(x));
1123 }
1124 
1125 template <unsigned D1, unsigned D2, unsigned D3>
1126 inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y)
1127 {
1128    if (eval_is_zero(y))
1129       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1130    mpf_div(a.data(), x.data(), y.data());
1131 }
1132 template <unsigned D1, unsigned D2>
1133 inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y)
1134 {
1135    if (y == 0)
1136       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1137    mpf_div_ui(a.data(), x.data(), y);
1138 }
1139 template <unsigned D1, unsigned D2>
1140 inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, long y)
1141 {
1142    if (y == 0)
1143       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1144 
1145    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1146 
1147    if (y < 0)
1148    {
1149       mpf_div_ui(a.data(), x.data(), static_cast<local_uint_type>(-y));
1150       a.negate();
1151    }
1152    else
1153       mpf_div_ui(a.data(), x.data(), static_cast<local_uint_type>(y));
1154 }
1155 template <unsigned D1, unsigned D2>
1156 inline void eval_divide(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y)
1157 {
1158    if (eval_is_zero(y))
1159       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1160    mpf_ui_div(a.data(), x, y.data());
1161 }
1162 template <unsigned D1, unsigned D2>
1163 inline void eval_divide(gmp_float<D1>& a, long x, const gmp_float<D2>& y)
1164 {
1165    if (eval_is_zero(y))
1166       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1167    if (x < 0)
1168    {
1169       mpf_ui_div(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data());
1170       mpf_neg(a.data(), a.data());
1171    }
1172    else
1173    {
1174       using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1175 
1176       mpf_ui_div(a.data(), static_cast<local_uint_type>(x), y.data());
1177    }
1178 }
1179 
1180 template <unsigned digits10>
1181 inline int eval_get_sign(const gmp_float<digits10>& val) noexcept
1182 {
1183    return mpf_sgn(val.data());
1184 }
1185 
1186 template <unsigned digits10>
1187 inline void eval_convert_to(unsigned long* result, const gmp_float<digits10>& val) noexcept
1188 {
1189    if (0 == mpf_fits_ulong_p(val.data()))
1190       *result = (std::numeric_limits<unsigned long>::max)();
1191    else
1192       *result = static_cast<unsigned long>(mpf_get_ui(val.data()));
1193 }
1194 template <unsigned digits10>
1195 inline void eval_convert_to(long* result, const gmp_float<digits10>& val) noexcept
1196 {
1197    if (0 == mpf_fits_slong_p(val.data()))
1198    {
1199       *result = (std::numeric_limits<long>::max)();
1200       *result *= mpf_sgn(val.data());
1201    }
1202    else
1203       *result = static_cast<long>(mpf_get_si(val.data()));
1204 }
1205 #ifdef BOOST_MP_STANDALONE
1206 template <unsigned digits10>
1207 inline void eval_convert_to(long double* result, const gmp_float<digits10>& val) noexcept
1208 {
1209    mp_exp_t exp = 0;
1210 
1211    detail::gmp_char_ptr val_char_ptr {mpf_get_str(nullptr, &exp, 10, LDBL_DIG, val.data())};
1212 
1213    auto temp_string = std::string(val_char_ptr.get());
1214    if(exp > 0 && static_cast<std::size_t>(exp) < temp_string.size())
1215    {
1216       if(temp_string.front() == '-')
1217       {
1218          ++exp;
1219       }
1220 
1221       temp_string.insert(static_cast<std::size_t>(exp), static_cast<std::size_t>(1u), '.');
1222    }
1223 
1224    *result = std::strtold(temp_string.c_str(), nullptr);
1225 
1226    if((temp_string.size() == 2ul && *result < 0.0l) ||
1227       (static_cast<std::size_t>(exp) > temp_string.size()))
1228    {
1229       *result *= std::pow(10l, exp-1);
1230    }
1231 }
1232 #endif // BOOST_MP_STANDALONE
1233 template <unsigned digits10>
1234 inline void eval_convert_to(double* result, const gmp_float<digits10>& val) noexcept
1235 {
1236    *result = mpf_get_d(val.data());
1237 }
1238 #ifdef BOOST_HAS_LONG_LONG
1239 template <unsigned digits10>
1240 inline void eval_convert_to(long long* result, const gmp_float<digits10>& val)
1241 {
1242    gmp_float<digits10> t(val);
1243    if (eval_get_sign(t) < 0)
1244       t.negate();
1245 
1246    long digits = std::numeric_limits<long long>::digits - std::numeric_limits<long>::digits;
1247 
1248    if (digits > 0)
1249       mpf_div_2exp(t.data(), t.data(), digits);
1250 
1251    if (!mpf_fits_slong_p(t.data()))
1252    {
1253       if (eval_get_sign(val) < 0)
1254          *result = (std::numeric_limits<long long>::min)();
1255       else
1256          *result = (std::numeric_limits<long long>::max)();
1257       return;
1258    };
1259 
1260    *result = mpf_get_si(t.data());
1261    while (digits > 0)
1262    {
1263       *result <<= digits;
1264       digits -= std::numeric_limits<unsigned long>::digits;
1265       mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits<unsigned long>::digits : std::numeric_limits<unsigned long>::digits + digits);
1266       unsigned long l = static_cast<unsigned long>(mpf_get_ui(t.data()));
1267       if (digits < 0)
1268          l >>= -digits;
1269       *result |= l;
1270    }
1271    if (eval_get_sign(val) < 0)
1272       *result = -*result;
1273 }
1274 template <unsigned digits10>
1275 inline void eval_convert_to(unsigned long long* result, const gmp_float<digits10>& val)
1276 {
1277    gmp_float<digits10> t(val);
1278 
1279    long digits = std::numeric_limits<long long>::digits - std::numeric_limits<long>::digits;
1280 
1281    if (digits > 0)
1282       mpf_div_2exp(t.data(), t.data(), digits);
1283 
1284    if (!mpf_fits_ulong_p(t.data()))
1285    {
1286       *result = (std::numeric_limits<long long>::max)();
1287       return;
1288    }
1289 
1290    *result = mpf_get_ui(t.data());
1291    while (digits > 0)
1292    {
1293       *result <<= digits;
1294       digits -= std::numeric_limits<unsigned long>::digits;
1295       mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits<unsigned long>::digits : std::numeric_limits<unsigned long>::digits + digits);
1296       unsigned long l = static_cast<unsigned long>(mpf_get_ui(t.data()));
1297       if (digits < 0)
1298          l >>= -digits;
1299       *result |= l;
1300    }
1301 }
1302 #endif
1303 
1304 
1305 #ifdef BOOST_HAS_FLOAT128
1306 template <unsigned digits10>
1307 inline void eval_convert_to(float128_type* result, const gmp_float<digits10>& val)
1308 {
1309    *result = float128_procs::strtoflt128(val.str(0, std::ios_base::scientific).c_str(), nullptr);
1310 }
1311 #endif
1312 
1313 
1314 //
1315 // Native non-member operations:
1316 //
1317 template <unsigned Digits10>
1318 inline void eval_sqrt(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1319 {
1320    mpf_sqrt(result.data(), val.data());
1321 }
1322 
1323 template <unsigned Digits10>
1324 inline void eval_abs(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1325 {
1326    mpf_abs(result.data(), val.data());
1327 }
1328 
1329 template <unsigned Digits10>
1330 inline void eval_fabs(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1331 {
1332    mpf_abs(result.data(), val.data());
1333 }
1334 template <unsigned Digits10>
1335 inline void eval_ceil(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1336 {
1337    mpf_ceil(result.data(), val.data());
1338 }
1339 template <unsigned Digits10>
1340 inline void eval_floor(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1341 {
1342    mpf_floor(result.data(), val.data());
1343 }
1344 template <unsigned Digits10>
1345 inline void eval_trunc(gmp_float<Digits10>& result, const gmp_float<Digits10>& val)
1346 {
1347    mpf_trunc(result.data(), val.data());
1348 }
1349 template <unsigned Digits10>
1350 inline void eval_ldexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, long e)
1351 {
1352    if (e > 0)
1353       mpf_mul_2exp(result.data(), val.data(), static_cast<mp_bitcnt_t>(e));
1354    else if (e < 0)
1355       mpf_div_2exp(result.data(), val.data(), static_cast<mp_bitcnt_t>(-e));
1356    else
1357       result = val;
1358 }
1359 template <unsigned Digits10>
1360 inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, int* e)
1361 {
1362 #if (BOOST_MP_MPIR_VERSION >= 20600) && (BOOST_MP_MPIR_VERSION < 30000)
1363    mpir_si v;
1364    mpf_get_d_2exp(&v, val.data());
1365 #else
1366    long v;
1367    mpf_get_d_2exp(&v, val.data());
1368 #endif
1369    *e = static_cast<int>(v);
1370    eval_ldexp(result, val, -v);
1371 }
1372 template <unsigned Digits10>
1373 inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, long* e)
1374 {
1375 #if (BOOST_MP_MPIR_VERSION >= 20600) && (BOOST_MP_MPIR_VERSION < 30000)
1376    mpir_si v;
1377    mpf_get_d_2exp(&v, val.data());
1378    *e = v;
1379    eval_ldexp(result, val, -v);
1380 #else
1381    mpf_get_d_2exp(e, val.data());
1382    eval_ldexp(result, val, -*e);
1383 #endif
1384 }
1385 
1386 template <unsigned Digits10>
1387 inline std::size_t hash_value(const gmp_float<Digits10>& val)
1388 {
1389    std::size_t result = 0;
1390    for (int i = 0; i < std::abs(val.data()[0]._mp_size); ++i)
1391       boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_d[i]);
1392    boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_exp, val.data()[0]._mp_size);
1393    return result;
1394 }
1395 
1396 struct gmp_int
1397 {
1398 #ifdef BOOST_HAS_LONG_LONG
1399    using signed_types = std::tuple<long, long long>          ;
1400    using unsigned_types = std::tuple<unsigned long, unsigned long long>;
1401 #else
1402    using signed_types = std::tuple<long>         ;
1403    using unsigned_types = std::tuple<unsigned long>;
1404 #endif
1405    using float_types = std::tuple<double, long double>;
1406 
1407    gmp_int()
1408    {
1409       mpz_init(this->m_data);
1410    }
1411    gmp_int(const gmp_int& o)
1412    {
1413       if (o.m_data[0]._mp_d)
1414          mpz_init_set(m_data, o.m_data);
1415       else
1416          mpz_init(this->m_data);
1417    }
1418    // rvalue
1419    gmp_int(gmp_int&& o) noexcept
1420    {
1421       m_data[0]         = o.m_data[0];
1422       o.m_data[0]._mp_d = nullptr;
1423    }
1424    explicit gmp_int(const mpf_t val)
1425    {
1426       mpz_init(this->m_data);
1427       mpz_set_f(this->m_data, val);
1428    }
1429    gmp_int(const mpz_t val)
1430    {
1431       mpz_init_set(this->m_data, val);
1432    }
1433    gmp_int(long i)
1434    {
1435       mpz_init_set_si(this->m_data, i);
1436    }
1437    gmp_int(unsigned long i)
1438    {
1439       mpz_init_set_ui(this->m_data, i);
1440    }
1441    explicit gmp_int(const mpq_t val)
1442    {
1443       mpz_init(this->m_data);
1444       mpz_set_q(this->m_data, val);
1445    }
1446    template <unsigned Digits10>
1447    explicit gmp_int(const gmp_float<Digits10>& o)
1448    {
1449       mpz_init(this->m_data);
1450       mpz_set_f(this->m_data, o.data());
1451    }
1452    explicit gmp_int(const gmp_rational& o);
1453    gmp_int& operator=(const gmp_int& o)
1454    {
1455       if (m_data[0]._mp_d == nullptr)
1456          mpz_init(this->m_data);
1457       mpz_set(m_data, o.m_data);
1458       return *this;
1459    }
1460    // rvalue copy
1461    gmp_int& operator=(gmp_int&& o) noexcept
1462    {
1463       mpz_swap(m_data, o.m_data);
1464       return *this;
1465    }
1466 #ifdef BOOST_HAS_LONG_LONG
1467 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
1468    gmp_int& operator=(unsigned long long i)
1469    {
1470       *this = static_cast<unsigned long>(i);
1471       return *this;
1472    }
1473 #else
1474    gmp_int& operator=(unsigned long long i)
1475    {
1476       if (m_data[0]._mp_d == nullptr)
1477          mpz_init(this->m_data);
1478       unsigned long long mask  = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
1479       unsigned               shift = 0;
1480       mpz_t                  t;
1481       mpz_set_ui(m_data, 0);
1482       mpz_init_set_ui(t, 0);
1483       while (i)
1484       {
1485          mpz_set_ui(t, static_cast<unsigned long>(i & mask));
1486          if (shift)
1487             mpz_mul_2exp(t, t, shift);
1488          mpz_add(m_data, m_data, t);
1489          shift += std::numeric_limits<unsigned long>::digits;
1490          i >>= std::numeric_limits<unsigned long>::digits;
1491       }
1492       mpz_clear(t);
1493       return *this;
1494    }
1495 #endif
1496    gmp_int& operator=(long long i)
1497    {
1498       if (m_data[0]._mp_d == nullptr)
1499          mpz_init(this->m_data);
1500       bool neg = i < 0;
1501       *this    = boost::multiprecision::detail::unsigned_abs(i);
1502       if (neg)
1503          mpz_neg(m_data, m_data);
1504       return *this;
1505    }
1506 #endif
1507 #ifdef BOOST_HAS_INT128
1508    gmp_int& operator=(uint128_type i)
1509    {
1510       if (m_data[0]._mp_d == nullptr)
1511          mpz_init(this->m_data);
1512       uint128_type mask  = ((((1uLL << (std::numeric_limits<unsigned long>::digits - 1)) - 1) << 1) | 1uLL);
1513       unsigned               shift = 0;
1514       mpz_t                  t;
1515       mpz_set_ui(m_data, 0);
1516       mpz_init_set_ui(t, 0);
1517       while (i)
1518       {
1519          mpz_set_ui(t, static_cast<unsigned long>(i & mask));
1520          if (shift)
1521             mpz_mul_2exp(t, t, shift);
1522          mpz_add(m_data, m_data, t);
1523          shift += std::numeric_limits<unsigned long>::digits;
1524          i >>= std::numeric_limits<unsigned long>::digits;
1525       }
1526       mpz_clear(t);
1527       return *this;
1528    }
1529    gmp_int& operator=(int128_type i)
1530    {
1531       if (m_data[0]._mp_d == nullptr)
1532          mpz_init(this->m_data);
1533       bool neg = i < 0;
1534       *this    = boost::multiprecision::detail::unsigned_abs(i);
1535       if (neg)
1536          mpz_neg(m_data, m_data);
1537       return *this;
1538    }
1539 #endif
1540    gmp_int& operator=(unsigned long i)
1541    {
1542       if (m_data[0]._mp_d == nullptr)
1543          mpz_init(this->m_data);
1544       mpz_set_ui(m_data, i);
1545       return *this;
1546    }
1547    gmp_int& operator=(long i)
1548    {
1549       if (m_data[0]._mp_d == nullptr)
1550          mpz_init(this->m_data);
1551       mpz_set_si(m_data, i);
1552       return *this;
1553    }
1554    gmp_int& operator=(double d)
1555    {
1556       if (m_data[0]._mp_d == nullptr)
1557          mpz_init(this->m_data);
1558       mpz_set_d(m_data, d);
1559       return *this;
1560    }
1561    template <class F>
1562    gmp_int& assign_float(F a)
1563    {
1564       BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp;
1565 
1566       if (m_data[0]._mp_d == nullptr)
1567          mpz_init(this->m_data);
1568 
1569       if (a == 0)
1570       {
1571          mpz_set_si(m_data, 0);
1572          return *this;
1573       }
1574 
1575       if (a == 1)
1576       {
1577          mpz_set_si(m_data, 1);
1578          return *this;
1579       }
1580 
1581       BOOST_MP_ASSERT(!BOOST_MP_ISINF(a));
1582       BOOST_MP_ASSERT(!BOOST_MP_ISNAN(a));
1583 
1584       int         e;
1585       F f, term;
1586       mpz_set_ui(m_data, 0u);
1587 
1588       f = frexp(a, &e);
1589 
1590       constexpr int shift = std::numeric_limits<int>::digits - 1;
1591 
1592       while (f != static_cast<F>(0.0f))
1593       {
1594          // extract int sized bits from f:
1595          f    = ldexp(f, shift);
1596          term = floor(f);
1597          e -= shift;
1598          mpz_mul_2exp(m_data, m_data, shift);
1599          if (term > 0)
1600             mpz_add_ui(m_data, m_data, static_cast<unsigned>(term));
1601          else
1602             mpz_sub_ui(m_data, m_data, static_cast<unsigned>(-term));
1603          f -= term;
1604       }
1605       if (e > 0)
1606          mpz_mul_2exp(m_data, m_data, static_cast<mp_bitcnt_t>(e));
1607       else if (e < 0)
1608          mpz_div_2exp(m_data, m_data, static_cast<mp_bitcnt_t>(-e));
1609       return *this;
1610    }
1611    gmp_int& operator=(long double a)
1612    {
1613       return assign_float(a);
1614    }
1615    gmp_int& operator=(const char* s)
1616    {
1617       if (m_data[0]._mp_d == nullptr)
1618          mpz_init(this->m_data);
1619       std::size_t n     = s ? std::strlen(s) : 0;
1620       int         radix = 10;
1621       if (n && (*s == '0'))
1622       {
1623          if ((n > 1) && ((s[1] == 'x') || (s[1] == 'X')))
1624          {
1625             radix = 16;
1626             s += 2;
1627             n -= 2;
1628          }
1629          else
1630          {
1631             radix = 8;
1632             n -= 1;
1633          }
1634       }
1635       if (n)
1636       {
1637          if (0 != mpz_set_str(m_data, s, radix))
1638             BOOST_MP_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid integer.")));
1639       }
1640       else
1641          mpz_set_ui(m_data, 0);
1642       return *this;
1643    }
1644 #ifdef BOOST_HAS_FLOAT128
1645    gmp_int& operator=(float128_type a)
1646    {
1647       return assign_float(a);
1648    }
1649 #endif
1650    gmp_int& operator=(const mpf_t val)
1651    {
1652       if (m_data[0]._mp_d == nullptr)
1653          mpz_init(this->m_data);
1654       mpz_set_f(this->m_data, val);
1655       return *this;
1656    }
1657    gmp_int& operator=(const mpz_t val)
1658    {
1659       if (m_data[0]._mp_d == nullptr)
1660          mpz_init(this->m_data);
1661       mpz_set(this->m_data, val);
1662       return *this;
1663    }
1664    gmp_int& operator=(const mpq_t val)
1665    {
1666       if (m_data[0]._mp_d == nullptr)
1667          mpz_init(this->m_data);
1668       mpz_set_q(this->m_data, val);
1669       return *this;
1670    }
1671    template <unsigned Digits10>
1672    gmp_int& operator=(const gmp_float<Digits10>& o)
1673    {
1674       if (m_data[0]._mp_d == nullptr)
1675          mpz_init(this->m_data);
1676       mpz_set_f(this->m_data, o.data());
1677       return *this;
1678    }
1679    gmp_int& operator=(const gmp_rational& o);
1680    void     swap(gmp_int& o)
1681    {
1682       mpz_swap(m_data, o.m_data);
1683    }
1684    std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags f) const
1685    {
1686       BOOST_MP_ASSERT(m_data[0]._mp_d);
1687 
1688       int base = 10;
1689       if ((f & std::ios_base::oct) == std::ios_base::oct)
1690          base = 8;
1691       else if ((f & std::ios_base::hex) == std::ios_base::hex)
1692          base = 16;
1693       //
1694       // sanity check, bases 8 and 16 are only available for positive numbers:
1695       //
1696       if ((base != 10) && (mpz_sgn(m_data) < 0))
1697          BOOST_MP_THROW_EXCEPTION(std::runtime_error("Formatted output in bases 8 or 16 is only available for positive numbers"));
1698       void* (*alloc_func_ptr)(size_t);
1699       void* (*realloc_func_ptr)(void*, size_t, size_t);
1700       void (*free_func_ptr)(void*, size_t);
1701       const char* ps = mpz_get_str(nullptr, base, m_data);
1702       std::string s  = ps;
1703       mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
1704       (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
1705       if (f & std::ios_base::uppercase)
1706          for (size_t i = 0; i < s.length(); ++i)
1707             s[i] = static_cast<char>(std::toupper(s[i]));
1708       if ((base != 10) && (f & std::ios_base::showbase))
1709       {
1710          int         pos = s[0] == '-' ? 1 : 0;
1711          const char* pp  = base == 8 ? "0" : (f & std::ios_base::uppercase) ? "0X" : "0x";
1712          s.insert(static_cast<std::string::size_type>(pos), pp);
1713       }
1714       if ((f & std::ios_base::showpos) && (s[0] != '-'))
1715          s.insert(static_cast<std::string::size_type>(0), 1, '+');
1716 
1717       return s;
1718    }
1719    ~gmp_int() noexcept
1720    {
1721       if (m_data[0]._mp_d)
1722          mpz_clear(m_data);
1723    }
1724    void negate() noexcept
1725    {
1726       BOOST_MP_ASSERT(m_data[0]._mp_d);
1727       mpz_neg(m_data, m_data);
1728    }
1729    int compare(const gmp_int& o) const noexcept
1730    {
1731       BOOST_MP_ASSERT(m_data[0]._mp_d && o.m_data[0]._mp_d);
1732       return mpz_cmp(m_data, o.m_data);
1733    }
1734    int compare(long i) const noexcept
1735    {
1736       BOOST_MP_ASSERT(m_data[0]._mp_d);
1737       return mpz_cmp_si(m_data, i);
1738    }
1739    int compare(unsigned long i) const noexcept
1740    {
1741       BOOST_MP_ASSERT(m_data[0]._mp_d);
1742       return mpz_cmp_ui(m_data, i);
1743    }
1744    template <class V>
1745    int compare(V v) const
1746    {
1747       gmp_int d;
1748       d = v;
1749       return compare(d);
1750    }
1751    mpz_t& data() noexcept
1752    {
1753       BOOST_MP_ASSERT(m_data[0]._mp_d);
1754       return m_data;
1755    }
1756    const mpz_t& data() const noexcept
1757    {
1758       BOOST_MP_ASSERT(m_data[0]._mp_d);
1759       return m_data;
1760    }
1761 
1762  protected:
1763    mpz_t m_data;
1764 };
1765 
1766 template <class T>
1767 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_eq(const gmp_int& a, const T& b)
1768 {
1769    return a.compare(b) == 0;
1770 }
1771 template <class T>
1772 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_lt(const gmp_int& a, const T& b)
1773 {
1774    return a.compare(b) < 0;
1775 }
1776 template <class T>
1777 inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<T>::value, bool>::type eval_gt(const gmp_int& a, const T& b)
1778 {
1779    return a.compare(b) > 0;
1780 }
1781 
1782 inline bool eval_is_zero(const gmp_int& val)
1783 {
1784    return mpz_sgn(val.data()) == 0;
1785 }
1786 inline void eval_add(gmp_int& t, const gmp_int& o)
1787 {
1788    mpz_add(t.data(), t.data(), o.data());
1789 }
1790 inline void eval_multiply_add(gmp_int& t, const gmp_int& a, const gmp_int& b)
1791 {
1792    mpz_addmul(t.data(), a.data(), b.data());
1793 }
1794 inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, const gmp_int& b)
1795 {
1796    mpz_submul(t.data(), a.data(), b.data());
1797 }
1798 inline void eval_subtract(gmp_int& t, const gmp_int& o)
1799 {
1800    mpz_sub(t.data(), t.data(), o.data());
1801 }
1802 inline void eval_multiply(gmp_int& t, const gmp_int& o)
1803 {
1804    mpz_mul(t.data(), t.data(), o.data());
1805 }
1806 inline void eval_divide(gmp_int& t, const gmp_int& o)
1807 {
1808    if (eval_is_zero(o))
1809       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1810    mpz_tdiv_q(t.data(), t.data(), o.data());
1811 }
1812 inline void eval_modulus(gmp_int& t, const gmp_int& o)
1813 {
1814    mpz_tdiv_r(t.data(), t.data(), o.data());
1815 }
1816 inline void eval_add(gmp_int& t, unsigned long i)
1817 {
1818    mpz_add_ui(t.data(), t.data(), i);
1819 }
1820 inline void eval_multiply_add(gmp_int& t, const gmp_int& a, unsigned long i)
1821 {
1822    mpz_addmul_ui(t.data(), a.data(), i);
1823 }
1824 inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, unsigned long i)
1825 {
1826    mpz_submul_ui(t.data(), a.data(), i);
1827 }
1828 inline void eval_subtract(gmp_int& t, unsigned long i)
1829 {
1830    mpz_sub_ui(t.data(), t.data(), i);
1831 }
1832 inline void eval_multiply(gmp_int& t, unsigned long i)
1833 {
1834    mpz_mul_ui(t.data(), t.data(), i);
1835 }
1836 inline void eval_modulus(gmp_int& t, unsigned long i)
1837 {
1838    mpz_tdiv_r_ui(t.data(), t.data(), i);
1839 }
1840 inline void eval_divide(gmp_int& t, unsigned long i)
1841 {
1842    if (i == 0)
1843       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1844    mpz_tdiv_q_ui(t.data(), t.data(), i);
1845 }
1846 inline void eval_add(gmp_int& t, long i)
1847 {
1848    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1849 
1850    if (i > 0)
1851       mpz_add_ui(t.data(), t.data(), static_cast<local_uint_type>(i));
1852    else if (i < 0)
1853       mpz_sub_ui(t.data(), t.data(), static_cast<local_uint_type>(-i));
1854 }
1855 inline void eval_multiply_add(gmp_int& t, const gmp_int& a, long i)
1856 {
1857    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1858 
1859    if (i > 0)
1860       mpz_addmul_ui(t.data(), a.data(), static_cast<local_uint_type>(i));
1861    else
1862       mpz_submul_ui(t.data(), a.data(), static_cast<local_uint_type>(-i));
1863 }
1864 inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, long i)
1865 {
1866    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1867 
1868    if (i > 0)
1869       mpz_submul_ui(t.data(), a.data(), static_cast<local_uint_type>(i));
1870    else
1871       mpz_addmul_ui(t.data(), a.data(), static_cast<local_uint_type>(-i));
1872 }
1873 inline void eval_subtract(gmp_int& t, long i)
1874 {
1875    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1876 
1877    if (i > 0)
1878       mpz_sub_ui(t.data(), t.data(), static_cast<local_uint_type>(i));
1879    else if (i < 0)
1880       mpz_add_ui(t.data(), t.data(), static_cast<local_uint_type>(-i));
1881 }
1882 inline void eval_multiply(gmp_int& t, long i)
1883 {
1884    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1885 
1886    mpz_mul_ui(t.data(), t.data(), static_cast<local_uint_type>(boost::multiprecision::detail::unsigned_abs(i)));
1887 
1888    if (i < 0)
1889       mpz_neg(t.data(), t.data());
1890 }
1891 inline void eval_modulus(gmp_int& t, long i)
1892 {
1893    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1894 
1895    mpz_tdiv_r_ui(t.data(), t.data(), static_cast<local_uint_type>(boost::multiprecision::detail::unsigned_abs(i)));
1896 }
1897 inline void eval_divide(gmp_int& t, long i)
1898 {
1899    if (i == 0)
1900       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1901 
1902    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1903 
1904    mpz_tdiv_q_ui(t.data(), t.data(), static_cast<local_uint_type>(boost::multiprecision::detail::unsigned_abs(i)));
1905 
1906    if (i < 0)
1907       mpz_neg(t.data(), t.data());
1908 }
1909 template <class UI>
1910 inline void eval_left_shift(gmp_int& t, UI i)
1911 {
1912    mpz_mul_2exp(t.data(), t.data(), static_cast<unsigned long>(i));
1913 }
1914 template <class UI>
1915 inline void eval_right_shift(gmp_int& t, UI i)
1916 {
1917    mpz_fdiv_q_2exp(t.data(), t.data(), static_cast<unsigned long>(i));
1918 }
1919 template <class UI>
1920 inline void eval_left_shift(gmp_int& t, const gmp_int& v, UI i)
1921 {
1922    mpz_mul_2exp(t.data(), v.data(), static_cast<unsigned long>(i));
1923 }
1924 template <class UI>
1925 inline void eval_right_shift(gmp_int& t, const gmp_int& v, UI i)
1926 {
1927    mpz_fdiv_q_2exp(t.data(), v.data(), static_cast<unsigned long>(i));
1928 }
1929 
1930 inline void eval_bitwise_and(gmp_int& result, const gmp_int& v)
1931 {
1932    mpz_and(result.data(), result.data(), v.data());
1933 }
1934 
1935 inline void eval_bitwise_or(gmp_int& result, const gmp_int& v)
1936 {
1937    mpz_ior(result.data(), result.data(), v.data());
1938 }
1939 
1940 inline void eval_bitwise_xor(gmp_int& result, const gmp_int& v)
1941 {
1942    mpz_xor(result.data(), result.data(), v.data());
1943 }
1944 
1945 inline void eval_add(gmp_int& t, const gmp_int& p, const gmp_int& o)
1946 {
1947    mpz_add(t.data(), p.data(), o.data());
1948 }
1949 inline void eval_subtract(gmp_int& t, const gmp_int& p, const gmp_int& o)
1950 {
1951    mpz_sub(t.data(), p.data(), o.data());
1952 }
1953 inline void eval_multiply(gmp_int& t, const gmp_int& p, const gmp_int& o)
1954 {
1955    mpz_mul(t.data(), p.data(), o.data());
1956 }
1957 inline void eval_divide(gmp_int& t, const gmp_int& p, const gmp_int& o)
1958 {
1959    if (eval_is_zero(o))
1960       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1961    mpz_tdiv_q(t.data(), p.data(), o.data());
1962 }
1963 inline void eval_modulus(gmp_int& t, const gmp_int& p, const gmp_int& o)
1964 {
1965    mpz_tdiv_r(t.data(), p.data(), o.data());
1966 }
1967 inline void eval_add(gmp_int& t, const gmp_int& p, unsigned long i)
1968 {
1969    mpz_add_ui(t.data(), p.data(), i);
1970 }
1971 inline void eval_subtract(gmp_int& t, const gmp_int& p, unsigned long i)
1972 {
1973    mpz_sub_ui(t.data(), p.data(), i);
1974 }
1975 inline void eval_multiply(gmp_int& t, const gmp_int& p, unsigned long i)
1976 {
1977    mpz_mul_ui(t.data(), p.data(), i);
1978 }
1979 inline void eval_modulus(gmp_int& t, const gmp_int& p, unsigned long i)
1980 {
1981    mpz_tdiv_r_ui(t.data(), p.data(), i);
1982 }
1983 inline void eval_divide(gmp_int& t, const gmp_int& p, unsigned long i)
1984 {
1985    if (i == 0)
1986       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
1987    mpz_tdiv_q_ui(t.data(), p.data(), i);
1988 }
1989 inline void eval_add(gmp_int& t, const gmp_int& p, long i)
1990 {
1991    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
1992 
1993    if (i > 0)
1994       mpz_add_ui(t.data(), p.data(), static_cast<local_uint_type>(i));
1995    else
1996       mpz_sub_ui(t.data(), p.data(), static_cast<local_uint_type>(-i));
1997 }
1998 inline void eval_subtract(gmp_int& t, const gmp_int& p, long i)
1999 {
2000    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
2001 
2002    if (i > 0)
2003       mpz_sub_ui(t.data(), p.data(), static_cast<local_uint_type>(i));
2004    else
2005       mpz_add_ui(t.data(), p.data(), static_cast<local_uint_type>(-i));
2006 }
2007 inline void eval_multiply(gmp_int& t, const gmp_int& p, long i)
2008 {
2009    mpz_mul_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
2010    if (i < 0)
2011       mpz_neg(t.data(), t.data());
2012 }
2013 inline void eval_modulus(gmp_int& t, const gmp_int& p, long i)
2014 {
2015    mpz_tdiv_r_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
2016 }
2017 inline void eval_divide(gmp_int& t, const gmp_int& p, long i)
2018 {
2019    if (i == 0)
2020       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2021    mpz_tdiv_q_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i));
2022    if (i < 0)
2023       mpz_neg(t.data(), t.data());
2024 }
2025 
2026 inline void eval_bitwise_and(gmp_int& result, const gmp_int& u, const gmp_int& v)
2027 {
2028    mpz_and(result.data(), u.data(), v.data());
2029 }
2030 
2031 inline void eval_bitwise_or(gmp_int& result, const gmp_int& u, const gmp_int& v)
2032 {
2033    mpz_ior(result.data(), u.data(), v.data());
2034 }
2035 
2036 inline void eval_bitwise_xor(gmp_int& result, const gmp_int& u, const gmp_int& v)
2037 {
2038    mpz_xor(result.data(), u.data(), v.data());
2039 }
2040 
2041 inline void eval_complement(gmp_int& result, const gmp_int& u)
2042 {
2043    mpz_com(result.data(), u.data());
2044 }
2045 
2046 inline int eval_get_sign(const gmp_int& val)
2047 {
2048    return mpz_sgn(val.data());
2049 }
2050 inline void eval_convert_to(unsigned long* result, const gmp_int& val)
2051 {
2052    if (mpz_sgn(val.data()) < 0)
2053    {
2054       BOOST_MP_THROW_EXCEPTION(std::range_error("Conversion from negative integer to an unsigned type results in undefined behaviour"));
2055    }
2056    else
2057       *result = static_cast<unsigned long>(mpz_get_ui(val.data()));
2058 }
2059 inline void eval_convert_to(long* result, const gmp_int& val)
2060 {
2061    if (0 == mpz_fits_slong_p(val.data()))
2062    {
2063       *result = mpz_sgn(val.data()) < 0 ? (std::numeric_limits<long>::min)() : (std::numeric_limits<long>::max)();
2064    }
2065    else
2066       *result = static_cast<long>(mpz_get_si(val.data()));
2067 }
2068 inline void eval_convert_to(long double* result, const gmp_int& val)
2069 {
2070    detail::gmp_char_ptr val_char_ptr {mpz_get_str(nullptr, 10, val.data())};
2071    *result = std::strtold(val_char_ptr.get(), nullptr);
2072 }
2073 inline void eval_convert_to(double* result, const gmp_int& val)
2074 {
2075    *result = mpz_get_d(val.data());
2076 }
2077 #ifdef BOOST_HAS_LONG_LONG
2078 inline void eval_convert_to(unsigned long long* result, const gmp_int& val)
2079 {
2080    if (mpz_sgn(val.data()) < 0)
2081    {
2082       BOOST_MP_THROW_EXCEPTION(std::range_error("Conversion from negative integer to an unsigned type results in undefined behaviour"));
2083    }
2084    *result = 0;
2085    gmp_int t(val);
2086    unsigned parts = sizeof(unsigned long long) / sizeof(unsigned long);
2087 
2088    for (unsigned i = 0; i < parts; ++i)
2089    {
2090       unsigned long long part = mpz_get_ui(t.data());
2091       if (i)
2092          *result |= part << (i * sizeof(unsigned long) * CHAR_BIT);
2093       else
2094          *result = part;
2095       mpz_tdiv_q_2exp(t.data(), t.data(), sizeof(unsigned long) * CHAR_BIT);
2096    }
2097 }
2098 inline void eval_convert_to(long long* result, const gmp_int& val)
2099 {
2100    int s = mpz_sgn(val.data());
2101    *result = 0;
2102    gmp_int t(val);
2103    unsigned parts = sizeof(unsigned long long) / sizeof(unsigned long);
2104    unsigned long long unsigned_result = 0;
2105 
2106    for (unsigned i = 0; i < parts; ++i)
2107    {
2108       unsigned long long part = mpz_get_ui(t.data());
2109       if (i)
2110          unsigned_result |= part << (i * sizeof(unsigned long) * CHAR_BIT);
2111       else
2112          unsigned_result = part;
2113       mpz_tdiv_q_2exp(t.data(), t.data(), sizeof(unsigned long) * CHAR_BIT);
2114    }
2115    //
2116    // Overflow check:
2117    //
2118    bool overflow = false;
2119    if (mpz_sgn(t.data()))
2120    {
2121       overflow = true;
2122    }
2123    if ((s > 0) && (unsigned_result > static_cast<unsigned long long>((std::numeric_limits<long long>::max)())))
2124       overflow = true;
2125    if((s < 0) && (unsigned_result > 1u - static_cast<unsigned long long>((std::numeric_limits<long long>::min)() + 1)))
2126       overflow = true;
2127    if(overflow)
2128       *result = s < 0 ? (std::numeric_limits<long long>::min)() : (std::numeric_limits<long long>::max)();
2129    else
2130       *result = s < 0 ? -static_cast<long long>(unsigned_result - 1u) - 1 : static_cast<long long>(unsigned_result);
2131 }
2132 #endif
2133 #ifdef BOOST_HAS_INT128
2134 inline void eval_convert_to(uint128_type* result, const gmp_int& val)
2135 {
2136    if (mpz_sgn(val.data()) < 0)
2137    {
2138       BOOST_MP_THROW_EXCEPTION(std::range_error("Conversion from negative integer to an unsigned type results in undefined behaviour"));
2139    }
2140    *result = 0;
2141    gmp_int t(val);
2142    unsigned parts = sizeof(uint128_type) / sizeof(unsigned long);
2143 
2144    for (unsigned i = 0; i < parts; ++i)
2145    {
2146       uint128_type part = mpz_get_ui(t.data());
2147       if (i)
2148          *result |= part << (i * sizeof(unsigned long) * CHAR_BIT);
2149       else
2150          *result = part;
2151       mpz_tdiv_q_2exp(t.data(), t.data(), sizeof(unsigned long) * CHAR_BIT);
2152    }
2153 }
2154 inline void eval_convert_to(int128_type* result, const gmp_int& val)
2155 {
2156    int s = mpz_sgn(val.data());
2157    *result = 0;
2158    gmp_int t(val);
2159    unsigned parts = sizeof(uint128_type) / sizeof(unsigned long);
2160    uint128_type unsigned_result = 0;
2161 
2162    for (unsigned i = 0; i < parts; ++i)
2163    {
2164       uint128_type part = mpz_get_ui(t.data());
2165       if (i)
2166          unsigned_result |= part << (i * sizeof(unsigned long) * CHAR_BIT);
2167       else
2168          unsigned_result = part;
2169       mpz_tdiv_q_2exp(t.data(), t.data(), sizeof(unsigned long) * CHAR_BIT);
2170    }
2171    //
2172    // Overflow check:
2173    //
2174    constexpr int128_type int128_max = static_cast<int128_type>((static_cast<uint128_type>(1u) << 127) - 1);
2175    constexpr int128_type int128_min = static_cast<int128_type>(static_cast<int128_type>(-int128_max) -1);
2176    bool overflow = false;
2177    if (mpz_sgn(t.data()))
2178    {
2179       overflow = true;
2180    }
2181    if ((s > 0) && (unsigned_result > static_cast<uint128_type>(int128_max)))
2182       overflow = true;
2183    if ((s < 0) && (unsigned_result > 1u - static_cast<uint128_type>(int128_min + 1)))
2184       overflow = true;
2185    if (overflow)
2186       *result = s < 0 ? int128_min : int128_max;
2187    else
2188       *result = s < 0 ? -static_cast<int128_type>(unsigned_result - 1u) - 1 : static_cast<int128_type>(unsigned_result);
2189 }
2190 
2191 template <unsigned digits10>
2192 inline void eval_convert_to(int128_type* result, const gmp_float<digits10>& val)
2193 {
2194    gmp_int i;
2195    mpz_set_f(i.data(), val.data());
2196    eval_convert_to(result, i);
2197 }
2198 template <unsigned digits10>
2199 inline void eval_convert_to(uint128_type* result, const gmp_float<digits10>& val)
2200 {
2201    gmp_int i;
2202    mpz_set_f(i.data(), val.data());
2203    eval_convert_to(result, i);
2204 }
2205 
2206 #endif
2207 
2208 #ifdef BOOST_HAS_FLOAT128
2209 inline void eval_convert_to(float128_type* result, const gmp_int& val)
2210 {
2211    *result = float128_procs::strtoflt128(val.str(0, std::ios_base::fixed).c_str(), nullptr);
2212 }
2213 #endif
2214 
2215 inline void eval_abs(gmp_int& result, const gmp_int& val)
2216 {
2217    mpz_abs(result.data(), val.data());
2218 }
2219 
2220 inline void eval_gcd(gmp_int& result, const gmp_int& a, const gmp_int& b)
2221 {
2222    mpz_gcd(result.data(), a.data(), b.data());
2223 }
2224 inline void eval_lcm(gmp_int& result, const gmp_int& a, const gmp_int& b)
2225 {
2226    mpz_lcm(result.data(), a.data(), b.data());
2227 }
2228 template <class I>
2229 inline typename std::enable_if<(boost::multiprecision::detail::is_unsigned<I>::value && (sizeof(I) <= sizeof(unsigned long)))>::type eval_gcd(gmp_int& result, const gmp_int& a, const I b)
2230 {
2231    mpz_gcd_ui(result.data(), a.data(), b);
2232 }
2233 template <class I>
2234 inline typename std::enable_if<(boost::multiprecision::detail::is_unsigned<I>::value && (sizeof(I) <= sizeof(unsigned long)))>::type eval_lcm(gmp_int& result, const gmp_int& a, const I b)
2235 {
2236    mpz_lcm_ui(result.data(), a.data(), b);
2237 }
2238 template <class I>
2239 inline typename std::enable_if<(boost::multiprecision::detail::is_signed<I>::value && boost::multiprecision::detail::is_integral<I>::value && (sizeof(I) <= sizeof(long)))>::type eval_gcd(gmp_int& result, const gmp_int& a, const I b)
2240 {
2241    mpz_gcd_ui(result.data(), a.data(), boost::multiprecision::detail::unsigned_abs(b));
2242 }
2243 template <class I>
2244 inline typename std::enable_if<boost::multiprecision::detail::is_signed<I>::value && boost::multiprecision::detail::is_integral<I>::value && ((sizeof(I) <= sizeof(long)))>::type eval_lcm(gmp_int& result, const gmp_int& a, const I b)
2245 {
2246    mpz_lcm_ui(result.data(), a.data(), boost::multiprecision::detail::unsigned_abs(b));
2247 }
2248 
2249 inline void eval_integer_sqrt(gmp_int& s, gmp_int& r, const gmp_int& x)
2250 {
2251    mpz_sqrtrem(s.data(), r.data(), x.data());
2252 }
2253 
2254 inline std::size_t eval_lsb(const gmp_int& val)
2255 {
2256    int c = eval_get_sign(val);
2257    if (c == 0)
2258    {
2259       BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
2260    }
2261    if (c < 0)
2262    {
2263       BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
2264    }
2265    return static_cast<unsigned>(mpz_scan1(val.data(), 0));
2266 }
2267 
2268 inline std::size_t eval_msb(const gmp_int& val)
2269 {
2270    int c = eval_get_sign(val);
2271    if (c == 0)
2272    {
2273       BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
2274    }
2275    if (c < 0)
2276    {
2277       BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
2278    }
2279    return static_cast<unsigned>(mpz_sizeinbase(val.data(), 2) - 1);
2280 }
2281 
2282 inline bool eval_bit_test(const gmp_int& val, std::size_t index)
2283 {
2284    return mpz_tstbit(val.data(), index) ? true : false;
2285 }
2286 
2287 inline void eval_bit_set(gmp_int& val, std::size_t index)
2288 {
2289    mpz_setbit(val.data(), index);
2290 }
2291 
2292 inline void eval_bit_unset(gmp_int& val, std::size_t index)
2293 {
2294    mpz_clrbit(val.data(), index);
2295 }
2296 
2297 inline void eval_bit_flip(gmp_int& val, std::size_t index)
2298 {
2299    mpz_combit(val.data(), index);
2300 }
2301 
2302 inline void eval_qr(const gmp_int& x, const gmp_int& y,
2303                     gmp_int& q, gmp_int& r)
2304 {
2305    mpz_tdiv_qr(q.data(), r.data(), x.data(), y.data());
2306 }
2307 
2308 template <class Integer>
2309 inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<Integer>::value, Integer>::type eval_integer_modulus(const gmp_int& x, Integer val)
2310 {
2311 #if defined(__MPIR_VERSION) && (__MPIR_VERSION >= 3)
2312    if ((sizeof(Integer) <= sizeof(mpir_ui)) || (val <= (std::numeric_limits<mpir_ui>::max)()))
2313 #else
2314    if ((sizeof(Integer) <= sizeof(long)) || (val <= (std::numeric_limits<unsigned long>::max)()))
2315 #endif
2316    {
2317       return static_cast<Integer>(mpz_tdiv_ui(x.data(), val));
2318    }
2319    else
2320    {
2321       return default_ops::eval_integer_modulus(x, val);
2322    }
2323 }
2324 template <class Integer>
2325 inline typename std::enable_if<boost::multiprecision::detail::is_signed<Integer>::value && boost::multiprecision::detail::is_integral<Integer>::value, Integer>::type eval_integer_modulus(const gmp_int& x, Integer val)
2326 {
2327    return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
2328 }
2329 inline void eval_powm(gmp_int& result, const gmp_int& base, const gmp_int& p, const gmp_int& m)
2330 {
2331    if (eval_get_sign(p) < 0)
2332    {
2333       BOOST_MP_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
2334    }
2335    mpz_powm(result.data(), base.data(), p.data(), m.data());
2336 }
2337 
2338 template <class Integer>
2339 inline typename std::enable_if<
2340     boost::multiprecision::detail::is_unsigned<Integer>::value && (sizeof(Integer) <= sizeof(unsigned long))>::type
2341 eval_powm(gmp_int& result, const gmp_int& base, Integer p, const gmp_int& m)
2342 {
2343    mpz_powm_ui(result.data(), base.data(), p, m.data());
2344 }
2345 template <class Integer>
2346 inline typename std::enable_if<boost::multiprecision::detail::is_signed<Integer>::value && boost::multiprecision::detail::is_integral<Integer>::value && (sizeof(Integer) <= sizeof(unsigned long))>::type
2347 eval_powm(gmp_int& result, const gmp_int& base, Integer p, const gmp_int& m)
2348 {
2349    if (p < 0)
2350    {
2351       BOOST_MP_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
2352    }
2353    mpz_powm_ui(result.data(), base.data(), p, m.data());
2354 }
2355 
2356 inline std::size_t hash_value(const gmp_int& val)
2357 {
2358    // We should really use mpz_limbs_read here, but that's unsupported on older versions:
2359    std::size_t result = 0;
2360    for (int i = 0; i < std::abs(val.data()[0]._mp_size); ++i)
2361       boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_d[i]);
2362    boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_size);
2363    return result;
2364 }
2365 
2366 struct gmp_rational;
2367 void eval_add(gmp_rational& t, const gmp_rational& o);
2368 
2369 struct gmp_rational
2370 {
2371 #ifdef BOOST_HAS_LONG_LONG
2372    using signed_types = std::tuple<long, long long>          ;
2373    using unsigned_types = std::tuple<unsigned long, unsigned long long>;
2374 #else
2375    using signed_types = std::tuple<long>         ;
2376    using unsigned_types = std::tuple<unsigned long>;
2377 #endif
2378    using float_types = std::tuple<double, long double>;
2379 
2380    gmp_rational()
2381    {
2382       mpq_init(this->m_data);
2383    }
2384    gmp_rational(const gmp_rational& o)
2385    {
2386       mpq_init(m_data);
2387       if (o.m_data[0]._mp_num._mp_d)
2388          mpq_set(m_data, o.m_data);
2389    }
2390    gmp_rational(const gmp_int& o)
2391    {
2392       mpz_init_set(&m_data[0]._mp_num, o.data());
2393       mpz_init_set_ui(&m_data[0]._mp_den, 1u);
2394    }
2395    gmp_rational(long i)
2396    {
2397       mpz_init_set_si(&m_data[0]._mp_num, i);
2398       mpz_init_set_ui(&m_data[0]._mp_den, 1u);
2399    }
2400    gmp_rational(unsigned long ui)
2401    {
2402       mpz_init_set_ui(&m_data[0]._mp_num, ui);
2403       mpz_init_set_ui(&m_data[0]._mp_den, 1u);
2404    }
2405    // 2-arg constructors:
2406    template <class T, class U>
2407    gmp_rational(const T& a, const U& b, typename std::enable_if<std::is_constructible<gmp_int, T>::value && std::is_constructible<gmp_int, U>::value>::type* = nullptr)
2408    {
2409       gmp_int i(a), j(b);
2410 
2411       if (eval_is_zero(j))
2412          BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2413 
2414       m_data[0]._mp_num = i.data()[0];
2415       m_data[0]._mp_den = j.data()[0];
2416       mpq_canonicalize(m_data);
2417       i.data()[0]._mp_d = nullptr;
2418       j.data()[0]._mp_d = nullptr;
2419    }
2420    template <class U>
2421    gmp_rational(const gmp_int& a, const U& b, typename std::enable_if<std::is_constructible<gmp_int, U>::value>::type* = nullptr)
2422    {
2423       gmp_int j(b);
2424 
2425       if (eval_is_zero(j))
2426          BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2427 
2428       mpz_init_set(&m_data[0]._mp_num, a.data());
2429       m_data[0]._mp_den = j.data()[0];
2430       if (boost::multiprecision::detail::unsigned_abs(b) > 1)
2431          mpq_canonicalize(m_data);
2432       j.data()[0]._mp_d = nullptr;
2433    }
2434    template <class U>
2435    gmp_rational(gmp_int&& a, const U& b, typename std::enable_if<std::is_constructible<gmp_int, U>::value>::type* = nullptr)
2436    {
2437       gmp_int j(b);
2438 
2439       if (eval_is_zero(j))
2440          BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2441 
2442       m_data[0]._mp_num = a.data()[0];
2443       m_data[0]._mp_den = j.data()[0];
2444       if (boost::multiprecision::detail::unsigned_abs(b) > 1)
2445          mpq_canonicalize(m_data);
2446       a.data()[0]._mp_d = nullptr;
2447       j.data()[0]._mp_d = nullptr;
2448    }
2449    template <class T>
2450    gmp_rational(const T& a, const gmp_int& b, typename std::enable_if<std::is_constructible<gmp_int, T>::value>::type* = nullptr)
2451    {
2452       if (eval_is_zero(b))
2453          BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2454 
2455       gmp_int i(a);
2456       m_data[0]._mp_num = i.data()[0];
2457       mpz_init_set(&m_data[0]._mp_den, b.data());
2458       if(boost::multiprecision::detail::unsigned_abs(a) > 1)
2459          mpq_canonicalize(m_data);
2460       i.data()[0]._mp_d = nullptr;
2461    }
2462    template <class T>
2463    gmp_rational(const T& a, gmp_int&& b, typename std::enable_if<std::is_constructible<gmp_int, T>::value>::type* = nullptr)
2464    {
2465       if (eval_is_zero(static_cast<gmp_int&&>(b)))
2466          BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2467 
2468       gmp_int i(a);
2469       m_data[0]._mp_num = i.data()[0];
2470       m_data[0]._mp_den = b.data()[0];
2471       if(boost::multiprecision::detail::unsigned_abs(a) > 1)
2472          mpq_canonicalize(m_data);
2473       i.data()[0]._mp_d = nullptr;
2474       b.data()[0]._mp_d = nullptr;
2475    }
2476    gmp_rational(const gmp_int& a, const gmp_int& b)
2477    {
2478       if (eval_is_zero(b))
2479          BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2480 
2481       mpz_init_set(&m_data[0]._mp_num, a.data());
2482       mpz_init_set(&m_data[0]._mp_den, b.data());
2483       mpq_canonicalize(m_data);
2484    }
2485    gmp_rational(const gmp_int& a, gmp_int&& b)
2486    {
2487       if (eval_is_zero(static_cast<gmp_int&&>(b)))
2488          BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2489 
2490       mpz_init_set(&m_data[0]._mp_num, a.data());
2491       m_data[0]._mp_den = b.data()[0];
2492       mpq_canonicalize(m_data);
2493       b.data()[0]._mp_d = nullptr;
2494    }
2495    gmp_rational(gmp_int&& a, const gmp_int& b)
2496    {
2497       if (eval_is_zero(b))
2498          BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2499 
2500       m_data[0]._mp_num = a.data()[0];
2501       mpz_init_set(&m_data[0]._mp_den, b.data());
2502       mpq_canonicalize(m_data);
2503       a.data()[0]._mp_d = nullptr;
2504    }
2505    gmp_rational(gmp_int&& a, gmp_int&& b)
2506    {
2507       if (eval_is_zero(static_cast<gmp_int&&>(b)))
2508          BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2509 
2510       m_data[0]._mp_num = a.data()[0];
2511       m_data[0]._mp_den = b.data()[0];
2512       mpq_canonicalize(m_data);
2513       a.data()[0]._mp_d = nullptr;
2514       b.data()[0]._mp_d = nullptr;
2515    }
2516    // rvalue copy
2517    gmp_rational(gmp_rational&& o) noexcept
2518    {
2519       m_data[0]                 = o.m_data[0];
2520       o.m_data[0]._mp_num._mp_d = nullptr;
2521       o.m_data[0]._mp_den._mp_d = nullptr;
2522    }
2523    gmp_rational(const mpq_t o)
2524    {
2525       mpq_init(m_data);
2526       mpq_set(m_data, o);
2527    }
2528    gmp_rational(const mpz_t o)
2529    {
2530       mpq_init(m_data);
2531       mpq_set_z(m_data, o);
2532    }
2533    gmp_rational& operator=(const gmp_rational& o)
2534    {
2535       if (m_data[0]._mp_den._mp_d == nullptr)
2536          mpq_init(m_data);
2537       mpq_set(m_data, o.m_data);
2538       return *this;
2539    }
2540    // rvalue assign
2541    gmp_rational& operator=(gmp_rational&& o) noexcept
2542    {
2543       mpq_swap(m_data, o.m_data);
2544       return *this;
2545    }
2546 #ifdef BOOST_HAS_LONG_LONG
2547 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
2548    gmp_rational& operator=(unsigned long long i)
2549    {
2550       *this = static_cast<unsigned long>(i);
2551       return *this;
2552    }
2553 #else
2554    gmp_rational& operator=(unsigned long long i)
2555    {
2556       if (m_data[0]._mp_den._mp_d == nullptr)
2557          mpq_init(m_data);
2558       gmp_int zi;
2559       zi = i;
2560       mpq_set_z(m_data, zi.data());
2561       return *this;
2562    }
2563    gmp_rational& operator=(long long i)
2564    {
2565       if (m_data[0]._mp_den._mp_d == nullptr)
2566          mpq_init(m_data);
2567       bool neg = i < 0;
2568       *this    = boost::multiprecision::detail::unsigned_abs(i);
2569       if (neg)
2570          mpq_neg(m_data, m_data);
2571       return *this;
2572    }
2573 #endif
2574 #endif
2575    gmp_rational& operator=(unsigned long i)
2576    {
2577       if (m_data[0]._mp_den._mp_d == nullptr)
2578          mpq_init(m_data);
2579       mpq_set_ui(m_data, i, 1);
2580       return *this;
2581    }
2582    gmp_rational& operator=(long i)
2583    {
2584       if (m_data[0]._mp_den._mp_d == nullptr)
2585          mpq_init(m_data);
2586       mpq_set_si(m_data, i, 1);
2587       return *this;
2588    }
2589    gmp_rational& operator=(double d)
2590    {
2591       if (m_data[0]._mp_den._mp_d == nullptr)
2592          mpq_init(m_data);
2593       mpq_set_d(m_data, d);
2594       return *this;
2595    }
2596    template <class F>
2597    gmp_rational& assign_float(F a)
2598    {
2599       using default_ops::eval_add;
2600       using default_ops::eval_subtract;
2601       BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp;
2602 
2603       if (m_data[0]._mp_den._mp_d == nullptr)
2604          mpq_init(m_data);
2605 
2606       if (a == 0)
2607       {
2608          mpq_set_si(m_data, 0, 1);
2609          return *this;
2610       }
2611 
2612       if (a == 1)
2613       {
2614          mpq_set_si(m_data, 1, 1);
2615          return *this;
2616       }
2617 
2618       BOOST_MP_ASSERT(!BOOST_MP_ISINF(a));
2619       BOOST_MP_ASSERT(!BOOST_MP_ISNAN(a));
2620 
2621       int         e;
2622       F f, term;
2623       mpq_set_ui(m_data, 0, 1);
2624       mpq_set_ui(m_data, 0u, 1);
2625       gmp_rational t;
2626 
2627       f = frexp(a, &e);
2628 
2629       constexpr int shift = std::numeric_limits<int>::digits - 1;
2630 
2631       while (f != static_cast<F>(0.0f))
2632       {
2633          // extract int sized bits from f:
2634          f    = ldexp(f, shift);
2635          term = floor(f);
2636          e -= shift;
2637          mpq_mul_2exp(m_data, m_data, shift);
2638          t = static_cast<long>(term);
2639          eval_add(*this, t);
2640          f -= term;
2641       }
2642       if (e > 0)
2643          mpq_mul_2exp(m_data, m_data, static_cast<mp_bitcnt_t>(e));
2644       else if (e < 0)
2645          mpq_div_2exp(m_data, m_data, static_cast<mp_bitcnt_t>(-e));
2646       return *this;
2647    }
2648    gmp_rational& operator=(long double a)
2649    {
2650       return assign_float(a);
2651    }
2652 #ifdef BOOST_HAS_FLOAT128
2653    gmp_rational& operator=(float128_type a)
2654    {
2655       return assign_float(a);
2656    }
2657 #endif
2658 #ifdef BOOST_HAS_INT128
2659    gmp_rational& operator=(uint128_type i)
2660    {
2661       gmp_int gi;
2662       gi = i;
2663       return *this = gi;
2664    }
2665    gmp_rational& operator=(int128_type i)
2666    {
2667       gmp_int gi;
2668       gi = i;
2669       return *this = gi;
2670    }
2671 #endif
2672    gmp_rational& operator=(const char* s)
2673    {
2674       if (m_data[0]._mp_den._mp_d == nullptr)
2675          mpq_init(m_data);
2676       if (0 != mpq_set_str(m_data, s, 10))
2677          BOOST_MP_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid rational number.")));
2678       return *this;
2679    }
2680    gmp_rational& operator=(const gmp_int& o)
2681    {
2682       if (m_data[0]._mp_den._mp_d == nullptr)
2683          mpq_init(m_data);
2684       mpq_set_z(m_data, o.data());
2685       return *this;
2686    }
2687    gmp_rational& operator=(const mpq_t o)
2688    {
2689       if (m_data[0]._mp_den._mp_d == nullptr)
2690          mpq_init(m_data);
2691       mpq_set(m_data, o);
2692       return *this;
2693    }
2694    gmp_rational& operator=(const mpz_t o)
2695    {
2696       if (m_data[0]._mp_den._mp_d == nullptr)
2697          mpq_init(m_data);
2698       mpq_set_z(m_data, o);
2699       return *this;
2700    }
2701    void swap(gmp_rational& o)
2702    {
2703       mpq_swap(m_data, o.m_data);
2704    }
2705    std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags /*f*/) const
2706    {
2707       BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2708       // TODO make a better job of this including handling of f!!
2709       void* (*alloc_func_ptr)(size_t);
2710       void* (*realloc_func_ptr)(void*, size_t, size_t);
2711       void (*free_func_ptr)(void*, size_t);
2712       const char* ps = mpq_get_str(nullptr, 10, m_data);
2713       std::string s  = ps;
2714       mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
2715       (*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
2716       return s;
2717    }
2718    ~gmp_rational()
2719    {
2720       if (m_data[0]._mp_num._mp_d || m_data[0]._mp_den._mp_d)
2721          mpq_clear(m_data);
2722    }
2723    void negate()
2724    {
2725       BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2726       mpq_neg(m_data, m_data);
2727    }
2728    int compare(const gmp_rational& o) const
2729    {
2730       BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d && o.m_data[0]._mp_num._mp_d);
2731       return mpq_cmp(m_data, o.m_data);
2732    }
2733    template <class V>
2734    int compare(V v) const
2735    {
2736       gmp_rational d;
2737       d = v;
2738       return compare(d);
2739    }
2740    int compare(unsigned long v) const
2741    {
2742       BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2743       return mpq_cmp_ui(m_data, v, 1);
2744    }
2745    int compare(long v) const
2746    {
2747       BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2748       return mpq_cmp_si(m_data, v, 1);
2749    }
2750    mpq_t& data()
2751    {
2752       BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2753       return m_data;
2754    }
2755    const mpq_t& data() const
2756    {
2757       BOOST_MP_ASSERT(m_data[0]._mp_num._mp_d);
2758       return m_data;
2759    }
2760 
2761  protected:
2762    mpq_t m_data;
2763 };
2764 
2765 inline bool eval_is_zero(const gmp_rational& val)
2766 {
2767    return mpq_sgn(val.data()) == 0;
2768 }
2769 template <class T>
2770 inline bool eval_eq(gmp_rational& a, const T& b)
2771 {
2772    return a.compare(b) == 0;
2773 }
2774 template <class T>
2775 inline bool eval_lt(gmp_rational& a, const T& b)
2776 {
2777    return a.compare(b) < 0;
2778 }
2779 template <class T>
2780 inline bool eval_gt(gmp_rational& a, const T& b)
2781 {
2782    return a.compare(b) > 0;
2783 }
2784 
2785 inline void eval_add(gmp_rational& t, const gmp_rational& o)
2786 {
2787    mpq_add(t.data(), t.data(), o.data());
2788 }
2789 inline void eval_subtract(gmp_rational& t, const gmp_rational& o)
2790 {
2791    mpq_sub(t.data(), t.data(), o.data());
2792 }
2793 inline void eval_multiply(gmp_rational& t, const gmp_rational& o)
2794 {
2795    mpq_mul(t.data(), t.data(), o.data());
2796 }
2797 inline void eval_divide(gmp_rational& t, const gmp_rational& o)
2798 {
2799    if (eval_is_zero(o))
2800       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2801    mpq_div(t.data(), t.data(), o.data());
2802 }
2803 inline void eval_add(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2804 {
2805    mpq_add(t.data(), p.data(), o.data());
2806 }
2807 inline void eval_subtract(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2808 {
2809    mpq_sub(t.data(), p.data(), o.data());
2810 }
2811 inline void eval_multiply(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2812 {
2813    mpq_mul(t.data(), p.data(), o.data());
2814 }
2815 inline void eval_divide(gmp_rational& t, const gmp_rational& p, const gmp_rational& o)
2816 {
2817    if (eval_is_zero(o))
2818       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
2819    mpq_div(t.data(), p.data(), o.data());
2820 }
2821 //
2822 // operator with scalars:
2823 //
2824 inline void eval_add(gmp_rational& result, gmp_rational const& a, gmp_int const& b)
2825 {
2826    // we allow result and a to be the same object here:
2827    if (&a != &result)
2828    {
2829       mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2830       mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2831    }
2832    mpz_addmul(mpq_numref(result.data()), mpq_denref(a.data()), b.data());
2833    // no need to normalize, there can be no common divisor as long as a is already normalized.
2834 }
2835 inline void eval_add(gmp_rational& result, gmp_rational const& a, unsigned long b)
2836 {
2837    // we allow result and a to be the same object here:
2838    if (&a != &result)
2839    {
2840       mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2841       mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2842    }
2843    mpz_addmul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b);
2844    // no need to normalize, there can be no common divisor as long as a is already normalized.
2845 }
2846 inline void eval_add(gmp_rational& result, gmp_rational const& a, long b)
2847 {
2848    // we allow result and a to be the same object here:
2849    if (&a != &result)
2850    {
2851       mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2852       mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2853    }
2854 
2855    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
2856 
2857    if(b > 0)
2858       mpz_addmul_ui(mpq_numref(result.data()), mpq_denref(a.data()), static_cast<local_uint_type>(b));
2859    else
2860       mpz_submul_ui(mpq_numref(result.data()), mpq_denref(a.data()), static_cast<local_uint_type>(-b));
2861    // no need to normalize, there can be no common divisor as long as a is already normalized.
2862 }
2863 template <class T>
2864 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_add(gmp_rational& result, gmp_rational const& a, const T& b)
2865 {
2866    gmp_int t;
2867    t = b;
2868    eval_add(result, a, t);
2869 }
2870 template <class T>
2871 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_add(gmp_rational& result, const T& b, gmp_rational const& a)
2872 {
2873    eval_add(result, a, b);
2874 }
2875 template <class T>
2876 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_add(gmp_rational& result, const T& b)
2877 {
2878    eval_add(result, result, b);
2879 }
2880 inline void eval_subtract(gmp_rational& result, gmp_rational const& a, gmp_int const& b)
2881 {
2882    // we allow result and a to be the same object here:
2883    if (&a != &result)
2884    {
2885       mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2886       mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2887    }
2888    mpz_submul(mpq_numref(result.data()), mpq_denref(a.data()), b.data());
2889    // no need to normalize, there can be no common divisor as long as a is already normalized.
2890 }
2891 inline void eval_subtract(gmp_rational& result, gmp_rational const& a, unsigned long b)
2892 {
2893    // we allow result and a to be the same object here:
2894    if (&a != &result)
2895    {
2896       mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2897       mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2898    }
2899    mpz_submul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b);
2900    // no need to normalize, there can be no common divisor as long as a is already normalized.
2901 }
2902 inline void eval_subtract(gmp_rational& result, gmp_rational const& a, long b)
2903 {
2904    // we allow result and a to be the same object here:
2905    if (&a != &result)
2906    {
2907       mpz_set(mpq_numref(result.data()), mpq_numref(a.data()));
2908       mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2909    }
2910 
2911    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
2912 
2913    if(b > 0)
2914       mpz_submul_ui(mpq_numref(result.data()), mpq_denref(a.data()), static_cast<local_uint_type>(b));
2915    else
2916       mpz_addmul_ui(mpq_numref(result.data()), mpq_denref(a.data()), static_cast<local_uint_type>(-b));
2917    // no need to normalize, there can be no common divisor as long as a is already normalized.
2918 }
2919 template <class T>
2920 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_subtract(gmp_rational& result, gmp_rational const& a, const T& b)
2921 {
2922    gmp_int t;
2923    t = b;
2924    eval_subtract(result, a, t);
2925 }
2926 template <class T>
2927 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_subtract(gmp_rational& result, const T& b, gmp_rational const& a)
2928 {
2929    eval_subtract(result, a, b);
2930    result.negate();
2931 }
2932 template <class T>
2933 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_subtract(gmp_rational& result, const T& b)
2934 {
2935    eval_subtract(result, result, b);
2936 }
2937 
2938 inline void eval_multiply(gmp_rational& result, gmp_rational const& a, gmp_int const& b)
2939 {
2940    gmp_int g, t;
2941    mpz_gcd(g.data(), mpq_denref(a.data()), b.data());
2942    if (!mpz_fits_uint_p(g.data()) || (mpz_get_ui(g.data()) != 1))
2943    {
2944       // We get here if the gcd is not unity, this is true if the number is
2945       // too large for an unsigned long, or if we get an unsigned long and check against 1.
2946       eval_divide(t, b, g);
2947       mpz_mul(mpq_numref(result.data()), t.data(), mpq_numref(a.data()));
2948       mpz_divexact(mpq_denref(result.data()), mpq_denref(a.data()), g.data());
2949    }
2950    else
2951    {
2952       // gcd is 1.
2953       mpz_mul(mpq_numref(result.data()), mpq_numref(a.data()), b.data());
2954       if (&result != &a)
2955          mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2956    }
2957 }
2958 inline void eval_multiply(gmp_rational& result, gmp_rational const& a, unsigned long b)
2959 {
2960    if (b == 0)
2961    {
2962       mpq_set_ui(result.data(), b, 1);
2963       return;
2964    }
2965    if (mpz_sgn(mpq_numref(a.data())) == 0)
2966    {
2967       result = a;
2968       return;
2969    }
2970    unsigned long g = static_cast<unsigned long>(mpz_gcd_ui(nullptr, mpq_denref(a.data()), b));
2971    if (g != 1)
2972    {
2973       BOOST_MP_ASSERT(g);
2974       b /= g;
2975       mpz_mul_ui(mpq_numref(result.data()), mpq_numref(a.data()), b);
2976       mpz_divexact_ui(mpq_denref(result.data()), mpq_denref(a.data()), g);
2977    }
2978    else
2979    {
2980       mpz_mul_ui(mpq_numref(result.data()), mpq_numref(a.data()), b);
2981       if (&result != &a)
2982          mpz_set(mpq_denref(result.data()), mpq_denref(a.data()));
2983    }
2984 }
2985 inline void eval_multiply(gmp_rational& result, gmp_rational const& a, long b)
2986 {
2987    eval_multiply(result, a, boost::multiprecision::detail::unsigned_abs(b));
2988    if (b < 0)
2989       result.negate();
2990 }
2991 template <class T>
2992 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_multiply(gmp_rational& result, gmp_rational const& a, const T& b)
2993 {
2994    gmp_int t;
2995    t = b;
2996    eval_multiply(result, a, t);
2997 }
2998 template <class T>
2999 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_multiply(gmp_rational& result, const T& b, gmp_rational const& a)
3000 {
3001    eval_multiply(result, a, b);
3002 }
3003 template <class T>
3004 inline typename std::enable_if<boost::multiprecision::detail::is_integral<T>::value>::type eval_multiply(gmp_rational& result, const T& b)
3005 {
3006    eval_multiply(result, result, b);
3007 }
3008 
3009 inline int eval_get_sign(const gmp_rational& val)
3010 {
3011    return mpq_sgn(val.data());
3012 }
3013 template <class R>
3014 inline typename std::enable_if<number_category<R>::value == number_kind_floating_point>::type eval_convert_to(R* result, const gmp_rational& backend)
3015 {
3016    //
3017    // The generic conversion is as good as anything we can write here:
3018    //
3019    // This does not round correctly:
3020    //
3021    //*result = mpq_get_d(val.data());
3022    //
3023    // This does:
3024    //
3025    ::boost::multiprecision::detail::generic_convert_rational_to_float(*result, backend);
3026 }
3027 #ifdef BOOST_HAS_FLOAT128
3028 inline void eval_convert_to(float128_type* result, const gmp_rational& val)
3029 {
3030    using default_ops::eval_convert_to;
3031 
3032    gmp_int n, d;
3033    float128_type fn, fd;
3034    mpz_set(n.data(), mpq_numref(val.data()));
3035    mpz_set(d.data(), mpq_denref(val.data()));
3036 
3037    eval_convert_to(&fn, n);
3038    eval_convert_to(&fd, d);
3039 
3040    *result = fn / fd;
3041 }
3042 #endif
3043 
3044 template <class R>
3045 inline typename std::enable_if<number_category<R>::value == number_kind_integer>::type eval_convert_to(R* result, const gmp_rational& backend)
3046 {
3047    gmp_int n(mpq_numref(backend.data()));
3048    gmp_int d(mpq_denref(backend.data()));
3049    using default_ops::eval_divide;
3050    eval_divide(n, d);
3051    using default_ops::eval_convert_to;
3052    eval_convert_to(result, n);
3053 }
3054 
3055 inline void eval_abs(gmp_rational& result, const gmp_rational& val)
3056 {
3057    mpq_abs(result.data(), val.data());
3058 }
3059 
3060 inline void assign_components(gmp_rational& result, unsigned long v1, unsigned long v2)
3061 {
3062    if (v2 == 0u)
3063       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
3064 
3065    mpq_set_ui(result.data(), v1, v2);
3066    mpq_canonicalize(result.data());
3067 }
3068 inline void assign_components(gmp_rational& result, long v1, long v2)
3069 {
3070    if (v2 == 0)
3071       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
3072 
3073    using local_uint_type = typename boost::multiprecision::detail::make_unsigned<long>::type;
3074 
3075    if (v2 < 0)
3076       mpq_set_si(result.data(), -v1, static_cast<local_uint_type>(-v2));
3077    else
3078       mpq_set_si(result.data(), v1, static_cast<local_uint_type>(v2));
3079 
3080    mpq_canonicalize(result.data());
3081 }
3082 inline void assign_components(gmp_rational& result, gmp_int const& v1, gmp_int const& v2)
3083 {
3084    if (eval_is_zero(v2))
3085       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
3086 
3087    mpz_set(mpq_numref(result.data()), v1.data());
3088    mpz_set(mpq_denref(result.data()), v2.data());
3089    mpq_canonicalize(result.data());
3090 }
3091 template <class T, class U>
3092 void assign_components(gmp_rational& result, const T& a, const U& b)
3093 {
3094    gmp_int x, y;
3095 
3096    x = a;
3097    y = b;
3098 
3099    if (eval_is_zero(y))
3100       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
3101 
3102    std::swap(result.data()[0]._mp_num, x.data()[0]);
3103    std::swap(result.data()[0]._mp_den, y.data()[0]);
3104    mpq_canonicalize(result.data());
3105 }
3106 template <class U>
3107 void assign_components(gmp_rational& result, const gmp_int& a, const U& b)
3108 {
3109    gmp_int y;
3110 
3111    y = b;
3112 
3113    if (eval_is_zero(y))
3114       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
3115 
3116    mpz_set(&result.data()[0]._mp_num, a.data());
3117    std::swap(result.data()[0]._mp_den, y.data()[0]);
3118    mpq_canonicalize(result.data());
3119 }
3120 template <class T>
3121 void assign_components(gmp_rational& result, const T& a, const gmp_int& b)
3122 {
3123    if (eval_is_zero(b))
3124       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
3125 
3126    gmp_int x;
3127    x = a;
3128    std::swap(result.data()[0]._mp_num, x.data()[0]);
3129    mpz_set(&result.data()[0]._mp_den, b.data());
3130    mpq_canonicalize(result.data());
3131 }
3132 
3133 
3134 inline std::size_t hash_value(const gmp_rational& val)
3135 {
3136    std::size_t result = 0;
3137    for (int i = 0; i < std::abs(val.data()[0]._mp_num._mp_size); ++i)
3138       boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_num._mp_d[i]);
3139    for (int i = 0; i < std::abs(val.data()[0]._mp_den._mp_size); ++i)
3140       boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_den._mp_d[i]);
3141    boost::multiprecision::detail::hash_combine(result, val.data()[0]._mp_num._mp_size);
3142    return result;
3143 }
3144 
3145 //
3146 // Some useful helpers:
3147 //
3148 inline std::size_t used_gmp_int_bits(const gmp_int& val)
3149 {
3150    return eval_msb(val) - eval_lsb(val) + 1;
3151 }
3152 inline std::size_t used_gmp_rational_bits(const gmp_rational& val)
3153 {
3154    unsigned d2_d = static_cast<unsigned>(mpz_sizeinbase(mpq_denref(val.data()), 2) - mpz_scan1(mpq_denref(val.data()), 0));
3155    unsigned d2_n = static_cast<unsigned>(mpz_sizeinbase(mpq_numref(val.data()), 2) - mpz_scan1(mpq_numref(val.data()), 0));
3156    return (std::max)(d2_d, d2_n);
3157 }
3158 
3159 //
3160 // Some member functions that are dependent upon previous code go here:
3161 //
3162 template <unsigned Digits10>
3163 template <unsigned D>
3164 inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename std::enable_if<D <= Digits10>::type*)
3165 {
3166    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3167    mpf_set(this->m_data, o.data());
3168 }
3169 template <unsigned Digits10>
3170 template <unsigned D>
3171 inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename std::enable_if< !(D <= Digits10)>::type*)
3172 {
3173    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3174    mpf_set(this->m_data, o.data());
3175 }
3176 template <unsigned Digits10>
3177 inline gmp_float<Digits10>::gmp_float(const gmp_int& o)
3178 {
3179    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3180    mpf_set_z(this->data(), o.data());
3181 }
3182 template <unsigned Digits10>
3183 inline gmp_float<Digits10>::gmp_float(const gmp_rational& o)
3184 {
3185    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3186    mpf_set_q(this->data(), o.data());
3187 }
3188 template <unsigned Digits10>
3189 template <unsigned D>
3190 inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_float<D>& o)
3191 {
3192    if (this->m_data[0]._mp_d == nullptr)
3193       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3194    mpf_set(this->m_data, o.data());
3195    return *this;
3196 }
3197 template <unsigned Digits10>
3198 inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_int& o)
3199 {
3200    if (this->m_data[0]._mp_d == nullptr)
3201       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3202    mpf_set_z(this->data(), o.data());
3203    return *this;
3204 }
3205 template <unsigned Digits10>
3206 inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_rational& o)
3207 {
3208    if (this->m_data[0]._mp_d == nullptr)
3209       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : (unsigned)this->get_default_precision()));
3210    mpf_set_q(this->data(), o.data());
3211    return *this;
3212 }
3213 inline gmp_float<0>::gmp_float(const gmp_int& o) : requested_precision(get_default_precision())
3214 {
3215    if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3216    {
3217       std::size_t d2 = used_gmp_int_bits(o);
3218       std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(d2);
3219       if (d10 > requested_precision)
3220          requested_precision = static_cast<unsigned>(d10);
3221    }
3222    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
3223    mpf_set_z(this->data(), o.data());
3224 }
3225 inline gmp_float<0>::gmp_float(const gmp_rational& o) : requested_precision(get_default_precision())
3226 {
3227    if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3228    {
3229       std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(used_gmp_rational_bits(o));
3230       if (d10 > requested_precision)
3231          requested_precision = static_cast<unsigned>(d10);
3232    }
3233    mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
3234    mpf_set_q(this->data(), o.data());
3235 }
3236 inline gmp_float<0>& gmp_float<0>::operator=(const gmp_int& o)
3237 {
3238    if (this->m_data[0]._mp_d == nullptr)
3239    {
3240       requested_precision = this->get_default_precision();
3241       if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3242       {
3243          std::size_t d2 = used_gmp_int_bits(o);
3244          std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(d2);
3245          if (d10 > requested_precision)
3246             requested_precision = static_cast<unsigned>(d10);
3247       }
3248       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
3249    }
3250    else if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3251    {
3252       std::size_t d2 = used_gmp_int_bits(o);
3253       std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(d2);
3254       if (d10 > requested_precision)
3255          this->precision(static_cast<unsigned>(d10));
3256    }
3257    mpf_set_z(this->data(), o.data());
3258    return *this;
3259 }
3260 inline gmp_float<0>& gmp_float<0>::operator=(const gmp_rational& o)
3261 {
3262    if (this->m_data[0]._mp_d == nullptr)
3263    {
3264       requested_precision = this->get_default_precision();
3265       if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3266       {
3267          std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(used_gmp_rational_bits(o));
3268          if (d10 > requested_precision)
3269             requested_precision = static_cast<unsigned>(d10);
3270       }
3271       mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
3272    }
3273    else if (thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision)
3274    {
3275       std::size_t d10 = 1 + multiprecision::detail::digits2_2_10(used_gmp_rational_bits(o));
3276       if (d10 > requested_precision)
3277          this->precision(static_cast<unsigned>(d10));
3278    }
3279    mpf_set_q(this->data(), o.data());
3280    return *this;
3281 }
3282 inline gmp_int::gmp_int(const gmp_rational& o)
3283 {
3284    mpz_init(this->m_data);
3285    mpz_set_q(this->m_data, o.data());
3286 }
3287 inline gmp_int& gmp_int::operator=(const gmp_rational& o)
3288 {
3289    if (this->m_data[0]._mp_d == nullptr)
3290       mpz_init(this->m_data);
3291    mpz_set_q(this->m_data, o.data());
3292    return *this;
3293 }
3294 
3295 } //namespace backends
3296 
3297 template <expression_template_option ExpressionTemplates>
3298 struct component_type<number<gmp_rational, ExpressionTemplates> >
3299 {
3300    using type = number<gmp_int, ExpressionTemplates>;
3301 };
3302 
3303 template <expression_template_option ET>
3304 inline number<gmp_int, ET> numerator(const number<gmp_rational, ET>& val)
3305 {
3306    number<gmp_int, ET> result;
3307    mpz_set(result.backend().data(), (mpq_numref(val.backend().data())));
3308    return result;
3309 }
3310 template <expression_template_option ET>
3311 inline number<gmp_int, ET> denominator(const number<gmp_rational, ET>& val)
3312 {
3313    number<gmp_int, ET> result;
3314    mpz_set(result.backend().data(), (mpq_denref(val.backend().data())));
3315    return result;
3316 }
3317 
3318 namespace detail {
3319 
3320 template <>
3321 struct digits2<number<gmp_float<0>, et_on> >
3322 {
3323    static long value()
3324    {
3325       return static_cast<long>(multiprecision::detail::digits10_2_2(gmp_float<0>::thread_default_precision()));
3326    }
3327 };
3328 
3329 template <>
3330 struct digits2<number<gmp_float<0>, et_off> >
3331 {
3332    static long value()
3333    {
3334       return static_cast<long>(multiprecision::detail::digits10_2_2(gmp_float<0>::thread_default_precision()));
3335    }
3336 };
3337 
3338 template <>
3339 struct digits2<number<debug_adaptor<gmp_float<0> >, et_on> >
3340 {
3341    static long value()
3342    {
3343       return static_cast<long>(multiprecision::detail::digits10_2_2(gmp_float<0>::thread_default_precision()));
3344    }
3345 };
3346 
3347 template <>
3348 struct digits2<number<debug_adaptor<gmp_float<0> >, et_off> >
3349 {
3350    static long value()
3351    {
3352       return static_cast<long>(multiprecision::detail::digits10_2_2(gmp_float<0>::thread_default_precision()));
3353    }
3354 };
3355 
3356 template <unsigned Digits10>
3357 struct transcendental_reduction_type<boost::multiprecision::backends::gmp_float<Digits10> >
3358 {
3359    //
3360    // The type used for trigonometric reduction needs 3 times the precision of the base type.
3361    // This is double the precision of the original type, plus the largest exponent supported.
3362    // As a practical measure the largest argument supported is 1/eps, as supporting larger
3363    // arguments requires the division of argument by PI/2 to also be done at higher precision,
3364    // otherwise the result (an integer) can not be represented exactly.
3365    //
3366    // See ARGUMENT REDUCTION FOR HUGE ARGUMENTS. K C Ng.
3367    //
3368    using type = boost::multiprecision::backends::gmp_float<Digits10 * 3>;
3369 };
3370 
3371 
3372 } // namespace detail
3373 
3374 template <>
3375 struct number_category<detail::canonical<mpz_t, gmp_int>::type> : public std::integral_constant<int, number_kind_integer>
3376 {};
3377 template <>
3378 struct number_category<detail::canonical<mpq_t, gmp_rational>::type> : public std::integral_constant<int, number_kind_rational>
3379 {};
3380 template <>
3381 struct number_category<detail::canonical<mpf_t, gmp_float<0> >::type> : public std::integral_constant<int, number_kind_floating_point>
3382 {};
3383 
3384 namespace detail {
3385 template <>
3386 struct is_variable_precision<backends::gmp_float<0> > : public std::integral_constant<bool, true>
3387 {};
3388 } // namespace detail
3389 
3390 } // namespace multiprecision
3391 
3392 namespace math { namespace tools {
3393 
3394 #ifndef BOOST_MP_MATH_AVAILABLE
3395 
3396 template <typename T>
3397 inline int digits();
3398 
3399 template <typename T>
3400 inline T max_value();
3401 
3402 template <typename T>
3403 inline T min_value();
3404 
3405 #endif // BOOST_MP_MATH_AVAILABLE
3406 
3407 inline void set_output_precision(const boost::multiprecision::mpf_float& val, std::ostream& os)
3408 {
3409    const int sz_prec = static_cast<int>(val.precision());
3410 
3411    os << std::setprecision(sz_prec);
3412 }
3413 
3414 template <>
3415 inline int digits<boost::multiprecision::mpf_float>()
3416 #ifdef BOOST_MATH_NOEXCEPT
3417     noexcept
3418 #endif
3419 {
3420    return static_cast<int>(multiprecision::detail::digits10_2_2(boost::multiprecision::mpf_float::thread_default_precision()));
3421 }
3422 template <>
3423 inline int digits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >()
3424 #ifdef BOOST_MATH_NOEXCEPT
3425     noexcept
3426 #endif
3427 {
3428    return static_cast<int>(multiprecision::detail::digits10_2_2(boost::multiprecision::mpf_float::thread_default_precision()));
3429 }
3430 
3431 template <>
3432 inline boost::multiprecision::mpf_float
3433 max_value<boost::multiprecision::mpf_float>()
3434 {
3435    boost::multiprecision::mpf_float result(0.5);
3436    mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3437    return result;
3438 }
3439 
3440 template <>
3441 inline boost::multiprecision::mpf_float
3442 min_value<boost::multiprecision::mpf_float>()
3443 {
3444    boost::multiprecision::mpf_float result(0.5);
3445    mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3446    return result;
3447 }
3448 
3449 template <>
3450 inline boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off>
3451 max_value<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >()
3452 {
3453    boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> result(0.5);
3454    mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3455    return result;
3456 }
3457 
3458 template <>
3459 inline boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off>
3460 min_value<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> >()
3461 {
3462    boost::multiprecision::number<boost::multiprecision::gmp_float<0>, boost::multiprecision::et_off> result(0.5);
3463    mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3464    return result;
3465 }
3466 
3467 template <>
3468 inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >()
3469 #ifdef BOOST_MATH_NOEXCEPT
3470     noexcept
3471 #endif
3472 {
3473    return static_cast<int>(multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >::thread_default_precision()));
3474 }
3475 template <>
3476 inline int digits<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >()
3477 #ifdef BOOST_MATH_NOEXCEPT
3478     noexcept
3479 #endif
3480 {
3481    return static_cast<int>(multiprecision::detail::digits10_2_2(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >::thread_default_precision()));
3482 }
3483 
3484 template <>
3485 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >
3486 max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >()
3487 {
3488    return max_value<boost::multiprecision::mpf_float>().backend();
3489 }
3490 
3491 template <>
3492 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> >
3493 min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::mpf_float::backend_type> > >()
3494 {
3495    return min_value<boost::multiprecision::mpf_float>().backend();
3496 }
3497 
3498 template <>
3499 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off>
3500 max_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >()
3501 {
3502    return max_value<boost::multiprecision::mpf_float>().backend();
3503 }
3504 
3505 template <>
3506 inline boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off>
3507 min_value<boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::gmp_float<0> >, boost::multiprecision::et_off> >()
3508 {
3509    return min_value<boost::multiprecision::mpf_float>().backend();
3510 }
3511 
3512 }} // namespace math::tools
3513 
3514 } // namespace boost
3515 
3516 namespace std {
3517 
3518 //
3519 // numeric_limits [partial] specializations for the types declared in this header:
3520 //
3521 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3522 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >
3523 {
3524    using number_type = boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates>;
3525 
3526    //
3527    // min and max values chosen so as to not cause segfaults when calling
3528    // mpf_get_str on 64-bit Linux builds.  Possibly we could use larger
3529    // exponent values elsewhere.
3530    //
3531    static number_type calc_min()
3532    {
3533       number_type result(1);
3534       mpf_div_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3535       return result;
3536    }
3537    static number_type calc_max()
3538    {
3539       number_type result(1);
3540       mpf_mul_2exp(result.backend().data(), result.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1);
3541       return result;
3542    }
3543    static number_type calc_epsilon()
3544    {
3545       number_type result(1);
3546       mpf_div_2exp(result.backend().data(), result.backend().data(), std::numeric_limits<number_type>::digits - 1);
3547       return result;
3548    }
3549 
3550 
3551  public:
3552    static constexpr bool is_specialized = true;
3553    static number_type(min)()
3554    {
3555       // rely on C++11 thread safe initialization of statics:
3556       static const number_type value{calc_min()};
3557       return value;
3558    }
3559    static number_type(max)()
3560    {
3561       static number_type value{calc_max()};
3562       return value;
3563    }
3564    static constexpr number_type lowest()
3565    {
3566       return -(max)();
3567    }
3568    static constexpr int digits   = static_cast<int>((Digits10 * 1000L) / 301L + ((Digits10 * 1000L) % 301L ? 2 : 1));
3569    static constexpr int digits10 = Digits10;
3570    // Have to allow for a possible extra limb inside the gmp data structure:
3571    static constexpr int  max_digits10 = Digits10 + 3 + ((GMP_LIMB_BITS * 301L) / 1000L);
3572    static constexpr bool is_signed    = true;
3573    static constexpr bool is_integer   = false;
3574    static constexpr bool is_exact     = false;
3575    static constexpr int  radix        = 2;
3576    static number_type          epsilon()
3577    {
3578       static const number_type value{calc_epsilon()};
3579       return value;
3580    }
3581    // What value should this be????
3582    static number_type round_error()
3583    {
3584       return 1;
3585    }
3586    static constexpr long               min_exponent      = LONG_MIN;
3587    static constexpr long               min_exponent10    = (LONG_MIN / 1000) * 301L;
3588    static constexpr long               max_exponent      = LONG_MAX;
3589    static constexpr long               max_exponent10    = (LONG_MAX / 1000) * 301L;
3590    static constexpr bool               has_infinity      = false;
3591    static constexpr bool               has_quiet_NaN     = false;
3592    static constexpr bool               has_signaling_NaN = false;
3593    static constexpr float_denorm_style has_denorm        = denorm_absent;
3594    static constexpr bool               has_denorm_loss   = false;
3595    static constexpr number_type        infinity() { return number_type(); }
3596    static constexpr number_type        quiet_NaN() { return number_type(); }
3597    static constexpr number_type        signaling_NaN() { return number_type(); }
3598    static constexpr number_type        denorm_min() { return (min)(); }
3599    static constexpr bool               is_iec559       = false;
3600    static constexpr bool               is_bounded      = true;
3601    static constexpr bool               is_modulo       = false;
3602    static constexpr bool               traps           = true;
3603    static constexpr bool               tinyness_before = false;
3604    static constexpr float_round_style  round_style     = round_indeterminate;
3605 };
3606 
3607 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3608 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::digits;
3609 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3610 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::digits10;
3611 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3612 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_digits10;
3613 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3614 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_signed;
3615 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3616 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_integer;
3617 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3618 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_exact;
3619 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3620 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::radix;
3621 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3622 constexpr long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::min_exponent;
3623 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3624 constexpr long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::min_exponent10;
3625 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3626 constexpr long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_exponent;
3627 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3628 constexpr long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_exponent10;
3629 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3630 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_infinity;
3631 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3632 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_quiet_NaN;
3633 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3634 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_signaling_NaN;
3635 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3636 constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_denorm;
3637 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3638 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_denorm_loss;
3639 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3640 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_iec559;
3641 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3642 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_bounded;
3643 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3644 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_modulo;
3645 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3646 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::traps;
3647 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3648 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::tinyness_before;
3649 template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates>
3650 constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::round_style;
3651 
3652 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3653 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >
3654 {
3655    using number_type = boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates>;
3656 
3657  public:
3658    static constexpr bool is_specialized = false;
3659    static number_type(min)() { return number_type(); }
3660    static number_type(max)() { return number_type(); }
3661    static number_type                        lowest() { return number_type(); }
3662    static constexpr int                digits       = 0;
3663    static constexpr int                digits10     = 0;
3664    static constexpr int                max_digits10 = 0;
3665    static constexpr bool               is_signed    = false;
3666    static constexpr bool               is_integer   = false;
3667    static constexpr bool               is_exact     = false;
3668    static constexpr int                radix        = 0;
3669    static number_type                        epsilon() { return number_type(); }
3670    static number_type                        round_error() { return number_type(); }
3671    static constexpr int                min_exponent      = 0;
3672    static constexpr int                min_exponent10    = 0;
3673    static constexpr int                max_exponent      = 0;
3674    static constexpr int                max_exponent10    = 0;
3675    static constexpr bool               has_infinity      = false;
3676    static constexpr bool               has_quiet_NaN     = false;
3677    static constexpr bool               has_signaling_NaN = false;
3678    static constexpr float_denorm_style has_denorm        = denorm_absent;
3679    static constexpr bool               has_denorm_loss   = false;
3680    static number_type                        infinity() { return number_type(); }
3681    static number_type                        quiet_NaN() { return number_type(); }
3682    static number_type                        signaling_NaN() { return number_type(); }
3683    static number_type                        denorm_min() { return number_type(); }
3684    static constexpr bool               is_iec559       = false;
3685    static constexpr bool               is_bounded      = false;
3686    static constexpr bool               is_modulo       = false;
3687    static constexpr bool               traps           = false;
3688    static constexpr bool               tinyness_before = false;
3689    static constexpr float_round_style  round_style     = round_indeterminate;
3690 };
3691 
3692 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3693 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::digits;
3694 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3695 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::digits10;
3696 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3697 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_digits10;
3698 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3699 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_signed;
3700 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3701 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_integer;
3702 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3703 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_exact;
3704 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3705 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::radix;
3706 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3707 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::min_exponent;
3708 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3709 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::min_exponent10;
3710 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3711 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_exponent;
3712 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3713 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_exponent10;
3714 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3715 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_infinity;
3716 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3717 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_quiet_NaN;
3718 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3719 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_signaling_NaN;
3720 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3721 constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_denorm;
3722 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3723 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_denorm_loss;
3724 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3725 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_iec559;
3726 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3727 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_bounded;
3728 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3729 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_modulo;
3730 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3731 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::traps;
3732 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3733 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::tinyness_before;
3734 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3735 constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::round_style;
3736 
3737 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3738 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >
3739 {
3740    using number_type = boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates>;
3741 
3742  public:
3743    static constexpr bool is_specialized = true;
3744    //
3745    // Largest and smallest numbers are bounded only by available memory, set
3746    // to zero:
3747    //
3748    static number_type(min)()
3749    {
3750       return number_type();
3751    }
3752    static number_type(max)()
3753    {
3754       return number_type();
3755    }
3756    static number_type                        lowest() { return (min)(); }
3757    static constexpr int                digits       = INT_MAX;
3758    static constexpr int                digits10     = (INT_MAX / 1000) * 301L;
3759    static constexpr int                max_digits10 = digits10 + 3;
3760    static constexpr bool               is_signed    = true;
3761    static constexpr bool               is_integer   = true;
3762    static constexpr bool               is_exact     = true;
3763    static constexpr int                radix        = 2;
3764    static number_type                        epsilon() { return number_type(); }
3765    static number_type                        round_error() { return number_type(); }
3766    static constexpr int                min_exponent      = 0;
3767    static constexpr int                min_exponent10    = 0;
3768    static constexpr int                max_exponent      = 0;
3769    static constexpr int                max_exponent10    = 0;
3770    static constexpr bool               has_infinity      = false;
3771    static constexpr bool               has_quiet_NaN     = false;
3772    static constexpr bool               has_signaling_NaN = false;
3773    static constexpr float_denorm_style has_denorm        = denorm_absent;
3774    static constexpr bool               has_denorm_loss   = false;
3775    static number_type                        infinity() { return number_type(); }
3776    static number_type                        quiet_NaN() { return number_type(); }
3777    static number_type                        signaling_NaN() { return number_type(); }
3778    static number_type                        denorm_min() { return number_type(); }
3779    static constexpr bool               is_iec559       = false;
3780    static constexpr bool               is_bounded      = false;
3781    static constexpr bool               is_modulo       = false;
3782    static constexpr bool               traps           = false;
3783    static constexpr bool               tinyness_before = false;
3784    static constexpr float_round_style  round_style     = round_toward_zero;
3785 };
3786 
3787 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3788 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::digits;
3789 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3790 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::digits10;
3791 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3792 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_digits10;
3793 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3794 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_signed;
3795 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3796 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_integer;
3797 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3798 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_exact;
3799 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3800 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::radix;
3801 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3802 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::min_exponent;
3803 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3804 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::min_exponent10;
3805 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3806 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_exponent;
3807 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3808 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_exponent10;
3809 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3810 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_infinity;
3811 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3812 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_quiet_NaN;
3813 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3814 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_signaling_NaN;
3815 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3816 constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_denorm;
3817 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3818 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_denorm_loss;
3819 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3820 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_iec559;
3821 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3822 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_bounded;
3823 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3824 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_modulo;
3825 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3826 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::traps;
3827 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3828 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::tinyness_before;
3829 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3830 constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::round_style;
3831 
3832 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3833 class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >
3834 {
3835    using number_type = boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates>;
3836 
3837  public:
3838    static constexpr bool is_specialized = true;
3839    //
3840    // Largest and smallest numbers are bounded only by available memory, set
3841    // to zero:
3842    //
3843    static number_type(min)()
3844    {
3845       return number_type();
3846    }
3847    static number_type(max)()
3848    {
3849       return number_type();
3850    }
3851    static number_type lowest() { return (min)(); }
3852    // Digits are unbounded, use zero for now:
3853    static constexpr int                digits       = INT_MAX;
3854    static constexpr int                digits10     = (INT_MAX / 1000) * 301L;
3855    static constexpr int                max_digits10 = digits10 + 3;
3856    static constexpr bool               is_signed    = true;
3857    static constexpr bool               is_integer   = false;
3858    static constexpr bool               is_exact     = true;
3859    static constexpr int                radix        = 2;
3860    static number_type                        epsilon() { return number_type(); }
3861    static number_type                        round_error() { return number_type(); }
3862    static constexpr int                min_exponent      = 0;
3863    static constexpr int                min_exponent10    = 0;
3864    static constexpr int                max_exponent      = 0;
3865    static constexpr int                max_exponent10    = 0;
3866    static constexpr bool               has_infinity      = false;
3867    static constexpr bool               has_quiet_NaN     = false;
3868    static constexpr bool               has_signaling_NaN = false;
3869    static constexpr float_denorm_style has_denorm        = denorm_absent;
3870    static constexpr bool               has_denorm_loss   = false;
3871    static number_type                        infinity() { return number_type(); }
3872    static number_type                        quiet_NaN() { return number_type(); }
3873    static number_type                        signaling_NaN() { return number_type(); }
3874    static number_type                        denorm_min() { return (min)(); }
3875    static constexpr bool               is_iec559       = false;
3876    static constexpr bool               is_bounded      = false;
3877    static constexpr bool               is_modulo       = false;
3878    static constexpr bool               traps           = false;
3879    static constexpr bool               tinyness_before = false;
3880    static constexpr float_round_style  round_style     = round_toward_zero;
3881 };
3882 
3883 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3884 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::digits;
3885 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3886 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::digits10;
3887 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3888 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_digits10;
3889 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3890 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_signed;
3891 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3892 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_integer;
3893 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3894 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_exact;
3895 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3896 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::radix;
3897 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3898 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::min_exponent;
3899 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3900 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::min_exponent10;
3901 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3902 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_exponent;
3903 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3904 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_exponent10;
3905 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3906 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_infinity;
3907 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3908 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_quiet_NaN;
3909 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3910 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_signaling_NaN;
3911 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3912 constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_denorm;
3913 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3914 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_denorm_loss;
3915 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3916 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_iec559;
3917 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3918 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_bounded;
3919 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3920 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_modulo;
3921 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3922 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::traps;
3923 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3924 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::tinyness_before;
3925 template <boost::multiprecision::expression_template_option ExpressionTemplates>
3926 constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::round_style;
3927 
3928 #ifdef BOOST_MSVC
3929 #pragma warning(pop)
3930 #endif
3931 
3932 } // namespace std
3933 
3934 namespace Eigen
3935 {
3936 
3937    template <class B1, class B2>
3938    struct NumTraitsImp;
3939 
3940    template <boost::multiprecision::expression_template_option ExpressionTemplates>
3941    struct NumTraitsImp<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates>, boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >
3942    {
3943       using self_type = boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates>;
3944       using Real = typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type;
3945       using NonInteger = self_type; // Not correct but we can't do much better??
3946       using Literal = double;
3947       using Nested = self_type;
3948       enum
3949       {
3950          IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex,
3951          IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer,
3952          ReadCost = 1,
3953          AddCost = 4,
3954          MulCost = 8,
3955          IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true,
3956          RequireInitialization = 1,
3957       };
3958 
3959       static Real highest() noexcept
3960       {
3961          return boost::math::tools::max_value<Real>();
3962       }
3963       static Real lowest() noexcept
3964       {
3965          return boost::math::tools::min_value<Real>();
3966       }
3967       static int digits() noexcept
3968       {
3969          return boost::math::tools::digits<Real>();
3970       }
3971       static int digits10()
3972       {
3973          return Real::thread_default_precision();
3974       }
3975       static Real epsilon()
3976       {
3977          return ldexp(Real(1), 1 - digits());
3978       }
3979       static Real dummy_precision()
3980       {
3981          return 1000 * epsilon();
3982       }
3983       static constexpr long min_exponent() noexcept
3984       {
3985          return LONG_MIN;
3986       }
3987       static constexpr long max_exponent() noexcept
3988       {
3989          return LONG_MAX;
3990       }
3991       static Real infinity()
3992       {
3993          return Real();
3994       }
3995       static Real quiet_NaN()
3996       {
3997          return Real();
3998       }
3999    };
4000 
4001 }
4002 
4003 
4004 #endif