| /////////////////////////////////////////////////////////////////////////////// |
| // Copyright 2011 John Maddock. Distributed under the Boost |
| // Software License, Version 1.0. (See accompanying file |
| // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| #ifndef BOOST_MATH_ER_GMP_BACKEND_HPP |
| #define BOOST_MATH_ER_GMP_BACKEND_HPP |
| |
| #include <boost/multiprecision/number.hpp> |
| #include <boost/multiprecision/detail/integer_ops.hpp> |
| #include <boost/multiprecision/detail/big_lanczos.hpp> |
| #include <boost/multiprecision/detail/digits.hpp> |
| #include <boost/math/special_functions/fpclassify.hpp> |
| #include <boost/cstdint.hpp> |
| #ifdef BOOST_MSVC |
| # pragma warning(push) |
| # pragma warning(disable:4127) |
| #endif |
| #include <gmp.h> |
| #ifdef BOOST_MSVC |
| # pragma warning(pop) |
| #endif |
| #include <cmath> |
| #include <limits> |
| #include <climits> |
| |
| namespace boost{ |
| namespace multiprecision{ |
| namespace backends{ |
| |
| #ifdef BOOST_MSVC |
| // warning C4127: conditional expression is constant |
| #pragma warning(push) |
| #pragma warning(disable:4127) |
| #endif |
| |
| template <unsigned digits10> |
| struct gmp_float; |
| struct gmp_int; |
| struct gmp_rational; |
| |
| } // namespace backends |
| |
| template<> |
| struct number_category<backends::gmp_int> : public mpl::int_<number_kind_integer>{}; |
| template<> |
| struct number_category<backends::gmp_rational> : public mpl::int_<number_kind_rational>{}; |
| template <unsigned digits10> |
| struct number_category<backends::gmp_float<digits10> > : public mpl::int_<number_kind_floating_point>{}; |
| |
| namespace backends{ |
| // |
| // Within this file, the only functions we mark as noexcept are those that manipulate |
| // (but don't create) an mpf_t. All other types may allocate at pretty much any time |
| // via a user-supplied allocator, and therefore throw. |
| // |
| namespace detail{ |
| |
| template <unsigned digits10> |
| struct gmp_float_imp |
| { |
| typedef mpl::list<long, long long> signed_types; |
| typedef mpl::list<unsigned long, unsigned long long> unsigned_types; |
| typedef mpl::list<double, long double> float_types; |
| typedef long exponent_type; |
| |
| gmp_float_imp() BOOST_NOEXCEPT {} |
| |
| gmp_float_imp(const gmp_float_imp& o) |
| { |
| // |
| // We have to do an init followed by a set here, otherwise *this may be at |
| // a lower precision than o: seems like mpf_init_set copies just enough bits |
| // to get the right value, but if it's then used in further calculations |
| // things go badly wrong!! |
| // |
| mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| if(o.m_data[0]._mp_d) |
| mpf_set(m_data, o.m_data); |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_float_imp(gmp_float_imp&& o) BOOST_NOEXCEPT |
| { |
| m_data[0] = o.m_data[0]; |
| o.m_data[0]._mp_d = 0; |
| } |
| #endif |
| gmp_float_imp& operator = (const gmp_float_imp& o) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| if(o.m_data[0]._mp_d) |
| mpf_set(m_data, o.m_data); |
| return *this; |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_float_imp& operator = (gmp_float_imp&& o) BOOST_NOEXCEPT |
| { |
| mpf_swap(m_data, o.m_data); |
| return *this; |
| } |
| #endif |
| gmp_float_imp& operator = (unsigned long long i) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| unsigned long long mask = ((1uLL << std::numeric_limits<unsigned>::digits) - 1); |
| unsigned shift = 0; |
| mpf_t t; |
| mpf_init2(t, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| mpf_set_ui(m_data, 0); |
| while(i) |
| { |
| mpf_set_ui(t, static_cast<unsigned>(i & mask)); |
| if(shift) |
| mpf_mul_2exp(t, t, shift); |
| mpf_add(m_data, m_data, t); |
| shift += std::numeric_limits<unsigned>::digits; |
| i >>= std::numeric_limits<unsigned>::digits; |
| } |
| mpf_clear(t); |
| return *this; |
| } |
| gmp_float_imp& operator = (long long i) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| bool neg = i < 0; |
| *this = static_cast<unsigned long long>(boost::multiprecision::detail::unsigned_abs(i)); |
| if(neg) |
| mpf_neg(m_data, m_data); |
| return *this; |
| } |
| gmp_float_imp& operator = (unsigned long i) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| mpf_set_ui(m_data, i); |
| return *this; |
| } |
| gmp_float_imp& operator = (long i) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| mpf_set_si(m_data, i); |
| return *this; |
| } |
| gmp_float_imp& operator = (double d) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| mpf_set_d(m_data, d); |
| return *this; |
| } |
| gmp_float_imp& operator = (long double a) |
| { |
| using std::frexp; |
| using std::ldexp; |
| using std::floor; |
| |
| if(m_data[0]._mp_d == 0) |
| mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| |
| if (a == 0) { |
| mpf_set_si(m_data, 0); |
| return *this; |
| } |
| |
| if (a == 1) { |
| mpf_set_si(m_data, 1); |
| return *this; |
| } |
| |
| BOOST_ASSERT(!(boost::math::isinf)(a)); |
| BOOST_ASSERT(!(boost::math::isnan)(a)); |
| |
| int e; |
| long double f, term; |
| mpf_set_ui(m_data, 0u); |
| |
| f = frexp(a, &e); |
| |
| static const int shift = std::numeric_limits<int>::digits - 1; |
| |
| while(f) |
| { |
| // extract int sized bits from f: |
| f = ldexp(f, shift); |
| term = floor(f); |
| e -= shift; |
| mpf_mul_2exp(m_data, m_data, shift); |
| if(term > 0) |
| mpf_add_ui(m_data, m_data, static_cast<unsigned>(term)); |
| else |
| mpf_sub_ui(m_data, m_data, static_cast<unsigned>(-term)); |
| f -= term; |
| } |
| if(e > 0) |
| mpf_mul_2exp(m_data, m_data, e); |
| else if(e < 0) |
| mpf_div_2exp(m_data, m_data, -e); |
| return *this; |
| } |
| gmp_float_imp& operator = (const char* s) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : get_default_precision())); |
| if(0 != mpf_set_str(m_data, s, 10)) |
| BOOST_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid floating point number."))); |
| return *this; |
| } |
| void swap(gmp_float_imp& o) BOOST_NOEXCEPT |
| { |
| mpf_swap(m_data, o.m_data); |
| } |
| std::string str(std::streamsize digits, std::ios_base::fmtflags f)const |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| |
| bool scientific = (f & std::ios_base::scientific) == std::ios_base::scientific; |
| bool fixed = (f & std::ios_base::fixed) == std::ios_base::fixed; |
| std::streamsize org_digits(digits); |
| |
| if(scientific && digits) |
| ++digits; |
| |
| std::string result; |
| mp_exp_t e; |
| void *(*alloc_func_ptr) (size_t); |
| void *(*realloc_func_ptr) (void *, size_t, size_t); |
| void (*free_func_ptr) (void *, size_t); |
| mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr); |
| |
| if(mpf_sgn(m_data) == 0) |
| { |
| e = 0; |
| result = "0"; |
| if(fixed && digits) |
| ++digits; |
| } |
| else |
| { |
| char* ps = mpf_get_str (0, &e, 10, static_cast<std::size_t>(digits), m_data); |
| --e; // To match with what our formatter expects. |
| if(fixed && e != -1) |
| { |
| // Oops we actually need a different number of digits to what we asked for: |
| (*free_func_ptr)((void*)ps, std::strlen(ps) + 1); |
| digits += e + 1; |
| if(digits == 0) |
| { |
| // We need to get *all* the digits and then possibly round up, |
| // we end up with either "0" or "1" as the result. |
| ps = mpf_get_str (0, &e, 10, 0, m_data); |
| --e; |
| unsigned offset = *ps == '-' ? 1 : 0; |
| if(ps[offset] > '5') |
| { |
| ++e; |
| ps[offset] = '1'; |
| ps[offset + 1] = 0; |
| } |
| else if(ps[offset] == '5') |
| { |
| unsigned i = offset + 1; |
| bool round_up = false; |
| while(ps[i] != 0) |
| { |
| if(ps[i] != '0') |
| { |
| round_up = true; |
| break; |
| } |
| } |
| if(round_up) |
| { |
| ++e; |
| ps[offset] = '1'; |
| ps[offset + 1] = 0; |
| } |
| else |
| { |
| ps[offset] = '0'; |
| ps[offset + 1] = 0; |
| } |
| } |
| else |
| { |
| ps[offset] = '0'; |
| ps[offset + 1] = 0; |
| } |
| } |
| else if(digits > 0) |
| { |
| ps = mpf_get_str (0, &e, 10, static_cast<std::size_t>(digits), m_data); |
| --e; // To match with what our formatter expects. |
| } |
| else |
| { |
| ps = mpf_get_str (0, &e, 10, 1, m_data); |
| --e; |
| unsigned offset = *ps == '-' ? 1 : 0; |
| ps[offset] = '0'; |
| ps[offset + 1] = 0; |
| } |
| } |
| result = ps; |
| (*free_func_ptr)((void*)ps, std::strlen(ps) + 1); |
| } |
| boost::multiprecision::detail::format_float_string(result, e, org_digits, f, mpf_sgn(m_data) == 0); |
| return result; |
| } |
| ~gmp_float_imp() BOOST_NOEXCEPT |
| { |
| if(m_data[0]._mp_d) |
| mpf_clear(m_data); |
| } |
| void negate() BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| mpf_neg(m_data, m_data); |
| } |
| int compare(const gmp_float<digits10>& o)const BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d && o.m_data[0]._mp_d); |
| return mpf_cmp(m_data, o.m_data); |
| } |
| int compare(long i)const BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| return mpf_cmp_si(m_data, i); |
| } |
| int compare(unsigned long i)const BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| return mpf_cmp_ui(m_data, i); |
| } |
| template <class V> |
| typename enable_if<is_arithmetic<V>, int>::type compare(V v)const |
| { |
| gmp_float<digits10> d; |
| d = v; |
| return compare(d); |
| } |
| mpf_t& data() BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| return m_data; |
| } |
| const mpf_t& data()const BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| return m_data; |
| } |
| protected: |
| mpf_t m_data; |
| static unsigned& get_default_precision() BOOST_NOEXCEPT |
| { |
| static unsigned val = 50; |
| return val; |
| } |
| }; |
| |
| } // namespace detail |
| |
| struct gmp_int; |
| struct gmp_rational; |
| |
| template <unsigned digits10> |
| struct gmp_float : public detail::gmp_float_imp<digits10> |
| { |
| gmp_float() |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); |
| } |
| gmp_float(const gmp_float& o) : detail::gmp_float_imp<digits10>(o) {} |
| template <unsigned D> |
| gmp_float(const gmp_float<D>& o, typename enable_if_c<D <= digits10>::type* = 0); |
| template <unsigned D> |
| explicit gmp_float(const gmp_float<D>& o, typename disable_if_c<D <= digits10>::type* = 0); |
| gmp_float(const gmp_int& o); |
| gmp_float(const gmp_rational& o); |
| gmp_float(const mpf_t val) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); |
| mpf_set(this->m_data, val); |
| } |
| gmp_float(const mpz_t val) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); |
| mpf_set_z(this->m_data, val); |
| } |
| gmp_float(const mpq_t val) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); |
| mpf_set_q(this->m_data, val); |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_float(gmp_float&& o) BOOST_NOEXCEPT : detail::gmp_float_imp<digits10>(static_cast<detail::gmp_float_imp<digits10>&&>(o)) {} |
| #endif |
| gmp_float& operator=(const gmp_float& o) |
| { |
| *static_cast<detail::gmp_float_imp<digits10>*>(this) = static_cast<detail::gmp_float_imp<digits10> const&>(o); |
| return *this; |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_float& operator=(gmp_float&& o) BOOST_NOEXCEPT |
| { |
| *static_cast<detail::gmp_float_imp<digits10>*>(this) = static_cast<detail::gmp_float_imp<digits10>&&>(o); |
| return *this; |
| } |
| #endif |
| template <unsigned D> |
| gmp_float& operator=(const gmp_float<D>& o); |
| gmp_float& operator=(const gmp_int& o); |
| gmp_float& operator=(const gmp_rational& o); |
| gmp_float& operator=(const mpf_t val) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); |
| mpf_set(this->m_data, val); |
| return *this; |
| } |
| gmp_float& operator=(const mpz_t val) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); |
| mpf_set_z(this->m_data, val); |
| return *this; |
| } |
| gmp_float& operator=(const mpq_t val) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); |
| mpf_set_q(this->m_data, val); |
| return *this; |
| } |
| template <class V> |
| gmp_float& operator=(const V& v) |
| { |
| *static_cast<detail::gmp_float_imp<digits10>*>(this) = v; |
| return *this; |
| } |
| }; |
| |
| template <> |
| struct gmp_float<0> : public detail::gmp_float_imp<0> |
| { |
| gmp_float() |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); |
| } |
| gmp_float(const mpf_t val) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); |
| mpf_set(this->m_data, val); |
| } |
| gmp_float(const mpz_t val) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); |
| mpf_set_z(this->m_data, val); |
| } |
| gmp_float(const mpq_t val) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); |
| mpf_set_q(this->m_data, val); |
| } |
| gmp_float(const gmp_float& o) : detail::gmp_float_imp<0>(o) {} |
| template <unsigned D> |
| gmp_float(const gmp_float<D>& o) |
| { |
| mpf_init2(this->m_data, mpf_get_prec(o.data())); |
| mpf_set(this->m_data, o.data()); |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_float(gmp_float&& o) BOOST_NOEXCEPT : detail::gmp_float_imp<0>(static_cast<detail::gmp_float_imp<0>&&>(o)) {} |
| #endif |
| gmp_float(const gmp_int& o); |
| gmp_float(const gmp_rational& o); |
| gmp_float(const gmp_float& o, unsigned digits10) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); |
| mpf_set(this->m_data, o.data()); |
| } |
| |
| gmp_float& operator=(const gmp_float& o) |
| { |
| *static_cast<detail::gmp_float_imp<0>*>(this) = static_cast<detail::gmp_float_imp<0> const&>(o); |
| return *this; |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_float& operator=(gmp_float&& o) BOOST_NOEXCEPT |
| { |
| *static_cast<detail::gmp_float_imp<0>*>(this) = static_cast<detail::gmp_float_imp<0> &&>(o); |
| return *this; |
| } |
| #endif |
| template <unsigned D> |
| gmp_float& operator=(const gmp_float<D>& o) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| { |
| mpf_init2(this->m_data, mpf_get_prec(o.data())); |
| } |
| else |
| { |
| mpf_set_prec(this->m_data, mpf_get_prec(o.data())); |
| } |
| mpf_set(this->m_data, o.data()); |
| return *this; |
| } |
| gmp_float& operator=(const gmp_int& o); |
| gmp_float& operator=(const gmp_rational& o); |
| gmp_float& operator=(const mpf_t val) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); |
| mpf_set(this->m_data, val); |
| return *this; |
| } |
| gmp_float& operator=(const mpz_t val) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); |
| mpf_set_z(this->m_data, val); |
| return *this; |
| } |
| gmp_float& operator=(const mpq_t val) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); |
| mpf_set_q(this->m_data, val); |
| return *this; |
| } |
| template <class V> |
| gmp_float& operator=(const V& v) |
| { |
| *static_cast<detail::gmp_float_imp<0>*>(this) = v; |
| return *this; |
| } |
| static unsigned default_precision() BOOST_NOEXCEPT |
| { |
| return get_default_precision(); |
| } |
| static void default_precision(unsigned v) BOOST_NOEXCEPT |
| { |
| get_default_precision() = v; |
| } |
| unsigned precision()const BOOST_NOEXCEPT |
| { |
| return multiprecision::detail::digits2_2_10(mpf_get_prec(this->m_data)); |
| } |
| void precision(unsigned digits10) BOOST_NOEXCEPT |
| { |
| mpf_set_prec(this->m_data, multiprecision::detail::digits10_2_2(digits10)); |
| } |
| }; |
| |
| template <unsigned digits10, class T> |
| inline typename enable_if_c<is_arithmetic<T>::value, bool>::type eval_eq(const gmp_float<digits10>& a, const T& b) BOOST_NOEXCEPT |
| { |
| return a.compare(b) == 0; |
| } |
| template <unsigned digits10, class T> |
| inline typename enable_if_c<is_arithmetic<T>::value, bool>::type eval_lt(const gmp_float<digits10>& a, const T& b) BOOST_NOEXCEPT |
| { |
| return a.compare(b) < 0; |
| } |
| template <unsigned digits10, class T> |
| inline typename enable_if_c<is_arithmetic<T>::value, bool>::type eval_gt(const gmp_float<digits10>& a, const T& b) BOOST_NOEXCEPT |
| { |
| return a.compare(b) > 0; |
| } |
| |
| template <unsigned D1, unsigned D2> |
| inline void eval_add(gmp_float<D1>& result, const gmp_float<D2>& o) |
| { |
| mpf_add(result.data(), result.data(), o.data()); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_subtract(gmp_float<D1>& result, const gmp_float<D2>& o) |
| { |
| mpf_sub(result.data(), result.data(), o.data()); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_multiply(gmp_float<D1>& result, const gmp_float<D2>& o) |
| { |
| mpf_mul(result.data(), result.data(), o.data()); |
| } |
| template <unsigned digits10> |
| inline bool eval_is_zero(const gmp_float<digits10>& val) BOOST_NOEXCEPT |
| { |
| return mpf_sgn(val.data()) == 0; |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_divide(gmp_float<D1>& result, const gmp_float<D2>& o) |
| { |
| if(eval_is_zero(o)) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpf_div(result.data(), result.data(), o.data()); |
| } |
| template <unsigned digits10> |
| inline void eval_add(gmp_float<digits10>& result, unsigned long i) |
| { |
| mpf_add_ui(result.data(), result.data(), i); |
| } |
| template <unsigned digits10> |
| inline void eval_subtract(gmp_float<digits10>& result, unsigned long i) |
| { |
| mpf_sub_ui(result.data(), result.data(), i); |
| } |
| template <unsigned digits10> |
| inline void eval_multiply(gmp_float<digits10>& result, unsigned long i) |
| { |
| mpf_mul_ui(result.data(), result.data(), i); |
| } |
| template <unsigned digits10> |
| inline void eval_divide(gmp_float<digits10>& result, unsigned long i) |
| { |
| if(i == 0) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpf_div_ui(result.data(), result.data(), i); |
| } |
| template <unsigned digits10> |
| inline void eval_add(gmp_float<digits10>& result, long i) |
| { |
| if(i > 0) |
| mpf_add_ui(result.data(), result.data(), i); |
| else |
| mpf_sub_ui(result.data(), result.data(), std::abs(i)); |
| } |
| template <unsigned digits10> |
| inline void eval_subtract(gmp_float<digits10>& result, long i) |
| { |
| if(i > 0) |
| mpf_sub_ui(result.data(), result.data(), i); |
| else |
| mpf_add_ui(result.data(), result.data(), std::abs(i)); |
| } |
| template <unsigned digits10> |
| inline void eval_multiply(gmp_float<digits10>& result, long i) |
| { |
| mpf_mul_ui(result.data(), result.data(), std::abs(i)); |
| if(i < 0) |
| mpf_neg(result.data(), result.data()); |
| } |
| template <unsigned digits10> |
| inline void eval_divide(gmp_float<digits10>& result, long i) |
| { |
| if(i == 0) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpf_div_ui(result.data(), result.data(), std::abs(i)); |
| if(i < 0) |
| mpf_neg(result.data(), result.data()); |
| } |
| // |
| // Specialised 3 arg versions of the basic operators: |
| // |
| template <unsigned D1, unsigned D2, unsigned D3> |
| inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y) |
| { |
| mpf_add(a.data(), x.data(), y.data()); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y) |
| { |
| mpf_add_ui(a.data(), x.data(), y); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_add(gmp_float<D1>& a, const gmp_float<D2>& x, long y) |
| { |
| if(y < 0) |
| mpf_sub_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y)); |
| else |
| mpf_add_ui(a.data(), x.data(), y); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_add(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y) |
| { |
| mpf_add_ui(a.data(), y.data(), x); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_add(gmp_float<D1>& a, long x, const gmp_float<D2>& y) |
| { |
| if(x < 0) |
| { |
| mpf_ui_sub(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data()); |
| mpf_neg(a.data(), a.data()); |
| } |
| else |
| mpf_add_ui(a.data(), y.data(), x); |
| } |
| template <unsigned D1, unsigned D2, unsigned D3> |
| inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y) |
| { |
| mpf_sub(a.data(), x.data(), y.data()); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y) |
| { |
| mpf_sub_ui(a.data(), x.data(), y); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_subtract(gmp_float<D1>& a, const gmp_float<D2>& x, long y) |
| { |
| if(y < 0) |
| mpf_add_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y)); |
| else |
| mpf_sub_ui(a.data(), x.data(), y); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_subtract(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y) |
| { |
| mpf_ui_sub(a.data(), x, y.data()); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_subtract(gmp_float<D1>& a, long x, const gmp_float<D2>& y) |
| { |
| if(x < 0) |
| { |
| mpf_add_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x)); |
| mpf_neg(a.data(), a.data()); |
| } |
| else |
| mpf_ui_sub(a.data(), x, y.data()); |
| } |
| |
| template <unsigned D1, unsigned D2, unsigned D3> |
| inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y) |
| { |
| mpf_mul(a.data(), x.data(), y.data()); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y) |
| { |
| mpf_mul_ui(a.data(), x.data(), y); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_multiply(gmp_float<D1>& a, const gmp_float<D2>& x, long y) |
| { |
| if(y < 0) |
| { |
| mpf_mul_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y)); |
| a.negate(); |
| } |
| else |
| mpf_mul_ui(a.data(), x.data(), y); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_multiply(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y) |
| { |
| mpf_mul_ui(a.data(), y.data(), x); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_multiply(gmp_float<D1>& a, long x, const gmp_float<D2>& y) |
| { |
| if(x < 0) |
| { |
| mpf_mul_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x)); |
| mpf_neg(a.data(), a.data()); |
| } |
| else |
| mpf_mul_ui(a.data(), y.data(), x); |
| } |
| |
| template <unsigned D1, unsigned D2, unsigned D3> |
| inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, const gmp_float<D3>& y) |
| { |
| if(eval_is_zero(y)) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpf_div(a.data(), x.data(), y.data()); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, unsigned long y) |
| { |
| if(y == 0) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpf_div_ui(a.data(), x.data(), y); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_divide(gmp_float<D1>& a, const gmp_float<D2>& x, long y) |
| { |
| if(y == 0) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| if(y < 0) |
| { |
| mpf_div_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y)); |
| a.negate(); |
| } |
| else |
| mpf_div_ui(a.data(), x.data(), y); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_divide(gmp_float<D1>& a, unsigned long x, const gmp_float<D2>& y) |
| { |
| if(eval_is_zero(y)) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpf_ui_div(a.data(), x, y.data()); |
| } |
| template <unsigned D1, unsigned D2> |
| inline void eval_divide(gmp_float<D1>& a, long x, const gmp_float<D2>& y) |
| { |
| if(eval_is_zero(y)) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| if(x < 0) |
| { |
| mpf_ui_div(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data()); |
| mpf_neg(a.data(), a.data()); |
| } |
| else |
| mpf_ui_div(a.data(), x, y.data()); |
| } |
| |
| template <unsigned digits10> |
| inline int eval_get_sign(const gmp_float<digits10>& val) BOOST_NOEXCEPT |
| { |
| return mpf_sgn(val.data()); |
| } |
| |
| template <unsigned digits10> |
| inline void eval_convert_to(unsigned long* result, const gmp_float<digits10>& val) BOOST_NOEXCEPT |
| { |
| if(0 == mpf_fits_ulong_p(val.data())) |
| *result = (std::numeric_limits<unsigned long>::max)(); |
| else |
| *result = mpf_get_ui(val.data()); |
| } |
| template <unsigned digits10> |
| inline void eval_convert_to(long* result, const gmp_float<digits10>& val) BOOST_NOEXCEPT |
| { |
| if(0 == mpf_fits_slong_p(val.data())) |
| { |
| *result = (std::numeric_limits<unsigned long>::max)(); |
| *result *= mpf_sgn(val.data()); |
| } |
| else |
| *result = mpf_get_si(val.data()); |
| } |
| template <unsigned digits10> |
| inline void eval_convert_to(double* result, const gmp_float<digits10>& val) BOOST_NOEXCEPT |
| { |
| *result = mpf_get_d(val.data()); |
| } |
| #ifdef BOOST_HAS_LONG_LONG |
| template <unsigned digits10> |
| inline void eval_convert_to(long long* result, const gmp_float<digits10>& val) |
| { |
| gmp_float<digits10> t(val); |
| if(eval_get_sign(t) < 0) |
| t.negate(); |
| |
| long digits = std::numeric_limits<long long>::digits - std::numeric_limits<long>::digits; |
| |
| if(digits > 0) |
| mpf_div_2exp(t.data(), t.data(), digits); |
| |
| if(!mpf_fits_slong_p(t.data())) |
| { |
| if(eval_get_sign(val) < 0) |
| *result = (std::numeric_limits<long long>::min)(); |
| else |
| *result = (std::numeric_limits<long long>::max)(); |
| return; |
| }; |
| |
| *result = mpf_get_si(t.data()); |
| while(digits > 0) |
| { |
| *result <<= digits; |
| digits -= std::numeric_limits<unsigned long>::digits; |
| mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits<unsigned long>::digits : std::numeric_limits<unsigned long>::digits + digits); |
| unsigned long l = mpf_get_ui(t.data()); |
| if(digits < 0) |
| l >>= -digits; |
| *result |= l; |
| } |
| if(eval_get_sign(val) < 0) |
| *result = -*result; |
| } |
| template <unsigned digits10> |
| inline void eval_convert_to(unsigned long long* result, const gmp_float<digits10>& val) |
| { |
| gmp_float<digits10> t(val); |
| |
| long digits = std::numeric_limits<long long>::digits - std::numeric_limits<long>::digits; |
| |
| if(digits > 0) |
| mpf_div_2exp(t.data(), t.data(), digits); |
| |
| if(!mpf_fits_ulong_p(t.data())) |
| { |
| *result = (std::numeric_limits<long long>::max)(); |
| return; |
| } |
| |
| *result = mpf_get_ui(t.data()); |
| while(digits > 0) |
| { |
| *result <<= digits; |
| digits -= std::numeric_limits<unsigned long>::digits; |
| mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits<unsigned long>::digits : std::numeric_limits<unsigned long>::digits + digits); |
| unsigned long l = mpf_get_ui(t.data()); |
| if(digits < 0) |
| l >>= -digits; |
| *result |= l; |
| } |
| } |
| #endif |
| |
| // |
| // Native non-member operations: |
| // |
| template <unsigned Digits10> |
| inline void eval_sqrt(gmp_float<Digits10>& result, const gmp_float<Digits10>& val) |
| { |
| mpf_sqrt(result.data(), val.data()); |
| } |
| |
| template <unsigned Digits10> |
| inline void eval_abs(gmp_float<Digits10>& result, const gmp_float<Digits10>& val) |
| { |
| mpf_abs(result.data(), val.data()); |
| } |
| |
| template <unsigned Digits10> |
| inline void eval_fabs(gmp_float<Digits10>& result, const gmp_float<Digits10>& val) |
| { |
| mpf_abs(result.data(), val.data()); |
| } |
| template <unsigned Digits10> |
| inline void eval_ceil(gmp_float<Digits10>& result, const gmp_float<Digits10>& val) |
| { |
| mpf_ceil(result.data(), val.data()); |
| } |
| template <unsigned Digits10> |
| inline void eval_floor(gmp_float<Digits10>& result, const gmp_float<Digits10>& val) |
| { |
| mpf_floor(result.data(), val.data()); |
| } |
| template <unsigned Digits10> |
| inline void eval_trunc(gmp_float<Digits10>& result, const gmp_float<Digits10>& val) |
| { |
| mpf_trunc(result.data(), val.data()); |
| } |
| template <unsigned Digits10> |
| inline void eval_ldexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, long e) |
| { |
| if(e > 0) |
| mpf_mul_2exp(result.data(), val.data(), e); |
| else if(e < 0) |
| mpf_div_2exp(result.data(), val.data(), -e); |
| else |
| result = val; |
| } |
| template <unsigned Digits10> |
| inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, int* e) |
| { |
| long v; |
| mpf_get_d_2exp(&v, val.data()); |
| *e = v; |
| eval_ldexp(result, val, -v); |
| } |
| template <unsigned Digits10> |
| inline void eval_frexp(gmp_float<Digits10>& result, const gmp_float<Digits10>& val, long* e) |
| { |
| mpf_get_d_2exp(e, val.data()); |
| eval_ldexp(result, val, -*e); |
| } |
| |
| struct gmp_int |
| { |
| typedef mpl::list<long, long long> signed_types; |
| typedef mpl::list<unsigned long, unsigned long long> unsigned_types; |
| typedef mpl::list<double, long double> float_types; |
| |
| gmp_int() |
| { |
| mpz_init(this->m_data); |
| } |
| gmp_int(const gmp_int& o) |
| { |
| if(o.m_data[0]._mp_d) |
| mpz_init_set(m_data, o.m_data); |
| else |
| mpz_init(this->m_data); |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_int(gmp_int&& o) BOOST_NOEXCEPT |
| { |
| m_data[0] = o.m_data[0]; |
| o.m_data[0]._mp_d = 0; |
| } |
| #endif |
| explicit gmp_int(const mpf_t val) |
| { |
| mpz_init(this->m_data); |
| mpz_set_f(this->m_data, val); |
| } |
| gmp_int(const mpz_t val) |
| { |
| mpz_init_set(this->m_data, val); |
| } |
| explicit gmp_int(const mpq_t val) |
| { |
| mpz_init(this->m_data); |
| mpz_set_q(this->m_data, val); |
| } |
| template <unsigned Digits10> |
| explicit gmp_int(const gmp_float<Digits10>& o) |
| { |
| mpz_init(this->m_data); |
| mpz_set_f(this->m_data, o.data()); |
| } |
| explicit gmp_int(const gmp_rational& o); |
| gmp_int& operator = (const gmp_int& o) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| mpz_set(m_data, o.m_data); |
| return *this; |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_int& operator = (gmp_int&& o) BOOST_NOEXCEPT |
| { |
| mpz_swap(m_data, o.m_data); |
| return *this; |
| } |
| #endif |
| gmp_int& operator = (unsigned long long i) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| unsigned long long mask = ((1uLL << std::numeric_limits<unsigned>::digits) - 1); |
| unsigned shift = 0; |
| mpz_t t; |
| mpz_set_ui(m_data, 0); |
| mpz_init_set_ui(t, 0); |
| while(i) |
| { |
| mpz_set_ui(t, static_cast<unsigned>(i & mask)); |
| if(shift) |
| mpz_mul_2exp(t, t, shift); |
| mpz_add(m_data, m_data, t); |
| shift += std::numeric_limits<unsigned>::digits; |
| i >>= std::numeric_limits<unsigned>::digits; |
| } |
| mpz_clear(t); |
| return *this; |
| } |
| gmp_int& operator = (long long i) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| bool neg = i < 0; |
| *this = boost::multiprecision::detail::unsigned_abs(i); |
| if(neg) |
| mpz_neg(m_data, m_data); |
| return *this; |
| } |
| gmp_int& operator = (unsigned long i) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| mpz_set_ui(m_data, i); |
| return *this; |
| } |
| gmp_int& operator = (long i) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| mpz_set_si(m_data, i); |
| return *this; |
| } |
| gmp_int& operator = (double d) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| mpz_set_d(m_data, d); |
| return *this; |
| } |
| gmp_int& operator = (long double a) |
| { |
| using std::frexp; |
| using std::ldexp; |
| using std::floor; |
| |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| |
| if (a == 0) { |
| mpz_set_si(m_data, 0); |
| return *this; |
| } |
| |
| if (a == 1) { |
| mpz_set_si(m_data, 1); |
| return *this; |
| } |
| |
| BOOST_ASSERT(!(boost::math::isinf)(a)); |
| BOOST_ASSERT(!(boost::math::isnan)(a)); |
| |
| int e; |
| long double f, term; |
| mpz_set_ui(m_data, 0u); |
| |
| f = frexp(a, &e); |
| |
| static const int shift = std::numeric_limits<int>::digits - 1; |
| |
| while(f) |
| { |
| // extract int sized bits from f: |
| f = ldexp(f, shift); |
| term = floor(f); |
| e -= shift; |
| mpz_mul_2exp(m_data, m_data, shift); |
| if(term > 0) |
| mpz_add_ui(m_data, m_data, static_cast<unsigned>(term)); |
| else |
| mpz_sub_ui(m_data, m_data, static_cast<unsigned>(-term)); |
| f -= term; |
| } |
| if(e > 0) |
| mpz_mul_2exp(m_data, m_data, e); |
| else if(e < 0) |
| mpz_div_2exp(m_data, m_data, -e); |
| return *this; |
| } |
| gmp_int& operator = (const char* s) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| std::size_t n = s ? std::strlen(s) : 0; |
| int radix = 10; |
| if(n && (*s == '0')) |
| { |
| if((n > 1) && ((s[1] == 'x') || (s[1] == 'X'))) |
| { |
| radix = 16; |
| s +=2; |
| n -= 2; |
| } |
| else |
| { |
| radix = 8; |
| n -= 1; |
| } |
| } |
| if(n) |
| { |
| if(0 != mpz_set_str(m_data, s, radix)) |
| BOOST_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid integer."))); |
| } |
| else |
| mpz_set_ui(m_data, 0); |
| return *this; |
| } |
| gmp_int& operator=(const mpf_t val) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| mpz_set_f(this->m_data, val); |
| return *this; |
| } |
| gmp_int& operator=(const mpz_t val) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| mpz_set(this->m_data, val); |
| return *this; |
| } |
| gmp_int& operator=(const mpq_t val) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| mpz_set_q(this->m_data, val); |
| return *this; |
| } |
| template <unsigned Digits10> |
| gmp_int& operator=(const gmp_float<Digits10>& o) |
| { |
| if(m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| mpz_set_f(this->m_data, o.data()); |
| return *this; |
| } |
| gmp_int& operator=(const gmp_rational& o); |
| void swap(gmp_int& o) |
| { |
| mpz_swap(m_data, o.m_data); |
| } |
| std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags f)const |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| |
| int base = 10; |
| if((f & std::ios_base::oct) == std::ios_base::oct) |
| base = 8; |
| else if((f & std::ios_base::hex) == std::ios_base::hex) |
| base = 16; |
| // |
| // sanity check, bases 8 and 16 are only available for positive numbers: |
| // |
| if((base != 10) && (mpz_sgn(m_data) < 0)) |
| BOOST_THROW_EXCEPTION(std::runtime_error("Formatted output in bases 8 or 16 is only available for positive numbers")); |
| void *(*alloc_func_ptr) (size_t); |
| void *(*realloc_func_ptr) (void *, size_t, size_t); |
| void (*free_func_ptr) (void *, size_t); |
| const char* ps = mpz_get_str (0, base, m_data); |
| std::string s = ps; |
| mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr); |
| (*free_func_ptr)((void*)ps, std::strlen(ps) + 1); |
| |
| if((base != 10) && (f & std::ios_base::showbase)) |
| { |
| int pos = s[0] == '-' ? 1 : 0; |
| const char* pp = base == 8 ? "0" : "0x"; |
| s.insert(static_cast<std::string::size_type>(pos), pp); |
| } |
| if((f & std::ios_base::showpos) && (s[0] != '-')) |
| s.insert(static_cast<std::string::size_type>(0), 1, '+'); |
| |
| return s; |
| } |
| ~gmp_int() BOOST_NOEXCEPT |
| { |
| if(m_data[0]._mp_d) |
| mpz_clear(m_data); |
| } |
| void negate() BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| mpz_neg(m_data, m_data); |
| } |
| int compare(const gmp_int& o)const BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d && o.m_data[0]._mp_d); |
| return mpz_cmp(m_data, o.m_data); |
| } |
| int compare(long i)const BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| return mpz_cmp_si(m_data, i); |
| } |
| int compare(unsigned long i)const BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| return mpz_cmp_ui(m_data, i); |
| } |
| template <class V> |
| int compare(V v)const |
| { |
| gmp_int d; |
| d = v; |
| return compare(d); |
| } |
| mpz_t& data() BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| return m_data; |
| } |
| const mpz_t& data()const BOOST_NOEXCEPT |
| { |
| BOOST_ASSERT(m_data[0]._mp_d); |
| return m_data; |
| } |
| protected: |
| mpz_t m_data; |
| }; |
| |
| template <class T> |
| inline typename enable_if<is_arithmetic<T>, bool>::type eval_eq(const gmp_int& a, const T& b) |
| { |
| return a.compare(b) == 0; |
| } |
| template <class T> |
| inline typename enable_if<is_arithmetic<T>, bool>::type eval_lt(const gmp_int& a, const T& b) |
| { |
| return a.compare(b) < 0; |
| } |
| template <class T> |
| inline typename enable_if<is_arithmetic<T>, bool>::type eval_gt(const gmp_int& a, const T& b) |
| { |
| return a.compare(b) > 0; |
| } |
| |
| inline bool eval_is_zero(const gmp_int& val) |
| { |
| return mpz_sgn(val.data()) == 0; |
| } |
| inline void eval_add(gmp_int& t, const gmp_int& o) |
| { |
| mpz_add(t.data(), t.data(), o.data()); |
| } |
| inline void eval_multiply_add(gmp_int& t, const gmp_int& a, const gmp_int& b) |
| { |
| mpz_addmul(t.data(), a.data(), b.data()); |
| } |
| inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, const gmp_int& b) |
| { |
| mpz_submul(t.data(), a.data(), b.data()); |
| } |
| inline void eval_subtract(gmp_int& t, const gmp_int& o) |
| { |
| mpz_sub(t.data(), t.data(), o.data()); |
| } |
| inline void eval_multiply(gmp_int& t, const gmp_int& o) |
| { |
| mpz_mul(t.data(), t.data(), o.data()); |
| } |
| inline void eval_divide(gmp_int& t, const gmp_int& o) |
| { |
| if(eval_is_zero(o)) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpz_tdiv_q(t.data(), t.data(), o.data()); |
| } |
| inline void eval_modulus(gmp_int& t, const gmp_int& o) |
| { |
| mpz_tdiv_r(t.data(), t.data(), o.data()); |
| } |
| inline void eval_add(gmp_int& t, unsigned long i) |
| { |
| mpz_add_ui(t.data(), t.data(), i); |
| } |
| inline void eval_multiply_add(gmp_int& t, const gmp_int& a, unsigned long i) |
| { |
| mpz_addmul_ui(t.data(), a.data(), i); |
| } |
| inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, unsigned long i) |
| { |
| mpz_submul_ui(t.data(), a.data(), i); |
| } |
| inline void eval_subtract(gmp_int& t, unsigned long i) |
| { |
| mpz_sub_ui(t.data(), t.data(), i); |
| } |
| inline void eval_multiply(gmp_int& t, unsigned long i) |
| { |
| mpz_mul_ui(t.data(), t.data(), i); |
| } |
| inline void eval_modulus(gmp_int& t, unsigned long i) |
| { |
| mpz_tdiv_r_ui(t.data(), t.data(), i); |
| } |
| inline void eval_divide(gmp_int& t, unsigned long i) |
| { |
| if(i == 0) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpz_tdiv_q_ui(t.data(), t.data(), i); |
| } |
| inline void eval_add(gmp_int& t, long i) |
| { |
| if(i > 0) |
| mpz_add_ui(t.data(), t.data(), i); |
| else |
| mpz_sub_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i)); |
| } |
| inline void eval_multiply_add(gmp_int& t, const gmp_int& a, long i) |
| { |
| if(i > 0) |
| mpz_addmul_ui(t.data(), a.data(), i); |
| else |
| mpz_submul_ui(t.data(), a.data(), boost::multiprecision::detail::unsigned_abs(i)); |
| } |
| inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, long i) |
| { |
| if(i > 0) |
| mpz_submul_ui(t.data(), a.data(), i); |
| else |
| mpz_addmul_ui(t.data(), a.data(), boost::multiprecision::detail::unsigned_abs(i)); |
| } |
| inline void eval_subtract(gmp_int& t, long i) |
| { |
| if(i > 0) |
| mpz_sub_ui(t.data(), t.data(), i); |
| else |
| mpz_add_ui(t.data(), t.data(), boost::multiprecision::detail::unsigned_abs(i)); |
| } |
| inline void eval_multiply(gmp_int& t, long i) |
| { |
| mpz_mul_ui(t.data(), t.data(), std::abs(i)); |
| if(i < 0) |
| mpz_neg(t.data(), t.data()); |
| } |
| inline void eval_modulus(gmp_int& t, long i) |
| { |
| mpz_tdiv_r_ui(t.data(), t.data(), std::abs(i)); |
| } |
| inline void eval_divide(gmp_int& t, long i) |
| { |
| if(i == 0) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpz_tdiv_q_ui(t.data(), t.data(), std::abs(i)); |
| if(i < 0) |
| mpz_neg(t.data(), t.data()); |
| } |
| template <class UI> |
| inline void eval_left_shift(gmp_int& t, UI i) |
| { |
| mpz_mul_2exp(t.data(), t.data(), static_cast<unsigned long>(i)); |
| } |
| template <class UI> |
| inline void eval_right_shift(gmp_int& t, UI i) |
| { |
| mpz_fdiv_q_2exp(t.data(), t.data(), static_cast<unsigned long>(i)); |
| } |
| template <class UI> |
| inline void eval_left_shift(gmp_int& t, const gmp_int& v, UI i) |
| { |
| mpz_mul_2exp(t.data(), v.data(), static_cast<unsigned long>(i)); |
| } |
| template <class UI> |
| inline void eval_right_shift(gmp_int& t, const gmp_int& v, UI i) |
| { |
| mpz_fdiv_q_2exp(t.data(), v.data(), static_cast<unsigned long>(i)); |
| } |
| |
| inline void eval_bitwise_and(gmp_int& result, const gmp_int& v) |
| { |
| mpz_and(result.data(), result.data(), v.data()); |
| } |
| |
| inline void eval_bitwise_or(gmp_int& result, const gmp_int& v) |
| { |
| mpz_ior(result.data(), result.data(), v.data()); |
| } |
| |
| inline void eval_bitwise_xor(gmp_int& result, const gmp_int& v) |
| { |
| mpz_xor(result.data(), result.data(), v.data()); |
| } |
| |
| inline void eval_add(gmp_int& t, const gmp_int& p, const gmp_int& o) |
| { |
| mpz_add(t.data(), p.data(), o.data()); |
| } |
| inline void eval_subtract(gmp_int& t, const gmp_int& p, const gmp_int& o) |
| { |
| mpz_sub(t.data(), p.data(), o.data()); |
| } |
| inline void eval_multiply(gmp_int& t, const gmp_int& p, const gmp_int& o) |
| { |
| mpz_mul(t.data(), p.data(), o.data()); |
| } |
| inline void eval_divide(gmp_int& t, const gmp_int& p, const gmp_int& o) |
| { |
| if(eval_is_zero(o)) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpz_tdiv_q(t.data(), p.data(), o.data()); |
| } |
| inline void eval_modulus(gmp_int& t, const gmp_int& p, const gmp_int& o) |
| { |
| mpz_tdiv_r(t.data(), p.data(), o.data()); |
| } |
| inline void eval_add(gmp_int& t, const gmp_int& p, unsigned long i) |
| { |
| mpz_add_ui(t.data(), p.data(), i); |
| } |
| inline void eval_subtract(gmp_int& t, const gmp_int& p, unsigned long i) |
| { |
| mpz_sub_ui(t.data(), p.data(), i); |
| } |
| inline void eval_multiply(gmp_int& t, const gmp_int& p, unsigned long i) |
| { |
| mpz_mul_ui(t.data(), p.data(), i); |
| } |
| inline void eval_modulus(gmp_int& t, const gmp_int& p, unsigned long i) |
| { |
| mpz_tdiv_r_ui(t.data(), p.data(), i); |
| } |
| inline void eval_divide(gmp_int& t, const gmp_int& p, unsigned long i) |
| { |
| if(i == 0) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpz_tdiv_q_ui(t.data(), p.data(), i); |
| } |
| inline void eval_add(gmp_int& t, const gmp_int& p, long i) |
| { |
| if(i > 0) |
| mpz_add_ui(t.data(), p.data(), i); |
| else |
| mpz_sub_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i)); |
| } |
| inline void eval_subtract(gmp_int& t, const gmp_int& p, long i) |
| { |
| if(i > 0) |
| mpz_sub_ui(t.data(), p.data(), i); |
| else |
| mpz_add_ui(t.data(), p.data(), boost::multiprecision::detail::unsigned_abs(i)); |
| } |
| inline void eval_multiply(gmp_int& t, const gmp_int& p, long i) |
| { |
| mpz_mul_ui(t.data(), p.data(), std::abs(i)); |
| if(i < 0) |
| mpz_neg(t.data(), t.data()); |
| } |
| inline void eval_modulus(gmp_int& t, const gmp_int& p, long i) |
| { |
| mpz_tdiv_r_ui(t.data(), p.data(), std::abs(i)); |
| } |
| inline void eval_divide(gmp_int& t, const gmp_int& p, long i) |
| { |
| if(i == 0) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpz_tdiv_q_ui(t.data(), p.data(), std::abs(i)); |
| if(i < 0) |
| mpz_neg(t.data(), t.data()); |
| } |
| |
| inline void eval_bitwise_and(gmp_int& result, const gmp_int& u, const gmp_int& v) |
| { |
| mpz_and(result.data(), u.data(), v.data()); |
| } |
| |
| inline void eval_bitwise_or(gmp_int& result, const gmp_int& u, const gmp_int& v) |
| { |
| mpz_ior(result.data(), u.data(), v.data()); |
| } |
| |
| inline void eval_bitwise_xor(gmp_int& result, const gmp_int& u, const gmp_int& v) |
| { |
| mpz_xor(result.data(), u.data(), v.data()); |
| } |
| |
| inline void eval_complement(gmp_int& result, const gmp_int& u) |
| { |
| mpz_com(result.data(), u.data()); |
| } |
| |
| inline int eval_get_sign(const gmp_int& val) |
| { |
| return mpz_sgn(val.data()); |
| } |
| inline void eval_convert_to(unsigned long* result, const gmp_int& val) |
| { |
| if(0 == mpz_fits_ulong_p(val.data())) |
| { |
| *result = (std::numeric_limits<unsigned long>::max)(); |
| } |
| else |
| *result = mpz_get_ui(val.data()); |
| } |
| inline void eval_convert_to(long* result, const gmp_int& val) |
| { |
| if(0 == mpz_fits_slong_p(val.data())) |
| { |
| *result = (std::numeric_limits<unsigned long>::max)(); |
| *result *= mpz_sgn(val.data()); |
| } |
| else |
| *result = mpz_get_si(val.data()); |
| } |
| inline void eval_convert_to(double* result, const gmp_int& val) |
| { |
| *result = mpz_get_d(val.data()); |
| } |
| |
| inline void eval_abs(gmp_int& result, const gmp_int& val) |
| { |
| mpz_abs(result.data(), val.data()); |
| } |
| |
| inline void eval_gcd(gmp_int& result, const gmp_int& a, const gmp_int& b) |
| { |
| mpz_gcd(result.data(), a.data(), b.data()); |
| } |
| inline void eval_lcm(gmp_int& result, const gmp_int& a, const gmp_int& b) |
| { |
| mpz_lcm(result.data(), a.data(), b.data()); |
| } |
| template <class I> |
| inline typename enable_if_c<(is_unsigned<I>::value && (sizeof(I) <= sizeof(unsigned long)))>::type eval_gcd(gmp_int& result, const gmp_int& a, const I b) |
| { |
| mpz_gcd_ui(result.data(), a.data(), b); |
| } |
| template <class I> |
| inline typename enable_if_c<(is_unsigned<I>::value && (sizeof(I) <= sizeof(unsigned long)))>::type eval_lcm(gmp_int& result, const gmp_int& a, const I b) |
| { |
| mpz_lcm_ui(result.data(), a.data(), b); |
| } |
| template <class I> |
| inline typename enable_if_c<(is_signed<I>::value && (sizeof(I) <= sizeof(long)))>::type eval_gcd(gmp_int& result, const gmp_int& a, const I b) |
| { |
| mpz_gcd_ui(result.data(), a.data(), std::abs(b)); |
| } |
| template <class I> |
| inline typename enable_if_c<is_signed<I>::value && ((sizeof(I) <= sizeof(long)))>::type eval_lcm(gmp_int& result, const gmp_int& a, const I b) |
| { |
| mpz_lcm_ui(result.data(), a.data(), std::abs(b)); |
| } |
| |
| inline void eval_integer_sqrt(gmp_int& s, gmp_int& r, const gmp_int& x) |
| { |
| mpz_sqrtrem(s.data(), r.data(), x.data()); |
| } |
| |
| inline unsigned eval_lsb(const gmp_int& val) |
| { |
| int c = eval_get_sign(val); |
| if(c == 0) |
| { |
| BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); |
| } |
| if(c < 0) |
| { |
| BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); |
| } |
| return mpz_scan1(val.data(), 0); |
| } |
| |
| inline unsigned eval_msb(const gmp_int& val) |
| { |
| int c = eval_get_sign(val); |
| if(c == 0) |
| { |
| BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); |
| } |
| if(c < 0) |
| { |
| BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); |
| } |
| return mpz_sizeinbase(val.data(), 2) - 1; |
| } |
| |
| inline bool eval_bit_test(const gmp_int& val, unsigned index) |
| { |
| return mpz_tstbit(val.data(), index) ? true : false; |
| } |
| |
| inline void eval_bit_set(gmp_int& val, unsigned index) |
| { |
| mpz_setbit(val.data(), index); |
| } |
| |
| inline void eval_bit_unset(gmp_int& val, unsigned index) |
| { |
| mpz_clrbit(val.data(), index); |
| } |
| |
| inline void eval_bit_flip(gmp_int& val, unsigned index) |
| { |
| mpz_combit(val.data(), index); |
| } |
| |
| inline void eval_qr(const gmp_int& x, const gmp_int& y, |
| gmp_int& q, gmp_int& r) |
| { |
| mpz_tdiv_qr(q.data(), r.data(), x.data(), y.data()); |
| } |
| |
| template <class Integer> |
| inline typename enable_if<is_unsigned<Integer>, Integer>::type eval_integer_modulus(const gmp_int& x, Integer val) |
| { |
| if((sizeof(Integer) <= sizeof(long)) || (val <= (std::numeric_limits<unsigned long>::max)())) |
| { |
| return mpz_tdiv_ui(x.data(), val); |
| } |
| else |
| { |
| return default_ops::eval_integer_modulus(x, val); |
| } |
| } |
| template <class Integer> |
| inline typename enable_if<is_signed<Integer>, Integer>::type eval_integer_modulus(const gmp_int& x, Integer val) |
| { |
| typedef typename make_unsigned<Integer>::type unsigned_type; |
| return eval_integer_modulus(x, static_cast<unsigned_type>(std::abs(val))); |
| } |
| inline void eval_powm(gmp_int& result, const gmp_int& base, const gmp_int& p, const gmp_int& m) |
| { |
| if(eval_get_sign(p) < 0) |
| { |
| BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent.")); |
| } |
| mpz_powm(result.data(), base.data(), p.data(), m.data()); |
| } |
| |
| template <class Integer> |
| inline typename enable_if< |
| mpl::and_< |
| is_unsigned<Integer>, |
| mpl::bool_<sizeof(Integer) <= sizeof(unsigned long)> |
| > |
| >::type eval_powm(gmp_int& result, const gmp_int& base, Integer p, const gmp_int& m) |
| { |
| mpz_powm_ui(result.data(), base.data(), p, m.data()); |
| } |
| template <class Integer> |
| inline typename enable_if< |
| mpl::and_< |
| is_signed<Integer>, |
| mpl::bool_<sizeof(Integer) <= sizeof(unsigned long)> |
| > |
| >::type eval_powm(gmp_int& result, const gmp_int& base, Integer p, const gmp_int& m) |
| { |
| if(p < 0) |
| { |
| BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent.")); |
| } |
| mpz_powm_ui(result.data(), base.data(), p, m.data()); |
| } |
| |
| struct gmp_rational; |
| void eval_add(gmp_rational& t, const gmp_rational& o); |
| |
| struct gmp_rational |
| { |
| typedef mpl::list<long, long long> signed_types; |
| typedef mpl::list<unsigned long, unsigned long long> unsigned_types; |
| typedef mpl::list<double, long double> float_types; |
| |
| gmp_rational() |
| { |
| mpq_init(this->m_data); |
| } |
| gmp_rational(const gmp_rational& o) |
| { |
| mpq_init(m_data); |
| if(o.m_data[0]._mp_num._mp_d) |
| mpq_set(m_data, o.m_data); |
| } |
| gmp_rational(const gmp_int& o) |
| { |
| mpq_init(m_data); |
| mpq_set_z(m_data, o.data()); |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_rational(gmp_rational&& o) BOOST_NOEXCEPT |
| { |
| m_data[0] = o.m_data[0]; |
| o.m_data[0]._mp_num._mp_d = 0; |
| o.m_data[0]._mp_den._mp_d = 0; |
| } |
| #endif |
| gmp_rational(const mpq_t o) |
| { |
| mpq_init(m_data); |
| mpq_set(m_data, o); |
| } |
| gmp_rational(const mpz_t o) |
| { |
| mpq_init(m_data); |
| mpq_set_z(m_data, o); |
| } |
| gmp_rational& operator = (const gmp_rational& o) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| mpq_set(m_data, o.m_data); |
| return *this; |
| } |
| #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| gmp_rational& operator = (gmp_rational&& o) BOOST_NOEXCEPT |
| { |
| mpq_swap(m_data, o.m_data); |
| return *this; |
| } |
| #endif |
| gmp_rational& operator = (unsigned long long i) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| unsigned long long mask = ((1uLL << std::numeric_limits<unsigned>::digits) - 1); |
| unsigned shift = 0; |
| mpq_t t; |
| mpq_set_ui(m_data, 0, 1); |
| mpq_init(t); |
| while(i) |
| { |
| mpq_set_ui(t, static_cast<unsigned>(i & mask), 1); |
| if(shift) |
| mpq_mul_2exp(t, t, shift); |
| mpq_add(m_data, m_data, t); |
| shift += std::numeric_limits<unsigned>::digits; |
| i >>= std::numeric_limits<unsigned>::digits; |
| } |
| mpq_clear(t); |
| return *this; |
| } |
| gmp_rational& operator = (long long i) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| bool neg = i < 0; |
| *this = boost::multiprecision::detail::unsigned_abs(i); |
| if(neg) |
| mpq_neg(m_data, m_data); |
| return *this; |
| } |
| gmp_rational& operator = (unsigned long i) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| mpq_set_ui(m_data, i, 1); |
| return *this; |
| } |
| gmp_rational& operator = (long i) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| mpq_set_si(m_data, i, 1); |
| return *this; |
| } |
| gmp_rational& operator = (double d) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| mpq_set_d(m_data, d); |
| return *this; |
| } |
| gmp_rational& operator = (long double a) |
| { |
| using std::frexp; |
| using std::ldexp; |
| using std::floor; |
| using default_ops::eval_add; |
| using default_ops::eval_subtract; |
| |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| |
| if (a == 0) { |
| mpq_set_si(m_data, 0, 1); |
| return *this; |
| } |
| |
| if (a == 1) { |
| mpq_set_si(m_data, 1, 1); |
| return *this; |
| } |
| |
| BOOST_ASSERT(!(boost::math::isinf)(a)); |
| BOOST_ASSERT(!(boost::math::isnan)(a)); |
| |
| int e; |
| long double f, term; |
| mpq_set_ui(m_data, 0, 1); |
| mpq_set_ui(m_data, 0u, 1); |
| gmp_rational t; |
| |
| f = frexp(a, &e); |
| |
| static const int shift = std::numeric_limits<int>::digits - 1; |
| |
| while(f) |
| { |
| // extract int sized bits from f: |
| f = ldexp(f, shift); |
| term = floor(f); |
| e -= shift; |
| mpq_mul_2exp(m_data, m_data, shift); |
| t = static_cast<long>(term); |
| eval_add(*this, t); |
| f -= term; |
| } |
| if(e > 0) |
| mpq_mul_2exp(m_data, m_data, e); |
| else if(e < 0) |
| mpq_div_2exp(m_data, m_data, -e); |
| return *this; |
| } |
| gmp_rational& operator = (const char* s) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| if(0 != mpq_set_str(m_data, s, 10)) |
| BOOST_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid rational number."))); |
| return *this; |
| } |
| gmp_rational& operator=(const gmp_int& o) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| mpq_set_z(m_data, o.data()); |
| return *this; |
| } |
| gmp_rational& operator=(const mpq_t o) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| mpq_set(m_data, o); |
| return *this; |
| } |
| gmp_rational& operator=(const mpz_t o) |
| { |
| if(m_data[0]._mp_den._mp_d == 0) |
| mpq_init(m_data); |
| mpq_set_z(m_data, o); |
| return *this; |
| } |
| void swap(gmp_rational& o) |
| { |
| mpq_swap(m_data, o.m_data); |
| } |
| std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags /*f*/)const |
| { |
| BOOST_ASSERT(m_data[0]._mp_num._mp_d); |
| // TODO make a better job of this including handling of f!! |
| void *(*alloc_func_ptr) (size_t); |
| void *(*realloc_func_ptr) (void *, size_t, size_t); |
| void (*free_func_ptr) (void *, size_t); |
| const char* ps = mpq_get_str (0, 10, m_data); |
| std::string s = ps; |
| mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr); |
| (*free_func_ptr)((void*)ps, std::strlen(ps) + 1); |
| return s; |
| } |
| ~gmp_rational() |
| { |
| if(m_data[0]._mp_num._mp_d || m_data[0]._mp_den._mp_d) |
| mpq_clear(m_data); |
| } |
| void negate() |
| { |
| BOOST_ASSERT(m_data[0]._mp_num._mp_d); |
| mpq_neg(m_data, m_data); |
| } |
| int compare(const gmp_rational& o)const |
| { |
| BOOST_ASSERT(m_data[0]._mp_num._mp_d && o.m_data[0]._mp_num._mp_d); |
| return mpq_cmp(m_data, o.m_data); |
| } |
| template <class V> |
| int compare(V v)const |
| { |
| gmp_rational d; |
| d = v; |
| return compare(d); |
| } |
| int compare(unsigned long v)const |
| { |
| BOOST_ASSERT(m_data[0]._mp_num._mp_d); |
| return mpq_cmp_ui(m_data, v, 1); |
| } |
| int compare(long v)const |
| { |
| BOOST_ASSERT(m_data[0]._mp_num._mp_d); |
| return mpq_cmp_si(m_data, v, 1); |
| } |
| mpq_t& data() |
| { |
| BOOST_ASSERT(m_data[0]._mp_num._mp_d); |
| return m_data; |
| } |
| const mpq_t& data()const |
| { |
| BOOST_ASSERT(m_data[0]._mp_num._mp_d); |
| return m_data; |
| } |
| protected: |
| mpq_t m_data; |
| }; |
| |
| inline bool eval_is_zero(const gmp_rational& val) |
| { |
| return mpq_sgn(val.data()) == 0; |
| } |
| template <class T> |
| inline bool eval_eq(gmp_rational& a, const T& b) |
| { |
| return a.compare(b) == 0; |
| } |
| template <class T> |
| inline bool eval_lt(gmp_rational& a, const T& b) |
| { |
| return a.compare(b) < 0; |
| } |
| template <class T> |
| inline bool eval_gt(gmp_rational& a, const T& b) |
| { |
| return a.compare(b) > 0; |
| } |
| |
| inline void eval_add(gmp_rational& t, const gmp_rational& o) |
| { |
| mpq_add(t.data(), t.data(), o.data()); |
| } |
| inline void eval_subtract(gmp_rational& t, const gmp_rational& o) |
| { |
| mpq_sub(t.data(), t.data(), o.data()); |
| } |
| inline void eval_multiply(gmp_rational& t, const gmp_rational& o) |
| { |
| mpq_mul(t.data(), t.data(), o.data()); |
| } |
| inline void eval_divide(gmp_rational& t, const gmp_rational& o) |
| { |
| if(eval_is_zero(o)) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpq_div(t.data(), t.data(), o.data()); |
| } |
| inline void eval_add(gmp_rational& t, const gmp_rational& p, const gmp_rational& o) |
| { |
| mpq_add(t.data(), p.data(), o.data()); |
| } |
| inline void eval_subtract(gmp_rational& t, const gmp_rational& p, const gmp_rational& o) |
| { |
| mpq_sub(t.data(), p.data(), o.data()); |
| } |
| inline void eval_multiply(gmp_rational& t, const gmp_rational& p, const gmp_rational& o) |
| { |
| mpq_mul(t.data(), p.data(), o.data()); |
| } |
| inline void eval_divide(gmp_rational& t, const gmp_rational& p, const gmp_rational& o) |
| { |
| if(eval_is_zero(o)) |
| BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); |
| mpq_div(t.data(), p.data(), o.data()); |
| } |
| |
| inline int eval_get_sign(const gmp_rational& val) |
| { |
| return mpq_sgn(val.data()); |
| } |
| inline void eval_convert_to(double* result, const gmp_rational& val) |
| { |
| // |
| // This does not round correctly: |
| // |
| //*result = mpq_get_d(val.data()); |
| // |
| // This does: |
| // |
| boost::multiprecision::detail::generic_convert_rational_to_float(*result, val); |
| } |
| |
| inline void eval_convert_to(long* result, const gmp_rational& val) |
| { |
| double r; |
| eval_convert_to(&r, val); |
| *result = static_cast<long>(r); |
| } |
| |
| inline void eval_convert_to(unsigned long* result, const gmp_rational& val) |
| { |
| double r; |
| eval_convert_to(&r, val); |
| *result = static_cast<long>(r); |
| } |
| |
| inline void eval_abs(gmp_rational& result, const gmp_rational& val) |
| { |
| mpq_abs(result.data(), val.data()); |
| } |
| |
| inline void assign_components(gmp_rational& result, unsigned long v1, unsigned long v2) |
| { |
| mpq_set_ui(result.data(), v1, v2); |
| mpq_canonicalize(result.data()); |
| } |
| inline void assign_components(gmp_rational& result, long v1, long v2) |
| { |
| mpq_set_si(result.data(), v1, v2); |
| mpq_canonicalize(result.data()); |
| } |
| inline void assign_components(gmp_rational& result, gmp_int const& v1, gmp_int const& v2) |
| { |
| mpz_set(mpq_numref(result.data()), v1.data()); |
| mpz_set(mpq_denref(result.data()), v2.data()); |
| mpq_canonicalize(result.data()); |
| } |
| |
| // |
| // Some member functions that are dependent upon previous code go here: |
| // |
| template <unsigned Digits10> |
| template <unsigned D> |
| inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename enable_if_c<D <= Digits10>::type*) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision())); |
| mpf_set(this->m_data, o.data()); |
| } |
| template <unsigned Digits10> |
| template <unsigned D> |
| inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename disable_if_c<D <= Digits10>::type*) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision())); |
| mpf_set(this->m_data, o.data()); |
| } |
| template <unsigned Digits10> |
| inline gmp_float<Digits10>::gmp_float(const gmp_int& o) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision())); |
| mpf_set_z(this->data(), o.data()); |
| } |
| template <unsigned Digits10> |
| inline gmp_float<Digits10>::gmp_float(const gmp_rational& o) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision())); |
| mpf_set_q(this->data(), o.data()); |
| } |
| template <unsigned Digits10> |
| template <unsigned D> |
| inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_float<D>& o) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision())); |
| mpf_set(this->m_data, o.data()); |
| return *this; |
| } |
| template <unsigned Digits10> |
| inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_int& o) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision())); |
| mpf_set_z(this->data(), o.data()); |
| return *this; |
| } |
| template <unsigned Digits10> |
| inline gmp_float<Digits10>& gmp_float<Digits10>::operator=(const gmp_rational& o) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(Digits10 ? Digits10 : this->get_default_precision())); |
| mpf_set_q(this->data(), o.data()); |
| return *this; |
| } |
| inline gmp_float<0>::gmp_float(const gmp_int& o) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); |
| mpf_set_z(this->data(), o.data()); |
| } |
| inline gmp_float<0>::gmp_float(const gmp_rational& o) |
| { |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); |
| mpf_set_q(this->data(), o.data()); |
| } |
| inline gmp_float<0>& gmp_float<0>::operator=(const gmp_int& o) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(this->get_default_precision())); |
| mpf_set_z(this->data(), o.data()); |
| return *this; |
| } |
| inline gmp_float<0>& gmp_float<0>::operator=(const gmp_rational& o) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(this->get_default_precision())); |
| mpf_set_q(this->data(), o.data()); |
| return *this; |
| } |
| inline gmp_int::gmp_int(const gmp_rational& o) |
| { |
| mpz_init(this->m_data); |
| mpz_set_q(this->m_data, o.data()); |
| } |
| inline gmp_int& gmp_int::operator=(const gmp_rational& o) |
| { |
| if(this->m_data[0]._mp_d == 0) |
| mpz_init(this->m_data); |
| mpz_set_q(this->m_data, o.data()); |
| return *this; |
| } |
| |
| } //namespace backends |
| |
| using boost::multiprecision::backends::gmp_int; |
| using boost::multiprecision::backends::gmp_rational; |
| using boost::multiprecision::backends::gmp_float; |
| |
| template <> |
| struct component_type<number<gmp_rational> > |
| { |
| typedef number<gmp_int> type; |
| }; |
| |
| template <expression_template_option ET> |
| inline number<gmp_int, ET> numerator(const number<gmp_rational, ET>& val) |
| { |
| number<gmp_int, ET> result; |
| mpz_set(result.backend().data(), (mpq_numref(val.backend().data()))); |
| return result; |
| } |
| template <expression_template_option ET> |
| inline number<gmp_int, ET> denominator(const number<gmp_rational, ET>& val) |
| { |
| number<gmp_int, ET> result; |
| mpz_set(result.backend().data(), (mpq_denref(val.backend().data()))); |
| return result; |
| } |
| |
| #ifdef BOOST_NO_SFINAE_EXPR |
| |
| namespace detail{ |
| |
| template<> |
| struct is_explicitly_convertible<canonical<mpf_t, gmp_int>::type, gmp_int> : public mpl::true_ {}; |
| template<> |
| struct is_explicitly_convertible<canonical<mpq_t, gmp_int>::type, gmp_int> : public mpl::true_ {}; |
| template<unsigned Digits10> |
| struct is_explicitly_convertible<gmp_float<Digits10>, gmp_int> : public mpl::true_ {}; |
| template<> |
| struct is_explicitly_convertible<gmp_rational, gmp_int> : public mpl::true_ {}; |
| template<unsigned D1, unsigned D2> |
| struct is_explicitly_convertible<gmp_float<D1>, gmp_float<D2> > : public mpl::true_ {}; |
| |
| } |
| |
| #endif |
| |
| template<> |
| struct number_category<detail::canonical<mpz_t, gmp_int>::type> : public mpl::int_<number_kind_integer>{}; |
| template<> |
| struct number_category<detail::canonical<mpq_t, gmp_rational>::type> : public mpl::int_<number_kind_rational>{}; |
| template<> |
| struct number_category<detail::canonical<mpf_t, gmp_float<0> >::type> : public mpl::int_<number_kind_floating_point>{}; |
| |
| |
| typedef number<gmp_float<50> > mpf_float_50; |
| typedef number<gmp_float<100> > mpf_float_100; |
| typedef number<gmp_float<500> > mpf_float_500; |
| typedef number<gmp_float<1000> > mpf_float_1000; |
| typedef number<gmp_float<0> > mpf_float; |
| typedef number<gmp_int > mpz_int; |
| typedef number<gmp_rational > mpq_rational; |
| |
| }} // namespaces |
| |
| namespace std{ |
| |
| // |
| // numeric_limits [partial] specializations for the types declared in this header: |
| // |
| template<unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> > |
| { |
| typedef boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> number_type; |
| public: |
| BOOST_STATIC_CONSTEXPR bool is_specialized = true; |
| // |
| // min and max values chosen so as to not cause segfaults when calling |
| // mpf_get_str on 64-bit Linux builds. Possibly we could use larger |
| // exponent values elsewhere. |
| // |
| static number_type (min)() |
| { |
| initializer.do_nothing(); |
| static std::pair<bool, number_type> value; |
| if(!value.first) |
| { |
| value.first = true; |
| value.second = 1; |
| mpf_div_2exp(value.second.backend().data(), value.second.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1); |
| } |
| return value.second; |
| } |
| static number_type (max)() |
| { |
| initializer.do_nothing(); |
| static std::pair<bool, number_type> value; |
| if(!value.first) |
| { |
| value.first = true; |
| value.second = 1; |
| mpf_mul_2exp(value.second.backend().data(), value.second.backend().data(), (std::numeric_limits<mp_exp_t>::max)() / 64 + 1); |
| } |
| return value.second; |
| } |
| BOOST_STATIC_CONSTEXPR number_type lowest() |
| { |
| return -(max)(); |
| } |
| BOOST_STATIC_CONSTEXPR int digits = static_cast<int>((Digits10 * 1000L) / 301L + ((Digits10 * 1000L) % 301L ? 2 : 1)); |
| BOOST_STATIC_CONSTEXPR int digits10 = Digits10; |
| // Have to allow for a possible extra limb inside the gmp data structure: |
| BOOST_STATIC_CONSTEXPR int max_digits10 = Digits10 + 2 + ((GMP_LIMB_BITS * 301L) / 1000L); |
| BOOST_STATIC_CONSTEXPR bool is_signed = true; |
| BOOST_STATIC_CONSTEXPR bool is_integer = false; |
| BOOST_STATIC_CONSTEXPR bool is_exact = false; |
| BOOST_STATIC_CONSTEXPR int radix = 2; |
| static number_type epsilon() |
| { |
| initializer.do_nothing(); |
| static std::pair<bool, number_type> value; |
| if(!value.first) |
| { |
| value.first = true; |
| value.second = 1; |
| mpf_div_2exp(value.second.backend().data(), value.second.backend().data(), std::numeric_limits<number_type>::digits - 1); |
| } |
| return value.second; |
| } |
| // What value should this be???? |
| static number_type round_error() |
| { |
| // returns epsilon/2 |
| initializer.do_nothing(); |
| static std::pair<bool, number_type> value; |
| if(!value.first) |
| { |
| value.first = true; |
| value.second = 1; |
| } |
| return value.second; |
| } |
| BOOST_STATIC_CONSTEXPR long min_exponent = LONG_MIN; |
| BOOST_STATIC_CONSTEXPR long min_exponent10 = (LONG_MIN / 1000) * 301L; |
| BOOST_STATIC_CONSTEXPR long max_exponent = LONG_MAX; |
| BOOST_STATIC_CONSTEXPR long max_exponent10 = (LONG_MAX / 1000) * 301L; |
| BOOST_STATIC_CONSTEXPR bool has_infinity = false; |
| BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = false; |
| BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false; |
| BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent; |
| BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false; |
| BOOST_STATIC_CONSTEXPR number_type infinity() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR number_type quiet_NaN() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR number_type signaling_NaN() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR number_type denorm_min() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR bool is_iec559 = false; |
| BOOST_STATIC_CONSTEXPR bool is_bounded = true; |
| BOOST_STATIC_CONSTEXPR bool is_modulo = false; |
| BOOST_STATIC_CONSTEXPR bool traps = true; |
| BOOST_STATIC_CONSTEXPR bool tinyness_before = false; |
| BOOST_STATIC_CONSTEXPR float_round_style round_style = round_indeterminate; |
| |
| private: |
| struct data_initializer |
| { |
| data_initializer() |
| { |
| std::numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<digits10> > >::epsilon(); |
| std::numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<digits10> > >::round_error(); |
| (std::numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<digits10> > >::min)(); |
| (std::numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<digits10> > >::max)(); |
| } |
| void do_nothing()const{} |
| }; |
| static const data_initializer initializer; |
| }; |
| |
| template<unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| const typename numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::data_initializer numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::initializer; |
| |
| #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION |
| |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::digits; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::digits10; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_digits10; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_signed; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_integer; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_exact; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::radix; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::min_exponent; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::min_exponent10; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_exponent; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST long numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::max_exponent10; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_infinity; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_quiet_NaN; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_signaling_NaN; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_denorm; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::has_denorm_loss; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_iec559; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_bounded; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::is_modulo; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::traps; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::tinyness_before; |
| template <unsigned Digits10, boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<Digits10>, ExpressionTemplates> >::round_style; |
| |
| #endif |
| |
| template<boost::multiprecision::expression_template_option ExpressionTemplates> |
| class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> > |
| { |
| typedef boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> number_type; |
| public: |
| BOOST_STATIC_CONSTEXPR bool is_specialized = false; |
| static number_type (min)() { return number_type(); } |
| static number_type (max)() { return number_type(); } |
| static number_type lowest() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR int digits = 0; |
| BOOST_STATIC_CONSTEXPR int digits10 = 0; |
| BOOST_STATIC_CONSTEXPR int max_digits10 = 0; |
| BOOST_STATIC_CONSTEXPR bool is_signed = false; |
| BOOST_STATIC_CONSTEXPR bool is_integer = false; |
| BOOST_STATIC_CONSTEXPR bool is_exact = false; |
| BOOST_STATIC_CONSTEXPR int radix = 0; |
| static number_type epsilon() { return number_type(); } |
| static number_type round_error() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR int min_exponent = 0; |
| BOOST_STATIC_CONSTEXPR int min_exponent10 = 0; |
| BOOST_STATIC_CONSTEXPR int max_exponent = 0; |
| BOOST_STATIC_CONSTEXPR int max_exponent10 = 0; |
| BOOST_STATIC_CONSTEXPR bool has_infinity = false; |
| BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = false; |
| BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false; |
| BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent; |
| BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false; |
| static number_type infinity() { return number_type(); } |
| static number_type quiet_NaN() { return number_type(); } |
| static number_type signaling_NaN() { return number_type(); } |
| static number_type denorm_min() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR bool is_iec559 = false; |
| BOOST_STATIC_CONSTEXPR bool is_bounded = false; |
| BOOST_STATIC_CONSTEXPR bool is_modulo = false; |
| BOOST_STATIC_CONSTEXPR bool traps = false; |
| BOOST_STATIC_CONSTEXPR bool tinyness_before = false; |
| BOOST_STATIC_CONSTEXPR float_round_style round_style = round_indeterminate; |
| }; |
| |
| #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION |
| |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::digits; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::digits10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_digits10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_signed; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_integer; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_exact; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::radix; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::min_exponent; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::min_exponent10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_exponent; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::max_exponent10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_infinity; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_quiet_NaN; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_signaling_NaN; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_denorm; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::has_denorm_loss; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_iec559; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_bounded; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::is_modulo; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::traps; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::tinyness_before; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >::round_style; |
| |
| #endif |
| |
| template<boost::multiprecision::expression_template_option ExpressionTemplates> |
| class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> > |
| { |
| typedef boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> number_type; |
| public: |
| BOOST_STATIC_CONSTEXPR bool is_specialized = true; |
| // |
| // Largest and smallest numbers are bounded only by available memory, set |
| // to zero: |
| // |
| static number_type (min)() |
| { |
| return number_type(); |
| } |
| static number_type (max)() |
| { |
| return number_type(); |
| } |
| static number_type lowest() { return (min)(); } |
| BOOST_STATIC_CONSTEXPR int digits = INT_MAX; |
| BOOST_STATIC_CONSTEXPR int digits10 = (INT_MAX / 1000) * 301L; |
| BOOST_STATIC_CONSTEXPR int max_digits10 = digits10 + 2; |
| BOOST_STATIC_CONSTEXPR bool is_signed = true; |
| BOOST_STATIC_CONSTEXPR bool is_integer = true; |
| BOOST_STATIC_CONSTEXPR bool is_exact = true; |
| BOOST_STATIC_CONSTEXPR int radix = 2; |
| static number_type epsilon() { return number_type(); } |
| static number_type round_error() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR int min_exponent = 0; |
| BOOST_STATIC_CONSTEXPR int min_exponent10 = 0; |
| BOOST_STATIC_CONSTEXPR int max_exponent = 0; |
| BOOST_STATIC_CONSTEXPR int max_exponent10 = 0; |
| BOOST_STATIC_CONSTEXPR bool has_infinity = false; |
| BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = false; |
| BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false; |
| BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent; |
| BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false; |
| static number_type infinity() { return number_type(); } |
| static number_type quiet_NaN() { return number_type(); } |
| static number_type signaling_NaN() { return number_type(); } |
| static number_type denorm_min() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR bool is_iec559 = false; |
| BOOST_STATIC_CONSTEXPR bool is_bounded = false; |
| BOOST_STATIC_CONSTEXPR bool is_modulo = false; |
| BOOST_STATIC_CONSTEXPR bool traps = false; |
| BOOST_STATIC_CONSTEXPR bool tinyness_before = false; |
| BOOST_STATIC_CONSTEXPR float_round_style round_style = round_toward_zero; |
| }; |
| |
| #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION |
| |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::digits; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::digits10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_digits10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_signed; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_integer; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_exact; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::radix; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::min_exponent; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::min_exponent10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_exponent; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::max_exponent10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_infinity; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_quiet_NaN; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_signaling_NaN; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_denorm; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::has_denorm_loss; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_iec559; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_bounded; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::is_modulo; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::traps; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::tinyness_before; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_int, ExpressionTemplates> >::round_style; |
| |
| #endif |
| |
| template<boost::multiprecision::expression_template_option ExpressionTemplates> |
| class numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> > |
| { |
| typedef boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> number_type; |
| public: |
| BOOST_STATIC_CONSTEXPR bool is_specialized = true; |
| // |
| // Largest and smallest numbers are bounded only by available memory, set |
| // to zero: |
| // |
| static number_type (min)() |
| { |
| return number_type(); |
| } |
| static number_type (max)() |
| { |
| return number_type(); |
| } |
| static number_type lowest() { return (min)(); } |
| // Digits are unbounded, use zero for now: |
| BOOST_STATIC_CONSTEXPR int digits = INT_MAX; |
| BOOST_STATIC_CONSTEXPR int digits10 = (INT_MAX / 1000) * 301L; |
| BOOST_STATIC_CONSTEXPR int max_digits10 = digits10 + 2; |
| BOOST_STATIC_CONSTEXPR bool is_signed = true; |
| BOOST_STATIC_CONSTEXPR bool is_integer = false; |
| BOOST_STATIC_CONSTEXPR bool is_exact = true; |
| BOOST_STATIC_CONSTEXPR int radix = 2; |
| static number_type epsilon() { return number_type(); } |
| static number_type round_error() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR int min_exponent = 0; |
| BOOST_STATIC_CONSTEXPR int min_exponent10 = 0; |
| BOOST_STATIC_CONSTEXPR int max_exponent = 0; |
| BOOST_STATIC_CONSTEXPR int max_exponent10 = 0; |
| BOOST_STATIC_CONSTEXPR bool has_infinity = false; |
| BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = false; |
| BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false; |
| BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent; |
| BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false; |
| static number_type infinity() { return number_type(); } |
| static number_type quiet_NaN() { return number_type(); } |
| static number_type signaling_NaN() { return number_type(); } |
| static number_type denorm_min() { return number_type(); } |
| BOOST_STATIC_CONSTEXPR bool is_iec559 = false; |
| BOOST_STATIC_CONSTEXPR bool is_bounded = false; |
| BOOST_STATIC_CONSTEXPR bool is_modulo = false; |
| BOOST_STATIC_CONSTEXPR bool traps = false; |
| BOOST_STATIC_CONSTEXPR bool tinyness_before = false; |
| BOOST_STATIC_CONSTEXPR float_round_style round_style = round_toward_zero; |
| }; |
| |
| #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION |
| |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::digits; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::digits10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_digits10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_signed; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_integer; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_exact; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::radix; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::min_exponent; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::min_exponent10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_exponent; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::max_exponent10; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_infinity; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_quiet_NaN; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_signaling_NaN; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_denorm; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::has_denorm_loss; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_iec559; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_bounded; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::is_modulo; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::traps; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::tinyness_before; |
| template <boost::multiprecision::expression_template_option ExpressionTemplates> |
| BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::gmp_rational, ExpressionTemplates> >::round_style; |
| |
| #endif |
| |
| #ifdef BOOST_MSVC |
| #pragma warning(pop) |
| #endif |
| |
| } // namespace std |
| |
| #endif |