/////////////////////////////////////////////////////////////////////////////// // Copyright 2018 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_MULTIPRECISION_MPC_HPP #define BOOST_MULTIPRECISION_MPC_HPP #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BOOST_MULTIPRECISION_MPFI_DEFAULT_PRECISION #define BOOST_MULTIPRECISION_MPFI_DEFAULT_PRECISION 20 #endif namespace boost { namespace multiprecision { namespace backends { template struct mpc_complex_backend; } // namespace backends template struct number_category > : public std::integral_constant {}; namespace backends { namespace detail { inline void mpc_copy_precision(mpc_t dest, const mpc_t src) { mpfr_prec_t p_dest = mpc_get_prec(dest); mpfr_prec_t p_src = mpc_get_prec(src); if (p_dest != p_src) mpc_set_prec(dest, p_src); } inline void mpc_copy_precision(mpc_t dest, const mpc_t src1, const mpc_t src2) { mpfr_prec_t p_dest = mpc_get_prec(dest); mpfr_prec_t p_src1 = mpc_get_prec(src1); mpfr_prec_t p_src2 = mpc_get_prec(src2); if (p_src2 > p_src1) p_src1 = p_src2; if (p_dest != p_src1) mpc_set_prec(dest, p_src1); } template struct mpc_complex_imp { #ifdef BOOST_HAS_LONG_LONG using signed_types = std::tuple ; using unsigned_types = std::tuple; #else using signed_types = std::tuple ; using unsigned_types = std::tuple; #endif using float_types = std::tuple; using exponent_type = long ; mpc_complex_imp() { mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpc_set_ui(m_data, 0u, GMP_RNDN); } mpc_complex_imp(unsigned digits2) { mpc_init2(m_data, digits2); mpc_set_ui(m_data, 0u, GMP_RNDN); } mpc_complex_imp(const mpc_complex_imp& o) { mpc_init2(m_data, mpc_get_prec(o.m_data)); if (o.m_data[0].re[0]._mpfr_d) mpc_set(m_data, o.m_data, GMP_RNDN); } // rvalue copy mpc_complex_imp(mpc_complex_imp&& o) noexcept { m_data[0] = o.m_data[0]; o.m_data[0].re[0]._mpfr_d = 0; } mpc_complex_imp& operator=(const mpc_complex_imp& o) { if ((o.m_data[0].re[0]._mpfr_d) && (this != &o)) { if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, mpc_get_prec(o.m_data)); mpc_set(m_data, o.m_data, GMP_RNDD); } return *this; } // rvalue assign mpc_complex_imp& operator=(mpc_complex_imp&& o) noexcept { mpc_swap(m_data, o.m_data); return *this; } #ifdef BOOST_HAS_LONG_LONG #ifdef _MPFR_H_HAVE_INTMAX_T mpc_complex_imp& operator=(boost::ulong_long_type i) { if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpc_set_uj(data(), i, GMP_RNDD); return *this; } mpc_complex_imp& operator=(boost::long_long_type i) { if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpc_set_sj(data(), i, GMP_RNDD); return *this; } #else mpc_complex_imp& operator=(boost::ulong_long_type i) { mpfr_float_backend f(0uL, mpc_get_prec(m_data)); f = i; mpc_set_fr(this->data(), f.data(), GMP_RNDN); return *this; } mpc_complex_imp& operator=(boost::long_long_type i) { mpfr_float_backend f(0uL, mpc_get_prec(m_data)); f = i; mpc_set_fr(this->data(), f.data(), GMP_RNDN); return *this; } #endif #endif mpc_complex_imp& operator=(unsigned long i) { if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpc_set_ui(m_data, i, GMP_RNDN); return *this; } mpc_complex_imp& operator=(long i) { if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpc_set_si(m_data, i, GMP_RNDN); return *this; } mpc_complex_imp& operator=(double d) { if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpc_set_d(m_data, d, GMP_RNDN); return *this; } mpc_complex_imp& operator=(long double d) { if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpc_set_ld(m_data, d, GMP_RNDN); return *this; } mpc_complex_imp& operator=(mpz_t i) { if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpc_set_z(m_data, i, GMP_RNDN); return *this; } mpc_complex_imp& operator=(gmp_int i) { if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpc_set_z(m_data, i.data(), GMP_RNDN); return *this; } mpc_complex_imp& operator=(const char* s) { using default_ops::eval_fpclassify; if (m_data[0].re[0]._mpfr_d == 0) mpc_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpfr_float_backend a(0uL, mpc_get_prec(m_data)), b(0uL, mpc_get_prec(m_data)); if (s && (*s == '(')) { std::string part; const char* p = ++s; while (*p && (*p != ',') && (*p != ')')) ++p; part.assign(s, p); if (part.size()) a = part.c_str(); else a = 0uL; s = p; if (*p && (*p != ')')) { ++p; while (*p && (*p != ')')) ++p; part.assign(s + 1, p); } else part.erase(); if (part.size()) b = part.c_str(); else b = 0uL; } else { a = s; b = 0uL; } if (eval_fpclassify(a) == (int)FP_NAN) { mpc_set_fr(this->data(), a.data(), GMP_RNDN); } else if (eval_fpclassify(b) == (int)FP_NAN) { mpc_set_fr(this->data(), b.data(), GMP_RNDN); } else { mpc_set_fr_fr(m_data, a.data(), b.data(), GMP_RNDN); } return *this; } void swap(mpc_complex_imp& o) noexcept { mpc_swap(m_data, o.m_data); } std::string str(std::streamsize digits, std::ios_base::fmtflags f) const { BOOST_ASSERT(m_data[0].re[0]._mpfr_d); mpfr_float_backend a(0uL, mpc_get_prec(m_data)), b(0uL, mpc_get_prec(m_data)); mpc_real(a.data(), m_data, GMP_RNDD); mpc_imag(b.data(), m_data, GMP_RNDD); if (eval_is_zero(b)) return a.str(digits, f); return "(" + a.str(digits, f) + "," + b.str(digits, f) + ")"; } ~mpc_complex_imp() noexcept { if (m_data[0].re[0]._mpfr_d) mpc_clear(m_data); } void negate() noexcept { BOOST_ASSERT(m_data[0].re[0]._mpfr_d); mpc_neg(m_data, m_data, GMP_RNDD); } int compare(const mpc_complex_imp& o) const noexcept { BOOST_ASSERT(m_data[0].re[0]._mpfr_d && o.m_data[0].re[0]._mpfr_d); return mpc_cmp(m_data, o.m_data); } int compare(const mpc_complex_backend& o) const noexcept { BOOST_ASSERT(m_data[0].re[0]._mpfr_d && o.m_data[0].re[0]._mpfr_d); return mpc_cmp(m_data, o.data()); } int compare(long int i) const noexcept { BOOST_ASSERT(m_data[0].re[0]._mpfr_d); return mpc_cmp_si(m_data, i); } int compare(unsigned long int i) const noexcept { BOOST_ASSERT(m_data[0].re[0]._mpfr_d); constexpr const unsigned long int max_val = (std::numeric_limits::max)(); if (i > max_val) { mpc_complex_imp d(mpc_get_prec(m_data)); d = i; return compare(d); } return mpc_cmp_si(m_data, (long)i); } template int compare(const V& v) const noexcept { mpc_complex_imp d(mpc_get_prec(m_data)); d = v; return compare(d); } mpc_t& data() noexcept { BOOST_ASSERT(m_data[0].re[0]._mpfr_d); return m_data; } const mpc_t& data() const noexcept { BOOST_ASSERT(m_data[0].re[0]._mpfr_d); return m_data; } protected: mpc_t m_data; static boost::multiprecision::detail::precision_type& get_default_precision() noexcept { static boost::multiprecision::detail::precision_type val(BOOST_MULTIPRECISION_MPFI_DEFAULT_PRECISION); return val; } }; } // namespace detail template struct mpc_complex_backend : public detail::mpc_complex_imp { mpc_complex_backend() : detail::mpc_complex_imp() {} mpc_complex_backend(const mpc_complex_backend& o) : detail::mpc_complex_imp(o) {} // rvalue copy mpc_complex_backend(mpc_complex_backend&& o) : detail::mpc_complex_imp(static_cast&&>(o)) {} template mpc_complex_backend(const mpc_complex_backend& val, typename std::enable_if::type* = 0) : detail::mpc_complex_imp() { mpc_set(this->m_data, val.data(), GMP_RNDN); } template explicit mpc_complex_backend(const mpc_complex_backend& val, typename std::enable_if::type* = 0) : detail::mpc_complex_imp() { mpc_set(this->m_data, val.data(), GMP_RNDN); } template mpc_complex_backend(const mpfr_float_backend& val, typename std::enable_if::type* = 0) : detail::mpc_complex_imp() { mpc_set_fr(this->m_data, val.data(), GMP_RNDN); } template explicit mpc_complex_backend(const mpfr_float_backend& val, typename std::enable_if::type* = 0) : detail::mpc_complex_imp() { mpc_set(this->m_data, val.data(), GMP_RNDN); } mpc_complex_backend(const mpc_t val) : detail::mpc_complex_imp() { mpc_set(this->m_data, val, GMP_RNDN); } mpc_complex_backend(const std::complex& val) : detail::mpc_complex_imp() { mpc_set_d_d(this->m_data, val.real(), val.imag(), GMP_RNDN); } mpc_complex_backend(const std::complex& val) : detail::mpc_complex_imp() { mpc_set_d_d(this->m_data, val.real(), val.imag(), GMP_RNDN); } mpc_complex_backend(const std::complex& val) : detail::mpc_complex_imp() { mpc_set_ld_ld(this->m_data, val.real(), val.imag(), GMP_RNDN); } mpc_complex_backend(mpz_srcptr val) : detail::mpc_complex_imp() { mpc_set_z(this->m_data, val, GMP_RNDN); } mpc_complex_backend& operator=(mpz_srcptr val) { mpc_set_z(this->m_data, val, GMP_RNDN); return *this; } mpc_complex_backend(gmp_int const& val) : detail::mpc_complex_imp() { mpc_set_z(this->m_data, val.data(), GMP_RNDN); } mpc_complex_backend& operator=(gmp_int const& val) { mpc_set_z(this->m_data, val.data(), GMP_RNDN); return *this; } mpc_complex_backend(mpf_srcptr val) : detail::mpc_complex_imp() { mpc_set_f(this->m_data, val, GMP_RNDN); } mpc_complex_backend& operator=(mpf_srcptr val) { mpc_set_f(this->m_data, val, GMP_RNDN); return *this; } template mpc_complex_backend(gmp_float const& val) : detail::mpc_complex_imp() { mpc_set_f(this->m_data, val.data(), GMP_RNDN); } template mpc_complex_backend& operator=(gmp_float const& val) { mpc_set_f(this->m_data, val.data(), GMP_RNDN); return *this; } mpc_complex_backend(mpq_srcptr val) : detail::mpc_complex_imp() { mpc_set_q(this->m_data, val, GMP_RNDN); } mpc_complex_backend& operator=(mpq_srcptr val) { mpc_set_q(this->m_data, val, GMP_RNDN); return *this; } mpc_complex_backend(gmp_rational const& val) : detail::mpc_complex_imp() { mpc_set_q(this->m_data, val.data(), GMP_RNDN); } mpc_complex_backend& operator=(gmp_rational const& val) { mpc_set_q(this->m_data, val.data(), GMP_RNDN); return *this; } mpc_complex_backend(mpfr_srcptr val) : detail::mpc_complex_imp() { mpc_set_fr(this->m_data, val, GMP_RNDN); } mpc_complex_backend& operator=(mpfr_srcptr val) { mpc_set_fr(this->m_data, val, GMP_RNDN); return *this; } template mpc_complex_backend(mpfr_float_backend const& val) : detail::mpc_complex_imp() { mpc_set_fr(this->m_data, val.data(), GMP_RNDN); } template mpc_complex_backend& operator=(mpfr_float_backend const& val) { mpc_set_fr(this->m_data, val.data(), GMP_RNDN); return *this; } mpc_complex_backend& operator=(const mpc_complex_backend& o) { *static_cast*>(this) = static_cast const&>(o); return *this; } // rvalue assign mpc_complex_backend& operator=(mpc_complex_backend&& o) noexcept { *static_cast*>(this) = static_cast&&>(o); return *this; } template mpc_complex_backend& operator=(const V& v) { *static_cast*>(this) = v; return *this; } mpc_complex_backend& operator=(const mpc_t val) { mpc_set(this->m_data, val, GMP_RNDN); return *this; } mpc_complex_backend& operator=(const std::complex& val) { mpc_set_d_d(this->m_data, val.real(), val.imag(), GMP_RNDN); return *this; } mpc_complex_backend& operator=(const std::complex& val) { mpc_set_d_d(this->m_data, val.real(), val.imag(), GMP_RNDN); return *this; } mpc_complex_backend& operator=(const std::complex& val) { mpc_set_ld_ld(this->m_data, val.real(), val.imag(), GMP_RNDN); return *this; } // We don't change our precision here, this is a fixed precision type: template mpc_complex_backend& operator=(const mpc_complex_backend& val) { mpc_set(this->m_data, val.data(), GMP_RNDN); return *this; } }; template <> struct mpc_complex_backend<0> : public detail::mpc_complex_imp<0> { mpc_complex_backend() : detail::mpc_complex_imp<0>() {} mpc_complex_backend(const mpc_t val) : detail::mpc_complex_imp<0>(mpc_get_prec(val)) { mpc_set(this->m_data, val, GMP_RNDN); } mpc_complex_backend(const mpc_complex_backend& o) : detail::mpc_complex_imp<0>(o) {} // rvalue copy mpc_complex_backend(mpc_complex_backend&& o) noexcept : detail::mpc_complex_imp<0>(static_cast&&>(o)) {} mpc_complex_backend(const mpc_complex_backend& o, unsigned digits10) : detail::mpc_complex_imp<0>(multiprecision::detail::digits10_2_2(digits10)) { mpc_set(this->m_data, o.data(), GMP_RNDN); } template mpc_complex_backend(const mpc_complex_backend& val) : detail::mpc_complex_imp<0>(mpc_get_prec(val.data())) { mpc_set(this->m_data, val.data(), GMP_RNDN); } template mpc_complex_backend(const mpfr_float_backend& val) : detail::mpc_complex_imp<0>(mpfr_get_prec(val.data())) { mpc_set_fr(this->m_data, val.data(), GMP_RNDN); } mpc_complex_backend(mpz_srcptr val) : detail::mpc_complex_imp<0>() { mpc_set_z(this->m_data, val, GMP_RNDN); } mpc_complex_backend& operator=(mpz_srcptr val) { mpc_set_z(this->m_data, val, GMP_RNDN); return *this; } mpc_complex_backend(gmp_int const& val) : detail::mpc_complex_imp<0>() { mpc_set_z(this->m_data, val.data(), GMP_RNDN); } mpc_complex_backend& operator=(gmp_int const& val) { mpc_set_z(this->m_data, val.data(), GMP_RNDN); return *this; } mpc_complex_backend(mpf_srcptr val) : detail::mpc_complex_imp<0>((unsigned)mpf_get_prec(val)) { mpc_set_f(this->m_data, val, GMP_RNDN); } mpc_complex_backend& operator=(mpf_srcptr val) { if ((mp_bitcnt_t)mpc_get_prec(data()) != mpf_get_prec(val)) { mpc_complex_backend t(val); t.swap(*this); } else mpc_set_f(this->m_data, val, GMP_RNDN); return *this; } template mpc_complex_backend(gmp_float const& val) : detail::mpc_complex_imp<0>((unsigned)mpf_get_prec(val.data())) { mpc_set_f(this->m_data, val.data(), GMP_RNDN); } template mpc_complex_backend& operator=(gmp_float const& val) { if (mpc_get_prec(data()) != (mpfr_prec_t)mpf_get_prec(val.data())) { mpc_complex_backend t(val); t.swap(*this); } else mpc_set_f(this->m_data, val.data(), GMP_RNDN); return *this; } mpc_complex_backend(mpq_srcptr val) : detail::mpc_complex_imp<0>() { mpc_set_q(this->m_data, val, GMP_RNDN); } mpc_complex_backend& operator=(mpq_srcptr val) { mpc_set_q(this->m_data, val, GMP_RNDN); return *this; } mpc_complex_backend(gmp_rational const& val) : detail::mpc_complex_imp<0>() { mpc_set_q(this->m_data, val.data(), GMP_RNDN); } mpc_complex_backend& operator=(gmp_rational const& val) { mpc_set_q(this->m_data, val.data(), GMP_RNDN); return *this; } mpc_complex_backend(mpfr_srcptr val) : detail::mpc_complex_imp<0>(mpfr_get_prec(val)) { mpc_set_fr(this->m_data, val, GMP_RNDN); } mpc_complex_backend& operator=(mpfr_srcptr val) { if (mpc_get_prec(data()) != mpfr_get_prec(val)) { mpc_complex_backend t(val); t.swap(*this); } else mpc_set_fr(this->m_data, val, GMP_RNDN); return *this; } mpc_complex_backend(const std::complex& val) : detail::mpc_complex_imp<0>() { mpc_set_d_d(this->m_data, val.real(), val.imag(), GMP_RNDN); } mpc_complex_backend(const std::complex& val) : detail::mpc_complex_imp<0>() { mpc_set_d_d(this->m_data, val.real(), val.imag(), GMP_RNDN); } mpc_complex_backend(const std::complex& val) : detail::mpc_complex_imp<0>() { mpc_set_ld_ld(this->m_data, val.real(), val.imag(), GMP_RNDN); } // Construction with precision: template mpc_complex_backend(const T& a, const U& b, unsigned digits10) : detail::mpc_complex_imp<0>(multiprecision::detail::digits10_2_2(digits10)) { // We can't use assign_components here because it copies the precision of // a and b, not digits10.... mpfr_float ca(a), cb(b); mpc_set_fr_fr(this->data(), ca.backend().data(), cb.backend().data(), GMP_RNDN); } template mpc_complex_backend(const mpfr_float_backend& a, const mpfr_float_backend& b, unsigned digits10) : detail::mpc_complex_imp<0>(multiprecision::detail::digits10_2_2(digits10)) { mpc_set_fr_fr(this->data(), a.data(), b.data(), GMP_RNDN); } mpc_complex_backend& operator=(const mpc_complex_backend& o) { if (this != &o) { detail::mpc_copy_precision(this->m_data, o.data()); mpc_set(this->m_data, o.data(), GMP_RNDN); } return *this; } // rvalue assign mpc_complex_backend& operator=(mpc_complex_backend&& o) noexcept { *static_cast*>(this) = static_cast&&>(o); return *this; } template mpc_complex_backend& operator=(const V& v) { *static_cast*>(this) = v; return *this; } mpc_complex_backend& operator=(const mpc_t val) { mpc_set_prec(this->m_data, mpc_get_prec(val)); mpc_set(this->m_data, val, GMP_RNDN); return *this; } template mpc_complex_backend& operator=(const mpc_complex_backend& val) { mpc_set_prec(this->m_data, mpc_get_prec(val.data())); mpc_set(this->m_data, val.data(), GMP_RNDN); return *this; } template mpc_complex_backend& operator=(const mpfr_float_backend& val) { mpc_set_prec(this->m_data, mpfr_get_prec(val.data())); mpc_set_fr(this->m_data, val.data(), GMP_RNDN); return *this; } mpc_complex_backend& operator=(const std::complex& val) { mpc_set_d_d(this->m_data, val.real(), val.imag(), GMP_RNDN); return *this; } mpc_complex_backend& operator=(const std::complex& val) { mpc_set_d_d(this->m_data, val.real(), val.imag(), GMP_RNDN); return *this; } mpc_complex_backend& operator=(const std::complex& val) { mpc_set_ld_ld(this->m_data, val.real(), val.imag(), GMP_RNDN); return *this; } static unsigned default_precision() noexcept { return get_default_precision(); } static void default_precision(unsigned v) noexcept { get_default_precision() = v; } unsigned precision() const noexcept { return multiprecision::detail::digits2_2_10(mpc_get_prec(this->m_data)); } void precision(unsigned digits10) noexcept { mpfr_prec_round(mpc_realref(this->m_data), multiprecision::detail::digits10_2_2((digits10)), GMP_RNDN); mpfr_prec_round(mpc_imagref(this->m_data), multiprecision::detail::digits10_2_2((digits10)), GMP_RNDN); } }; template inline typename std::enable_if::value, bool>::type eval_eq(const mpc_complex_backend& a, const T& b) noexcept { return a.compare(b) == 0; } template inline typename std::enable_if::value, bool>::type eval_lt(const mpc_complex_backend& a, const T& b) noexcept { return a.compare(b) < 0; } template inline typename std::enable_if::value, bool>::type eval_gt(const mpc_complex_backend& a, const T& b) noexcept { return a.compare(b) > 0; } template inline void eval_add(mpc_complex_backend& result, const mpc_complex_backend& o) { mpc_add(result.data(), result.data(), o.data(), GMP_RNDD); } template inline void eval_add(mpc_complex_backend& result, const mpfr_float_backend& o) { mpc_add_fr(result.data(), result.data(), o.data(), GMP_RNDD); } template inline void eval_subtract(mpc_complex_backend& result, const mpc_complex_backend& o) { mpc_sub(result.data(), result.data(), o.data(), GMP_RNDD); } template inline void eval_subtract(mpc_complex_backend& result, const mpfr_float_backend& o) { mpc_sub_fr(result.data(), result.data(), o.data(), GMP_RNDD); } template inline void eval_multiply(mpc_complex_backend& result, const mpc_complex_backend& o) { if ((void*)&result == (void*)&o) mpc_sqr(result.data(), o.data(), GMP_RNDN); else mpc_mul(result.data(), result.data(), o.data(), GMP_RNDN); } template inline void eval_multiply(mpc_complex_backend& result, const mpfr_float_backend& o) { mpc_mul_fr(result.data(), result.data(), o.data(), GMP_RNDN); } template inline void eval_divide(mpc_complex_backend& result, const mpc_complex_backend& o) { mpc_div(result.data(), result.data(), o.data(), GMP_RNDD); } template inline void eval_divide(mpc_complex_backend& result, const mpfr_float_backend& o) { mpc_div_fr(result.data(), result.data(), o.data(), GMP_RNDD); } template inline void eval_add(mpc_complex_backend& result, unsigned long i) { mpc_add_ui(result.data(), result.data(), i, GMP_RNDN); } template inline void eval_subtract(mpc_complex_backend& result, unsigned long i) { mpc_sub_ui(result.data(), result.data(), i, GMP_RNDN); } template inline void eval_multiply(mpc_complex_backend& result, unsigned long i) { mpc_mul_ui(result.data(), result.data(), i, GMP_RNDN); } template inline void eval_divide(mpc_complex_backend& result, unsigned long i) { mpc_div_ui(result.data(), result.data(), i, GMP_RNDN); } template inline void eval_add(mpc_complex_backend& result, long i) { if (i > 0) mpc_add_ui(result.data(), result.data(), i, GMP_RNDN); else mpc_sub_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i), GMP_RNDN); } template inline void eval_subtract(mpc_complex_backend& result, long i) { if (i > 0) mpc_sub_ui(result.data(), result.data(), i, GMP_RNDN); else mpc_add_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i), GMP_RNDN); } template inline void eval_multiply(mpc_complex_backend& result, long i) { mpc_mul_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i), GMP_RNDN); if (i < 0) mpc_neg(result.data(), result.data(), GMP_RNDN); } template inline void eval_divide(mpc_complex_backend& result, long i) { mpc_div_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i), GMP_RNDN); if (i < 0) mpc_neg(result.data(), result.data(), GMP_RNDN); } // // Specialised 3 arg versions of the basic operators: // template inline void eval_add(mpc_complex_backend& a, const mpc_complex_backend& x, const mpc_complex_backend& y) { mpc_add(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_add(mpc_complex_backend& a, const mpc_complex_backend& x, const mpfr_float_backend& y) { mpc_add_fr(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_add(mpc_complex_backend& a, const mpfr_float_backend& x, const mpc_complex_backend& y) { mpc_add_fr(a.data(), y.data(), x.data(), GMP_RNDD); } template inline void eval_add(mpc_complex_backend& a, const mpc_complex_backend& x, unsigned long y) { mpc_add_ui(a.data(), x.data(), y, GMP_RNDD); } template inline void eval_add(mpc_complex_backend& a, const mpc_complex_backend& x, long y) { if (y < 0) mpc_sub_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y), GMP_RNDD); else mpc_add_ui(a.data(), x.data(), y, GMP_RNDD); } template inline void eval_add(mpc_complex_backend& a, unsigned long x, const mpc_complex_backend& y) { mpc_add_ui(a.data(), y.data(), x, GMP_RNDD); } template inline void eval_add(mpc_complex_backend& a, long x, const mpc_complex_backend& y) { if (x < 0) { mpc_ui_sub(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data(), GMP_RNDN); mpc_neg(a.data(), a.data(), GMP_RNDD); } else mpc_add_ui(a.data(), y.data(), x, GMP_RNDD); } template inline void eval_subtract(mpc_complex_backend& a, const mpc_complex_backend& x, const mpc_complex_backend& y) { mpc_sub(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_subtract(mpc_complex_backend& a, const mpc_complex_backend& x, const mpfr_float_backend& y) { mpc_sub_fr(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_subtract(mpc_complex_backend& a, const mpfr_float_backend& x, const mpc_complex_backend& y) { mpc_fr_sub(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_subtract(mpc_complex_backend& a, const mpc_complex_backend& x, unsigned long y) { mpc_sub_ui(a.data(), x.data(), y, GMP_RNDD); } template inline void eval_subtract(mpc_complex_backend& a, const mpc_complex_backend& x, long y) { if (y < 0) mpc_add_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y), GMP_RNDD); else mpc_sub_ui(a.data(), x.data(), y, GMP_RNDD); } template inline void eval_subtract(mpc_complex_backend& a, unsigned long x, const mpc_complex_backend& y) { mpc_ui_sub(a.data(), x, y.data(), GMP_RNDN); } template inline void eval_subtract(mpc_complex_backend& a, long x, const mpc_complex_backend& y) { if (x < 0) { mpc_add_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x), GMP_RNDD); mpc_neg(a.data(), a.data(), GMP_RNDD); } else mpc_ui_sub(a.data(), x, y.data(), GMP_RNDN); } template inline void eval_multiply(mpc_complex_backend& a, const mpc_complex_backend& x, const mpc_complex_backend& y) { if ((void*)&x == (void*)&y) mpc_sqr(a.data(), x.data(), GMP_RNDD); else mpc_mul(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_multiply(mpc_complex_backend& a, const mpc_complex_backend& x, const mpfr_float_backend& y) { mpc_mul_fr(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_multiply(mpc_complex_backend& a, const mpfr_float_backend& x, const mpc_complex_backend& y) { mpc_mul_fr(a.data(), y.data(), x.data(), GMP_RNDD); } template inline void eval_multiply(mpc_complex_backend& a, const mpc_complex_backend& x, unsigned long y) { mpc_mul_ui(a.data(), x.data(), y, GMP_RNDD); } template inline void eval_multiply(mpc_complex_backend& a, const mpc_complex_backend& x, long y) { if (y < 0) { mpc_mul_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y), GMP_RNDD); a.negate(); } else mpc_mul_ui(a.data(), x.data(), y, GMP_RNDD); } template inline void eval_multiply(mpc_complex_backend& a, unsigned long x, const mpc_complex_backend& y) { mpc_mul_ui(a.data(), y.data(), x, GMP_RNDD); } template inline void eval_multiply(mpc_complex_backend& a, long x, const mpc_complex_backend& y) { if (x < 0) { mpc_mul_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x), GMP_RNDD); mpc_neg(a.data(), a.data(), GMP_RNDD); } else mpc_mul_ui(a.data(), y.data(), x, GMP_RNDD); } template inline void eval_divide(mpc_complex_backend& a, const mpc_complex_backend& x, const mpc_complex_backend& y) { mpc_div(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_divide(mpc_complex_backend& a, const mpc_complex_backend& x, const mpfr_float_backend& y) { mpc_div_fr(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_divide(mpc_complex_backend& a, const mpfr_float_backend& x, const mpc_complex_backend& y) { mpc_fr_div(a.data(), x.data(), y.data(), GMP_RNDD); } template inline void eval_divide(mpc_complex_backend& a, const mpc_complex_backend& x, unsigned long y) { mpc_div_ui(a.data(), x.data(), y, GMP_RNDD); } template inline void eval_divide(mpc_complex_backend& a, const mpc_complex_backend& x, long y) { if (y < 0) { mpc_div_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y), GMP_RNDD); a.negate(); } else mpc_div_ui(a.data(), x.data(), y, GMP_RNDD); } template inline void eval_divide(mpc_complex_backend& a, unsigned long x, const mpc_complex_backend& y) { mpc_ui_div(a.data(), x, y.data(), GMP_RNDD); } template inline void eval_divide(mpc_complex_backend& a, long x, const mpc_complex_backend& y) { if (x < 0) { mpc_ui_div(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data(), GMP_RNDD); mpc_neg(a.data(), a.data(), GMP_RNDD); } else mpc_ui_div(a.data(), x, y.data(), GMP_RNDD); } template inline bool eval_is_zero(const mpc_complex_backend& val) noexcept { return (0 != mpfr_zero_p(mpc_realref(val.data()))) && (0 != mpfr_zero_p(mpc_imagref(val.data()))); } template inline int eval_get_sign(const mpc_complex_backend&) { static_assert(digits10 == UINT_MAX, "Complex numbers have no sign bit."); // designed to always fail return 0; } template inline void eval_convert_to(unsigned long* result, const mpc_complex_backend& val) { if (0 == mpfr_zero_p(mpc_imagref(val.data()))) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar.")); } mpfr_float_backend t; mpc_real(t.data(), val.data(), GMP_RNDN); eval_convert_to(result, t); } template inline void eval_convert_to(long* result, const mpc_complex_backend& val) { if (0 == mpfr_zero_p(mpc_imagref(val.data()))) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar.")); } mpfr_float_backend t; mpc_real(t.data(), val.data(), GMP_RNDN); eval_convert_to(result, t); } #ifdef _MPFR_H_HAVE_INTMAX_T template inline void eval_convert_to(boost::ulong_long_type* result, const mpc_complex_backend& val) { if (0 == mpfr_zero_p(mpc_imagref(val.data()))) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar.")); } mpfr_float_backend t; mpc_real(t.data(), val.data(), GMP_RNDN); eval_convert_to(result, t); } template inline void eval_convert_to(boost::long_long_type* result, const mpc_complex_backend& val) { if (0 == mpfr_zero_p(mpc_imagref(val.data()))) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar.")); } mpfr_float_backend t; mpc_real(t.data(), val.data(), GMP_RNDN); eval_convert_to(result, t); } #endif template inline void eval_convert_to(double* result, const mpc_complex_backend& val) noexcept { if (0 == mpfr_zero_p(mpc_imagref(val.data()))) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar.")); } mpfr_float_backend t; mpc_real(t.data(), val.data(), GMP_RNDN); eval_convert_to(result, t); } template inline void eval_convert_to(long double* result, const mpc_complex_backend& val) noexcept { if (0 == mpfr_zero_p(mpc_imagref(val.data()))) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar.")); } mpfr_float_backend t; mpc_real(t.data(), val.data(), GMP_RNDN); eval_convert_to(result, t); } template inline void assign_components(mpc_complex_backend& result, const mpfr_float_backend& a, const mpfr_float_backend& b) { // // This is called from class number's constructors, so if we have variable // precision, then copy the precision of the source variables. // if (!D1) { unsigned long prec = (std::max)(mpfr_get_prec(a.data()), mpfr_get_prec(b.data())); mpc_set_prec(result.data(), prec); } using default_ops::eval_fpclassify; if (eval_fpclassify(a) == (int)FP_NAN) { mpc_set_fr(result.data(), a.data(), GMP_RNDN); } else if (eval_fpclassify(b) == (int)FP_NAN) { mpc_set_fr(result.data(), b.data(), GMP_RNDN); } else { mpc_set_fr_fr(result.data(), a.data(), b.data(), GMP_RNDN); } } template inline void assign_components(mpc_complex_backend& result, unsigned long a, unsigned long b) { mpc_set_ui_ui(result.data(), a, b, GMP_RNDN); } template inline void assign_components(mpc_complex_backend& result, long a, long b) { mpc_set_si_si(result.data(), a, b, GMP_RNDN); } #if defined(BOOST_HAS_LONG_LONG) && defined(_MPFR_H_HAVE_INTMAX_T) template inline void assign_components(mpc_complex_backend& result, unsigned long long a, unsigned long long b) { mpc_set_uj_uj(result.data(), a, b, GMP_RNDN); } template inline void assign_components(mpc_complex_backend& result, long long a, long long b) { mpc_set_sj_sj(result.data(), a, b, GMP_RNDN); } #endif template inline void assign_components(mpc_complex_backend& result, double a, double b) { if ((boost::math::isnan)(a)) { mpc_set_d(result.data(), a, GMP_RNDN); } else if ((boost::math::isnan)(b)) { mpc_set_d(result.data(), b, GMP_RNDN); } else { mpc_set_d_d(result.data(), a, b, GMP_RNDN); } } template inline void assign_components(mpc_complex_backend& result, long double a, long double b) { if ((boost::math::isnan)(a)) { mpc_set_d(result.data(), a, GMP_RNDN); } else if ((boost::math::isnan)(b)) { mpc_set_d(result.data(), b, GMP_RNDN); } else { mpc_set_ld_ld(result.data(), a, b, GMP_RNDN); } } // // Native non-member operations: // template inline void eval_sqrt(mpc_complex_backend& result, const mpc_complex_backend& val) { mpc_sqrt(result.data(), val.data(), GMP_RNDN); } template inline void eval_pow(mpc_complex_backend& result, const mpc_complex_backend& b, const mpc_complex_backend& e) { mpc_pow(result.data(), b.data(), e.data(), GMP_RNDN); } template inline void eval_exp(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_exp(result.data(), arg.data(), GMP_RNDN); } template inline void eval_log(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_log(result.data(), arg.data(), GMP_RNDN); } template inline void eval_log10(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_log10(result.data(), arg.data(), GMP_RNDN); } template inline void eval_sin(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_sin(result.data(), arg.data(), GMP_RNDN); } template inline void eval_cos(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_cos(result.data(), arg.data(), GMP_RNDN); } template inline void eval_tan(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_tan(result.data(), arg.data(), GMP_RNDN); } template inline void eval_asin(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_asin(result.data(), arg.data(), GMP_RNDN); } template inline void eval_acos(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_acos(result.data(), arg.data(), GMP_RNDN); } template inline void eval_atan(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_atan(result.data(), arg.data(), GMP_RNDN); } template inline void eval_sinh(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_sinh(result.data(), arg.data(), GMP_RNDN); } template inline void eval_cosh(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_cosh(result.data(), arg.data(), GMP_RNDN); } template inline void eval_tanh(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_tanh(result.data(), arg.data(), GMP_RNDN); } template inline void eval_asinh(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_asinh(result.data(), arg.data(), GMP_RNDN); } template inline void eval_acosh(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_acosh(result.data(), arg.data(), GMP_RNDN); } template inline void eval_atanh(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_atanh(result.data(), arg.data(), GMP_RNDN); } template inline void eval_conj(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_conj(result.data(), arg.data(), GMP_RNDN); } template inline void eval_proj(mpc_complex_backend& result, const mpc_complex_backend& arg) { mpc_proj(result.data(), arg.data(), GMP_RNDN); } template inline void eval_real(mpfr_float_backend& result, const mpc_complex_backend& arg) { mpfr_set_prec(result.data(), mpfr_get_prec(mpc_realref(arg.data()))); mpfr_set(result.data(), mpc_realref(arg.data()), GMP_RNDN); } template inline void eval_imag(mpfr_float_backend& result, const mpc_complex_backend& arg) { mpfr_set_prec(result.data(), mpfr_get_prec(mpc_imagref(arg.data()))); mpfr_set(result.data(), mpc_imagref(arg.data()), GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const mpfr_float_backend& arg) { mpfr_set(mpc_imagref(result.data()), arg.data(), GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const mpfr_float_backend& arg) { mpfr_set(mpc_realref(result.data()), arg.data(), GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const gmp_int& arg) { mpfr_set_z(mpc_realref(result.data()), arg.data(), GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const gmp_rational& arg) { mpfr_set_q(mpc_realref(result.data()), arg.data(), GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const unsigned& arg) { mpfr_set_ui(mpc_realref(result.data()), arg, GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const unsigned long& arg) { mpfr_set_ui(mpc_realref(result.data()), arg, GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const int& arg) { mpfr_set_si(mpc_realref(result.data()), arg, GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const long& arg) { mpfr_set_si(mpc_realref(result.data()), arg, GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const float& arg) { mpfr_set_flt(mpc_realref(result.data()), arg, GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const double& arg) { mpfr_set_d(mpc_realref(result.data()), arg, GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const long double& arg) { mpfr_set_ld(mpc_realref(result.data()), arg, GMP_RNDN); } #if defined(BOOST_HAS_LONG_LONG) && defined(_MPFR_H_HAVE_INTMAX_T) template inline void eval_set_real(mpc_complex_backend& result, const unsigned long long& arg) { mpfr_set_uj(mpc_realref(result.data()), arg, GMP_RNDN); } template inline void eval_set_real(mpc_complex_backend& result, const long long& arg) { mpfr_set_sj(mpc_realref(result.data()), arg, GMP_RNDN); } #endif template inline void eval_set_imag(mpc_complex_backend& result, const gmp_int& arg) { mpfr_set_z(mpc_imagref(result.data()), arg.data(), GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const gmp_rational& arg) { mpfr_set_q(mpc_imagref(result.data()), arg.data(), GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const unsigned& arg) { mpfr_set_ui(mpc_imagref(result.data()), arg, GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const unsigned long& arg) { mpfr_set_ui(mpc_imagref(result.data()), arg, GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const int& arg) { mpfr_set_si(mpc_imagref(result.data()), arg, GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const long& arg) { mpfr_set_si(mpc_imagref(result.data()), arg, GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const float& arg) { mpfr_set_flt(mpc_imagref(result.data()), arg, GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const double& arg) { mpfr_set_d(mpc_imagref(result.data()), arg, GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const long double& arg) { mpfr_set_ld(mpc_imagref(result.data()), arg, GMP_RNDN); } #if defined(BOOST_HAS_LONG_LONG) && defined(_MPFR_H_HAVE_INTMAX_T) template inline void eval_set_imag(mpc_complex_backend& result, const unsigned long long& arg) { mpfr_set_uj(mpc_imagref(result.data()), arg, GMP_RNDN); } template inline void eval_set_imag(mpc_complex_backend& result, const long long& arg) { mpfr_set_sj(mpc_imagref(result.data()), arg, GMP_RNDN); } #endif template inline std::size_t hash_value(const mpc_complex_backend& val) { std::size_t result = 0; std::size_t len = val.data()[0].re[0]._mpfr_prec / mp_bits_per_limb; if (val.data()[0].re[0]._mpfr_prec % mp_bits_per_limb) ++len; for (std::size_t i = 0; i < len; ++i) boost::hash_combine(result, val.data()[0].re[0]._mpfr_d[i]); boost::hash_combine(result, val.data()[0].re[0]._mpfr_exp); boost::hash_combine(result, val.data()[0].re[0]._mpfr_sign); len = val.data()[0].im[0]._mpfr_prec / mp_bits_per_limb; if (val.data()[0].im[0]._mpfr_prec % mp_bits_per_limb) ++len; for (std::size_t i = 0; i < len; ++i) boost::hash_combine(result, val.data()[0].im[0]._mpfr_d[i]); boost::hash_combine(result, val.data()[0].im[0]._mpfr_exp); boost::hash_combine(result, val.data()[0].im[0]._mpfr_sign); return result; } } // namespace backends namespace detail { template <> struct is_variable_precision > : public std::integral_constant {}; } // namespace detail template <> struct number_category >::type> : public std::integral_constant {}; using boost::multiprecision::backends::mpc_complex_backend; using mpc_complex_50 = number > ; using mpc_complex_100 = number > ; using mpc_complex_500 = number > ; using mpc_complex_1000 = number >; using mpc_complex = number > ; template struct component_type, ExpressionTemplates> > { using type = number, ExpressionTemplates>; }; template struct component_type >, ExpressionTemplates> > { using type = number, ExpressionTemplates>; }; template struct complex_result_from_scalar, ExpressionTemplates> > { using type = number, ExpressionTemplates>; }; } } // namespace boost::multiprecision #endif