diff --git a/include/boost/multiprecision/complex_adaptor.hpp b/include/boost/multiprecision/complex_adaptor.hpp index 62bb0fc2..8ba050f6 100644 --- a/include/boost/multiprecision/complex_adaptor.hpp +++ b/include/boost/multiprecision/complex_adaptor.hpp @@ -77,6 +77,18 @@ struct complex_adaptor m_real = val.real(); m_imag = val.imag(); } + template + complex_adaptor(const T& a, const U& b, typename std::enable_if::value&& std::is_constructible::value>::type const* = nullptr) + : m_real(a), m_imag(b) {} + template + complex_adaptor(T&& a, const U& b, typename std::enable_if::value&& std::is_constructible::value>::type const* = nullptr) + : m_real(static_cast(a)), m_imag(b) {} + template + complex_adaptor(T&& a, U&& b, typename std::enable_if::value&& std::is_constructible::value>::type const* = nullptr) + : m_real(static_cast(a)), m_imag(static_cast(b)) {} + template + complex_adaptor(const T& a, U&& b, typename std::enable_if::value&& std::is_constructible::value>::type const* = nullptr) + : m_real(a), m_imag(static_cast(b)) {} complex_adaptor& operator=(const complex_adaptor& o) { diff --git a/include/boost/multiprecision/detail/et_ops.hpp b/include/boost/multiprecision/detail/et_ops.hpp index 7a9a4c92..2d881fb5 100644 --- a/include/boost/multiprecision/detail/et_ops.hpp +++ b/include/boost/multiprecision/detail/et_ops.hpp @@ -142,18 +142,21 @@ operator+(const number& a, const detail::expression -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, detail::expression >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, detail::expression >::result_type, number >::value, + typename detail::expression, detail::expression >::result_type>::type operator+(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, detail::expression >::result_type, number >::value) - { - a += b; - return static_cast&&>(a); - } - else - { - return detail::expression, detail::expression >(a, b); - } + a += b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, detail::expression >::result_type, number >::value, + typename detail::expression, detail::expression >::result_type>::type +operator+(number&& a, const detail::expression& b) +{ + return detail::expression, detail::expression >(a, b); } template @@ -164,18 +167,21 @@ operator+(const detail::expression& a, const number } template -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, number >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, number >::result_type, number>::value, + typename detail::expression, number >::result_type>::type operator+(const detail::expression& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, number >::result_type, number>::value) - { - b += a; - return static_cast&&>(b); - } - else - { - return detail::expression, number >(a, b); - } + b += a; + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, number >::result_type, number>::value, + typename detail::expression, number >::result_type>::type +operator+(const detail::expression& a, number&& b) +{ + return detail::expression, number >(a, b); } template @@ -221,18 +227,21 @@ operator+(const number& a, const detail::expression -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression::left_type, typename detail::expression::right_type, number >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same::left_type, typename detail::expression::right_type, number >::result_type, number>::value, + typename detail::expression::left_type, typename detail::expression::right_type, number >::result_type>::type operator+(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same::left_type, typename detail::expression::right_type, number >::result_type, number>::value) - { - a += b; - return static_cast&&>(a); - } - else - { - return detail::expression::left_type, typename detail::expression::right_type, number >(b.left(), b.right(), a); - } + a += b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same::left_type, typename detail::expression::right_type, number >::result_type, number>::value, + typename detail::expression::left_type, typename detail::expression::right_type, number >::result_type>::type +operator+(number&& a, const detail::expression& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, number >(b.left(), b.right(), a); } template @@ -243,18 +252,21 @@ operator+(const detail::expression -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression::left_type, typename detail::expression::right_type, number >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same::left_type, typename detail::expression::right_type, number >::result_type, number>::value, + typename detail::expression::left_type, typename detail::expression::right_type, number >::result_type>::type operator+(const detail::expression& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same::left_type, typename detail::expression::right_type, number >::result_type, number>::value) - { - b += a; - return static_cast&&>(b); - } - else - { - return detail::expression::left_type, typename detail::expression::right_type, number >(a.left(), a.right(), b); - } + b += a; + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same::left_type, typename detail::expression::right_type, number >::result_type, number>::value, + typename detail::expression::left_type, typename detail::expression::right_type, number >::result_type>::type +operator+(const detail::expression& a, number&& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, number >(a.left(), a.right(), b); } // @@ -282,18 +294,21 @@ operator-(const number& a, const detail::expression -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression::left_type, typename detail::expression::right_type, number > >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same::left_type, typename detail::expression::right_type, number > >::result_type, number>::value, + typename detail::expression::left_type, typename detail::expression::right_type, number > >::result_type>::type operator-(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same::left_type, typename detail::expression::right_type, number > >::result_type, number>::value) - { - a -= b; - return static_cast&&>(a); - } - else - { - return detail::expression::left_type, typename detail::expression::right_type, number > >(detail::expression::left_type, typename detail::expression::right_type, number >(b.left(), b.right(), a)); - } + a -= b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same::left_type, typename detail::expression::right_type, number > >::result_type, number>::value, + typename detail::expression::left_type, typename detail::expression::right_type, number > >::result_type>::type +operator-(number&& a, const detail::expression& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, number > >(detail::expression::left_type, typename detail::expression::right_type, number >(b.left(), b.right(), a)); } template @@ -321,18 +336,21 @@ operator+(const number& a, const detail::expression -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, Arg1>::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, Arg1>::result_type, number>::value, + typename detail::expression, Arg1>::result_type>::type operator+(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, Arg1>::result_type, number>::value) - { - a -= b.left_ref(); - return static_cast&&>(a); - } - else - { - return detail::expression, Arg1>(a, b.left_ref()); - } + a -= b.left_ref(); + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, Arg1>::result_type, number>::value, + typename detail::expression, Arg1>::result_type>::type +operator+(number&& a, const detail::expression& b) +{ + return detail::expression, Arg1>(a, b.left_ref()); } template @@ -343,18 +361,21 @@ operator+(const detail::expression& a, c } template -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, Arg1>::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, Arg1>::result_type, number>::value, + typename detail::expression, Arg1>::result_type>::type operator+(const detail::expression& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, Arg1>::result_type, number>::value) - { - b -= a.left_ref(); - return static_cast&&>(b); - } - else - { - return detail::expression, Arg1>(b, a.left_ref()); - } + b -= a.left_ref(); + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, Arg1>::result_type, number>::value, + typename detail::expression, Arg1>::result_type>::type +operator+(const detail::expression& a, number&& b) +{ + return detail::expression, Arg1>(b, a.left_ref()); } template @@ -506,18 +527,21 @@ operator-(const number& a, const detail::expression -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, detail::expression >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, detail::expression >::result_type, number>::value, + typename detail::expression, detail::expression >::result_type>::type operator-(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, detail::expression >::result_type, number>::value) - { - a -= b; - return static_cast&&>(a); - } - else - { - return detail::expression, detail::expression >(a, b); - } + a -= b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, detail::expression >::result_type, number>::value, + typename detail::expression, detail::expression >::result_type>::type +operator-(number&& a, const detail::expression& b) +{ + return detail::expression, detail::expression >(a, b); } template @@ -528,19 +552,22 @@ operator-(const detail::expression& a, const number } template -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, number >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, number >::result_type, number>::value, + typename detail::expression, number >::result_type>::type operator-(const detail::expression& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, number >::result_type, number>::value) - { - b -= a; - b.backend().negate(); - return static_cast&&>(b); - } - else - { - return detail::expression, number >(a, b); - } + b -= a; + b.backend().negate(); + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, number >::result_type, number>::value, + typename detail::expression, number >::result_type>::type +operator-(const detail::expression& a, number&& b) +{ + return detail::expression, number >(a, b); } template @@ -572,16 +599,21 @@ operator-(const number& a, const detail::expression -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, Arg1>::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, Arg1>::result_type, number>::value, + typename detail::expression, Arg1>::result_type>::type operator-(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, Arg1>::result_type, number>::value) - { - a += b.left_ref(); - return static_cast&&>(a); - } - else - return detail::expression, Arg1>(a, b.left_ref()); + a += b.left_ref(); + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, Arg1>::result_type, number>::value, + typename detail::expression, Arg1>::result_type>::type +operator-(number&& a, const detail::expression& b) +{ + return detail::expression, Arg1>(a, b.left_ref()); } template @@ -593,17 +625,22 @@ operator-(const detail::expression& a, c } template -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, Arg1> >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, Arg1> >::result_type, number>::value, + typename detail::expression, Arg1> >::result_type>::type operator-(const detail::expression& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, Arg1> >::result_type, number>::value) - { - b += a.left_ref(); - b.backend().negate(); - return static_cast&&>(b); - } - else - return detail::expression, Arg1> >(detail::expression, Arg1>(b, a.left_ref())); + b += a.left_ref(); + b.backend().negate(); + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, Arg1> >::result_type, number>::value, + typename detail::expression, Arg1> >::result_type>::type +operator-(const detail::expression& a, number&& b) +{ + return detail::expression, Arg1> >(detail::expression, Arg1>(b, a.left_ref())); } template @@ -631,18 +668,23 @@ operator-(const detail::expression >& a, const } template -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, number > >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, number > >::result_type, number>::value, + typename detail::expression, number > >::result_type>::type operator-(const detail::expression >& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, number > >::result_type, number>::value) - { - using default_ops::eval_add; - eval_add(b.backend(), a.left_ref().backend()); - b.backend().negate(); - return static_cast&&>(b); - } - else - return detail::expression, number > >( + using default_ops::eval_add; + eval_add(b.backend(), a.left_ref().backend()); + b.backend().negate(); + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, number > >::result_type, number>::value, + typename detail::expression, number > >::result_type>::type +operator-(const detail::expression >& a, number&& b) +{ + return detail::expression, number > >( detail::expression, number >(b, a.left_ref())); } @@ -761,16 +803,21 @@ operator*(const number& a, const detail::expression -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, detail::expression >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, detail::expression >::result_type, number>::value, + typename detail::expression, detail::expression >::result_type>::type operator*(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, detail::expression >::result_type, number>::value) - { - a *= b; - return static_cast&&>(a); - } - else - return detail::expression, detail::expression >(a, b); + a *= b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, detail::expression >::result_type, number>::value, + typename detail::expression, detail::expression >::result_type>::type +operator*(number&& a, const detail::expression& b) +{ + return detail::expression, detail::expression >(a, b); } template @@ -781,16 +828,21 @@ operator*(const detail::expression& a, const number } template -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, number >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, number >::result_type, number>::value, + typename detail::expression, number >::result_type>::type operator*(const detail::expression& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, number >::result_type, number>::value) - { - b *= a; - return static_cast&&>(b); - } - else - return detail::expression, number >(a, b); + b *= a; + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, number >::result_type, number>::value, + typename detail::expression, number >::result_type>::type +operator*(const detail::expression& a, number&& b) +{ + return detail::expression, number >(a, b); } template @@ -855,17 +907,22 @@ operator*(const number& a, const detail::expression -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, number > >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, number > >::result_type, number>::value, + typename detail::expression, number > >::result_type>::type operator*(number&& a, const detail::expression >& b) { - BOOST_IF_CONSTEXPR(std::is_same, number > >::result_type, number>::value) - { - a *= b.left_ref(); - a.backend().negate(); - return static_cast&&>(a); - } - else - return detail::expression, number > >( + a *= b.left_ref(); + a.backend().negate(); + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, number > >::result_type, number>::value, + typename detail::expression, number > >::result_type>::type +operator*(number&& a, const detail::expression >& b) +{ + return detail::expression, number > >( detail::expression, number >(a, b.left_ref())); } @@ -878,17 +935,22 @@ operator*(const detail::expression >& a, const } template -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, number > >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, number > >::result_type, number>::value, + typename detail::expression, number > >::result_type>::type operator*(const detail::expression >& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, number > >::result_type, number>::value) - { - b *= a.left_ref(); - b.backend().negate(); - return static_cast&&>(b); - } - else - return detail::expression, number > >( + b *= a.left_ref(); + b.backend().negate(); + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, number > >::result_type, number>::value, + typename detail::expression, number > >::result_type>::type +operator*(const detail::expression >& a, number&& b) +{ + return detail::expression, number > >( detail::expression, number >(b, a.left_ref())); } @@ -1002,16 +1064,21 @@ operator/(const number& a, const detail::expression, detail::expression >(a, b); } template -inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression, detail::expression >::result_type +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, detail::expression >::result_type, number>::value, + typename detail::expression, detail::expression >::result_type>::type operator/(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, detail::expression >::result_type, number>::value) - { - a /= b; - return static_cast&&>(a); - } - else - return detail::expression, detail::expression >(a, b); + a /= b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, detail::expression >::result_type, number>::value, + typename detail::expression, detail::expression >::result_type>::type +operator/(number&& a, const detail::expression& b) +{ + return detail::expression, detail::expression >(a, b); } template inline BOOST_MP_CXX14_CONSTEXPR detail::expression, number > @@ -1054,17 +1121,22 @@ operator/(const number& a, const detail::expression, Arg1>(a, b.left_ref())); } template -inline typename detail::expression, Arg1> >::result_type +inline typename std::enable_if< + std::is_same, Arg1> >::result_type, number>::value, + typename detail::expression, Arg1> >::result_type>::type operator/(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, Arg1> >::result_type, number>::value) - { - a /= b.left_ref(); - a.backend().negate(); - return static_cast&&>(a); - } - else - return detail::expression, Arg1> >( + a /= b.left_ref(); + a.backend().negate(); + return static_cast&&>(a); +} +template +inline typename std::enable_if< + !std::is_same, Arg1> >::result_type, number>::value, + typename detail::expression, Arg1> >::result_type>::type +operator/(number&& a, const detail::expression& b) +{ + return detail::expression, Arg1> >( detail::expression, Arg1>(a, b.left_ref())); } template @@ -1225,17 +1297,23 @@ operator%(const number& a, const detail::expression, detail::expression >(a, b); } template -inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, detail::expression >::result_type, number>::value + && number_category::value == number_kind_integer, typename detail::expression, detail::expression >::result_type >::type operator%(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, detail::expression >::result_type, number>::value) - { - a %= b; - return static_cast&&>(a); - } - else - return detail::expression, detail::expression >(a, b); + a %= b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, detail::expression >::result_type, number>::value + && number_category::value == number_kind_integer, + typename detail::expression, detail::expression >::result_type >::type +operator%(number&& a, const detail::expression& b) +{ + return detail::expression, detail::expression >(a, b); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, @@ -1399,17 +1477,23 @@ operator&(const number& a, const detail::expression, detail::expression >(a, b); } template -inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, detail::expression >::result_type, number>::value + && number_category::value == number_kind_integer, typename detail::expression, detail::expression >::result_type >::type operator&(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, detail::expression >::result_type, number>::value) - { - a &= b; - return static_cast&&>(a); - } - else - return detail::expression, detail::expression >(a, b); + a &= b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, detail::expression >::result_type, number>::value + && number_category::value == number_kind_integer, + typename detail::expression, detail::expression >::result_type >::type +operator&(number&& a, const detail::expression& b) +{ + return detail::expression, detail::expression >(a, b); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, @@ -1419,17 +1503,23 @@ operator&(const detail::expression& a, const number return detail::expression, number >(a, b); } template -inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, number >::result_type, number>::value + && number_category::value == number_kind_integer, typename detail::expression, number >::result_type >::type operator&(const detail::expression& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, number >::result_type, number>::value) - { - b &= a; - return static_cast&&>(b); - } - else - return detail::expression, number >(a, b); + b &= a; + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, number >::result_type, number>::value + && number_category::value == number_kind_integer, + typename detail::expression, number >::result_type >::type +operator&(const detail::expression& a, number&& b) +{ + return detail::expression, number >(a, b); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value == number_kind_integer, @@ -1529,17 +1619,23 @@ operator|(const number& a, const detail::expression, detail::expression >(a, b); } template -inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, detail::expression >::result_type, number>::value + && number_category::value == number_kind_integer, typename detail::expression, detail::expression >::result_type>::type operator|(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, detail::expression >::result_type, number>::value) - { - a |= b; - return static_cast&&>(a); - } - else - return detail::expression, detail::expression >(a, b); + a |= b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, detail::expression >::result_type, number>::value + && number_category::value == number_kind_integer, + typename detail::expression, detail::expression >::result_type>::type +operator|(number&& a, const detail::expression& b) +{ + return detail::expression, detail::expression >(a, b); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, @@ -1549,17 +1645,23 @@ operator|(const detail::expression& a, const number return detail::expression, number >(a, b); } template -inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, number >::result_type, number>::value + && number_category::value == number_kind_integer, typename detail::expression, number >::result_type>::type operator|(const detail::expression& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, number >::result_type, number>::value) - { - b |= a; - return static_cast&&>(b); - } - else - return detail::expression, number >(a, b); + b |= a; + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, number >::result_type, number>::value + && number_category::value == number_kind_integer, + typename detail::expression, number >::result_type>::type +operator|(const detail::expression& a, number&& b) +{ + return detail::expression, number >(a, b); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value == number_kind_integer, @@ -1659,17 +1761,23 @@ operator^(const number& a, const detail::expression, detail::expression >(a, b); } template -inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, detail::expression >::result_type, number>::value + && number_category::value == number_kind_integer, typename detail::expression, detail::expression >::result_type>::type operator^(number&& a, const detail::expression& b) { - BOOST_IF_CONSTEXPR(std::is_same, detail::expression >::result_type, number>::value) - { - a ^= b; - return static_cast&&>(a); - } - else - return detail::expression, detail::expression >(a, b); + a ^= b; + return static_cast&&>(a); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, detail::expression >::result_type, number>::value + && number_category::value == number_kind_integer, + typename detail::expression, detail::expression >::result_type>::type +operator^(number&& a, const detail::expression& b) +{ + return detail::expression, detail::expression >(a, b); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, @@ -1679,17 +1787,23 @@ operator^(const detail::expression& a, const number return detail::expression, number >(a, b); } template -inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::value == number_kind_integer, +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + std::is_same, number >::result_type, number>::value + && number_category::value == number_kind_integer, typename detail::expression, number >::result_type>::type operator^(const detail::expression& a, number&& b) { - BOOST_IF_CONSTEXPR(std::is_same, number >::result_type, number>::value) - { - b ^= a; - return static_cast&&>(b); - } - else - return detail::expression, number >(a, b); + b ^= a; + return static_cast&&>(b); +} +template +inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< + !std::is_same, number >::result_type, number>::value + && number_category::value == number_kind_integer, + typename detail::expression, number >::result_type>::type +operator^(const detail::expression& a, number&& b) +{ + return detail::expression, number >(a, b); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if::result_type>::value == number_kind_integer, diff --git a/include/boost/multiprecision/gmp.hpp b/include/boost/multiprecision/gmp.hpp index 39c97a1f..603ed09b 100644 --- a/include/boost/multiprecision/gmp.hpp +++ b/include/boost/multiprecision/gmp.hpp @@ -2227,6 +2227,20 @@ struct gmp_rational mpz_init_set(&m_data[0]._mp_den, b.data()); mpq_canonicalize(m_data); } + gmp_rational(const gmp_int& a, gmp_int&& b) + { + mpz_init_set(&m_data[0]._mp_num, a.data()); + m_data[0]._mp_den = b.data()[0]; + mpq_canonicalize(m_data); + b.data()[0]._mp_d = nullptr; + } + gmp_rational(gmp_int&& a, const gmp_int& b) + { + m_data[0]._mp_num = a.data()[0]; + mpz_init_set(&m_data[0]._mp_den, b.data()); + mpq_canonicalize(m_data); + a.data()[0]._mp_d = nullptr; + } gmp_rational(gmp_int&& a, gmp_int&& b) { m_data[0]._mp_num = a.data()[0]; @@ -2531,6 +2545,174 @@ inline void eval_divide(gmp_rational& t, const gmp_rational& p, const gmp_ration BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); mpq_div(t.data(), p.data(), o.data()); } +// +// operator with scalars: +// +inline void eval_add(gmp_rational& result, gmp_rational const& a, gmp_int const& b) +{ + // we allow result and a to be the same object here: + if (&a != &result) + { + mpz_set(mpq_numref(result.data()), mpq_numref(a.data())); + mpz_set(mpq_denref(result.data()), mpq_denref(a.data())); + } + mpz_addmul(mpq_numref(result.data()), mpq_denref(a.data()), b.data()); + // no need to normalize, there can be no common divisor as long as a is already normalized. +} +inline void eval_add(gmp_rational& result, gmp_rational const& a, unsigned long b) +{ + // we allow result and a to be the same object here: + if (&a != &result) + { + mpz_set(mpq_numref(result.data()), mpq_numref(a.data())); + mpz_set(mpq_denref(result.data()), mpq_denref(a.data())); + } + mpz_addmul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b); + // no need to normalize, there can be no common divisor as long as a is already normalized. +} +inline void eval_add(gmp_rational& result, gmp_rational const& a, long b) +{ + // we allow result and a to be the same object here: + if (&a != &result) + { + mpz_set(mpq_numref(result.data()), mpq_numref(a.data())); + mpz_set(mpq_denref(result.data()), mpq_denref(a.data())); + } + if(b > 0) + mpz_addmul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b); + else + mpz_submul_ui(mpq_numref(result.data()), mpq_denref(a.data()), boost::multiprecision::detail::unsigned_abs(b)); + // no need to normalize, there can be no common divisor as long as a is already normalized. +} +template +inline void eval_add(gmp_rational& result, gmp_rational const& a, const T& b) +{ + gmp_int t; + t = b; + eval_add(result, a, t); +} +template +inline void eval_add(gmp_rational& result, const T& b, gmp_rational const& a) +{ + eval_add(result, a, b); +} +template +inline void eval_add(gmp_rational& result, const T& b) +{ + eval_add(result, result, b); +} +inline void eval_subtract(gmp_rational& result, gmp_rational const& a, gmp_int const& b) +{ + // we allow result and a to be the same object here: + if (&a != &result) + { + mpz_set(mpq_numref(result.data()), mpq_numref(a.data())); + mpz_set(mpq_denref(result.data()), mpq_denref(a.data())); + } + mpz_submul(mpq_numref(result.data()), mpq_denref(a.data()), b.data()); + // no need to normalize, there can be no common divisor as long as a is already normalized. +} +inline void eval_subtract(gmp_rational& result, gmp_rational const& a, unsigned long b) +{ + // we allow result and a to be the same object here: + if (&a != &result) + { + mpz_set(mpq_numref(result.data()), mpq_numref(a.data())); + mpz_set(mpq_denref(result.data()), mpq_denref(a.data())); + } + mpz_submul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b); + // no need to normalize, there can be no common divisor as long as a is already normalized. +} +inline void eval_subtract(gmp_rational& result, gmp_rational const& a, long b) +{ + // we allow result and a to be the same object here: + if (&a != &result) + { + mpz_set(mpq_numref(result.data()), mpq_numref(a.data())); + mpz_set(mpq_denref(result.data()), mpq_denref(a.data())); + } + if(b > 0) + mpz_submul_ui(mpq_numref(result.data()), mpq_denref(a.data()), b); + else + mpz_addmul_ui(mpq_numref(result.data()), mpq_denref(a.data()), boost::multiprecision::detail::unsigned_abs(b)); + // no need to normalize, there can be no common divisor as long as a is already normalized. +} +template +inline void eval_subtract(gmp_rational& result, gmp_rational const& a, const T& b) +{ + gmp_int t; + t = b; + eval_subtract(result, a, t); +} +template +inline void eval_subtract(gmp_rational& result, const T& b, gmp_rational const& a) +{ + eval_subtract(result, a, b); + result.negate(); +} +template +inline void eval_subtract(gmp_rational& result, const T& b) +{ + eval_subtract(result, result, b); +} + +inline void eval_multiply(gmp_rational& result, gmp_rational const& a, gmp_int const& b) +{ + gmp_int g, t; + mpz_gcd(g.data(), mpq_denref(a.data()), b.data()); + if (!mpz_fits_uint_p(g.data()) || (mpz_get_ui(g.data()) != 1)) + { + eval_divide(t, b, g); + mpz_mul(mpq_numref(result.data()), t.data(), mpq_numref(a.data())); + mpz_div(mpq_denref(result.data()), mpq_denref(a.data()), g.data()); + } + else + { + mpz_mul(mpq_numref(result.data()), mpq_numref(a.data()), b.data()); + if (&result != &a) + mpz_set(mpq_denref(result.data()), mpq_denref(a.data())); + } +} +inline void eval_multiply(gmp_rational& result, gmp_rational const& a, unsigned long b) +{ + gmp_int g; + mpz_gcd_ui(g.data(), mpq_denref(a.data()), b); + if (!mpz_fits_uint_p(g.data()) || (mpz_get_ui(g.data()) != 1)) + { + b /= mpz_get_ui(g.data()); + mpz_mul_ui(mpq_numref(result.data()), mpq_numref(a.data()), b); + mpz_div(mpq_denref(result.data()), mpq_denref(a.data()), g.data()); + } + else + { + mpz_mul_ui(mpq_numref(result.data()), mpq_numref(a.data()), b); + if (&result != &a) + mpz_set(mpq_denref(result.data()), mpq_denref(a.data())); + } +} +inline void eval_multiply(gmp_rational& result, gmp_rational const& a, long b) +{ + eval_multiply(result, a, boost::multiprecision::detail::unsigned_abs(b)); + if (b < 0) + result.negate(); +} +template +inline void eval_multiply(gmp_rational& result, gmp_rational const& a, const T& b) +{ + gmp_int t; + t = b; + eval_multiply(result, a, t); +} +template +inline void eval_multiply(gmp_rational& result, const T& b, gmp_rational const& a) +{ + eval_multiply(result, a, b); +} +template +inline void eval_multiply(gmp_rational& result, const T& b) +{ + eval_multiply(result, result, b); +} inline int eval_get_sign(const gmp_rational& val) { diff --git a/include/boost/multiprecision/logged_adaptor.hpp b/include/boost/multiprecision/logged_adaptor.hpp index 628f6a19..6d7eb4e4 100644 --- a/include/boost/multiprecision/logged_adaptor.hpp +++ b/include/boost/multiprecision/logged_adaptor.hpp @@ -100,13 +100,15 @@ struct logged_adaptor { log_postfix_event(m_value, "construct from a pair of arithmetic types"); } - logged_adaptor(const Backend& i, unsigned digits10) + template + logged_adaptor(const Backend& i, unsigned digits10, typename std::enable_if::value>::type const* = nullptr) : m_value(i, digits10) { log_postfix_event(m_value, "construct from arithmetic type and precision"); } - logged_adaptor(const logged_adaptor& i, unsigned digits10) - : m_value(i, digits10) + template + logged_adaptor(const logged_adaptor& i, unsigned digits10, typename std::enable_if::value>::type const* = nullptr) + : m_value(i.value(), digits10) { log_postfix_event(m_value, "construct from arithmetic type and precision"); } diff --git a/include/boost/multiprecision/number.hpp b/include/boost/multiprecision/number.hpp index 38cf288e..c6a238bb 100644 --- a/include/boost/multiprecision/number.hpp +++ b/include/boost/multiprecision/number.hpp @@ -158,7 +158,7 @@ class number (std::is_convertible::value && std::is_convertible::value && !std::is_same::value - && std::is_constructible()))>::type const&, typename detail::canonical()))>::type const&>::value + && std::is_constructible()))>::type>::type, Backend>::type const&, typename detail::canonical()))>::type>::type, Backend>::type const&>::value && !boost::multiprecision::detail::is_variable_precision::value)>::type* = 0) : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2))) { @@ -169,7 +169,7 @@ class number (std::is_convertible::value && std::is_convertible::value && !std::is_same::value - && std::is_constructible()))>::type const&, typename detail::canonical()))>::type const&>::value + && std::is_constructible()))>::type>::type, Backend>::type const&, typename detail::canonical()))>::type>::type, Backend>::type const&>::value && !boost::multiprecision::detail::is_variable_precision::value)>::type* = 0) : m_backend(canonical_value(detail::evaluate_if_expression(static_cast(v1))), canonical_value(detail::evaluate_if_expression(v2))) { @@ -180,7 +180,7 @@ class number (std::is_convertible::value && std::is_convertible::value && !std::is_same::value - && std::is_constructible()))>::type const&, typename detail::canonical()))>::type const&>::value + && std::is_constructible()))>::type>::type, Backend>::type const&, typename detail::canonical()))>::type>::type, Backend>::type const&>::value && !boost::multiprecision::detail::is_variable_precision::value)>::type* = 0) : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(static_cast(v2)))) { @@ -191,7 +191,7 @@ class number (std::is_convertible::value && std::is_convertible::value && !std::is_same::value - && std::is_constructible()))>::type const&, typename detail::canonical()))>::type const&>::value + && std::is_constructible()))>::type>::type, Backend>::type const&, typename detail::canonical()))>::type>::type, Backend>::type const&>::value && !boost::multiprecision::detail::is_variable_precision::value)>::type* = 0) : m_backend(canonical_value(detail::evaluate_if_expression(static_cast(v1))), canonical_value(detail::evaluate_if_expression(static_cast(v2)))) { @@ -202,7 +202,7 @@ class number (std::is_convertible::value && std::is_convertible::value && !std::is_same::value - && (!std::is_constructible()))>::type const&, typename detail::canonical()))>::type const&>::value + && (!std::is_constructible()))>::type>::type, Backend>::type const&, typename detail::canonical()))>::type>::type, Backend>::type const&>::value || boost::multiprecision::detail::is_variable_precision::value))>::type* = 0) { using default_ops::assign_components; @@ -265,7 +265,12 @@ class number : m_backend(detail::evaluate_if_expression(v1), detail::evaluate_if_expression(v2), digits10) {} template - BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number& v1, const number& v2, typename std::enable_if::value>::type* = 0) + BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number( + const number& v1, + const number& v2, + typename std::enable_if< + std::is_convertible::value + && (!std::is_constructible&>()))>::type>::type, Backend>::type const&, typename detail::canonical&>()))>::type>::type, Backend>::type const&>::value || boost::multiprecision::detail::is_variable_precision::value) >::type* = 0) { using default_ops::assign_components; detail::scoped_default_precision > precision_guard(v1, v2); diff --git a/include/boost/multiprecision/rational_adaptor.hpp b/include/boost/multiprecision/rational_adaptor.hpp index 530f9d85..b83bdce0 100644 --- a/include/boost/multiprecision/rational_adaptor.hpp +++ b/include/boost/multiprecision/rational_adaptor.hpp @@ -54,6 +54,23 @@ struct rational_adaptor return result; } + void normalize() + { + using default_ops::eval_gcd; + using default_ops::eval_eq; + using default_ops::eval_divide; + + Backend g, t; + eval_gcd(g, m_num, m_denom); + if (!eval_eq(g, one())) + { + eval_divide(t, m_num, g); + m_num.swap(t); + eval_divide(t, m_denom, g); + m_denom = std::move(t); + } + } + // We must have a default constructor: rational_adaptor() : m_num(one()), m_denom(one()) {} @@ -70,6 +87,33 @@ struct rational_adaptor rational_adaptor(const Arithmetic& val, typename std::enable_if::value && !std::is_floating_point::value>::type const* = nullptr) : m_num(val), m_denom(one()) {} + // + // Pass-through 2-arg construction of components: + // + template + rational_adaptor(const T& a, const U& b, typename std::enable_if::value && std::is_constructible::value>::type const* = nullptr) + : m_num(a), m_denom(b) + { + normalize(); + } + template + rational_adaptor(T&& a, const U& b, typename std::enable_if::value && std::is_constructible::value>::type const* = nullptr) + : m_num(static_cast(a)), m_denom(b) + { + normalize(); + } + template + rational_adaptor(T&& a, U&& b, typename std::enable_if::value && std::is_constructible::value>::type const* = nullptr) + : m_num(static_cast(a)), m_denom(static_cast(b)) + { + normalize(); + } + template + rational_adaptor(const T& a, U&& b, typename std::enable_if::value && std::is_constructible::value>::type const* = nullptr) + : m_num(a), m_denom(static_cast(b)) + { + normalize(); + } // // In the absense of converting constructors, operator= takes the strain. // In addition to the usual suspects, there must be one operator= for each type @@ -290,26 +334,20 @@ is_minus_one(const T& val) // Required non-members: // template -void eval_add(rational_adaptor& a, const rational_adaptor& b) +inline void eval_add(rational_adaptor& a, const rational_adaptor& b) { - rational_adaptor t; - eval_add(t, a, b); - a = std::move(t); + eval_add_subtract_imp(a, a, b, true); } template -void eval_subtract(rational_adaptor& a, const rational_adaptor& b) +inline void eval_subtract(rational_adaptor& a, const rational_adaptor& b) { - rational_adaptor t; - eval_subtract(t, a, b); - a = std::move(t); + eval_add_subtract_imp(a, a, b, false); } template -void eval_multiply(rational_adaptor& a, const rational_adaptor& b) +inline void eval_multiply(rational_adaptor& a, const rational_adaptor& b) { - rational_adaptor t; - eval_multiply(t, a, b); - a = std::move(t); + eval_multiply_imp(a, a, b.num(), b.denom()); } template diff --git a/performance/rational_bernoulli_allocations.cpp b/performance/rational_bernoulli_allocations.cpp new file mode 100644 index 00000000..f17e9bee --- /dev/null +++ b/performance/rational_bernoulli_allocations.cpp @@ -0,0 +1,139 @@ +// Copyright 2020 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +#include + +template +inline Integer factorial(unsigned n) +{ + Integer result = 1; + for (unsigned k = 1; k <= n; ++k) + result *= k; + return result; +} + +template +inline Rational binomial(unsigned n, unsigned k) +{ + return Rational(factorial(n), factorial(k) * factorial(n - k)); +} + +inline mpz_class pow(mpz_class i, unsigned p) +{ + mpz_class result; + mpz_pow_ui(result.get_mpz_t(), i.get_mpz_t(), p); + return result; +} + +template +Rational Bernoulli(unsigned m) +{ + Rational result = 0; + + for (unsigned k = 0; k <= m; ++k) + { + Rational inner = 0; + for (unsigned v = 0; v <= k; ++v) + { + Rational term = binomial(k, v) * Rational(pow(Integer(v), m), k + 1); + if (v & 1) + term = -term; + inner += term; + } + result += inner; + } + return result; +} + +template +static void BM_bernoulli(benchmark::State& state) +{ + int m = state.range(0); + for (auto _ : state) + { + benchmark::DoNotOptimize(Bernoulli(m)); + } +} + +unsigned allocation_count = 0; + +void* (*alloc_func_ptr)(size_t); +void* (*realloc_func_ptr)(void*, size_t, size_t); +void (*free_func_ptr)(void*, size_t); + +void* alloc_func(size_t n) +{ + ++allocation_count; + return (*alloc_func_ptr)(n); +} + +void free_func(void* p, size_t n) +{ + (*free_func_ptr)(p, n); +} + +void* realloc_func(void* p, size_t old, size_t n) +{ + ++allocation_count; + return (*realloc_func_ptr)(p, old, n); +} + +unsigned new_count = 0; + +void* operator new(std::size_t n) throw(std::bad_alloc) +{ + ++new_count; + return std::malloc(n); +} +void operator delete(void* p) throw() +{ + std::free(p); +} + +void* operator new[](std::size_t n) throw(std::bad_alloc) +{ + ++new_count; + return std::malloc(n); +} +void operator delete[](void* p) throw() +{ + std::free(p); +} + + +int main() +{ + using namespace boost::multiprecision; + + mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr); + mp_set_memory_functions(&alloc_func, &realloc_func, &free_func); + + std::cout << "[table Total Allocation Counts for Bernoulli Number Calculation\n" + "[[m][cpp_rational][mpq_rational][number>][mpq_class]]\n"; + + for (unsigned m = 2; m < 200; m += 2) + { + std::cout << "[[" << m << "]["; + new_count = 0; + Bernoulli(m); + std::cout << new_count << "]["; + allocation_count = 0; + Bernoulli(m); + std::cout << allocation_count << "]["; + allocation_count = 0; + Bernoulli>>(m); + std::cout << allocation_count << "]["; + allocation_count = 0; + Bernoulli(m); + std::cout << allocation_count << "]]\n"; + } + + std::cout << "]\n"; + return 0; +} diff --git a/performance/rational_bernoulli_bench.cpp b/performance/rational_bernoulli_bench.cpp index a96bf8c9..d00618e8 100644 --- a/performance/rational_bernoulli_bench.cpp +++ b/performance/rational_bernoulli_bench.cpp @@ -62,9 +62,9 @@ static void BM_bernoulli(benchmark::State& state) } -BENCHMARK_TEMPLATE(BM_bernoulli, boost::multiprecision::cpp_rational)->DenseRange(10, 100, 2); -BENCHMARK_TEMPLATE(BM_bernoulli, boost::multiprecision::mpq_rational)->DenseRange(10, 100, 2); -BENCHMARK_TEMPLATE(BM_bernoulli, boost::multiprecision::number>)->DenseRange(10, 100, 2); -BENCHMARK_TEMPLATE(BM_bernoulli, mpq_class, mpz_class)->DenseRange(10, 100, 2); +BENCHMARK_TEMPLATE(BM_bernoulli, boost::multiprecision::cpp_rational)->DenseRange(50, 200, 4); +BENCHMARK_TEMPLATE(BM_bernoulli, boost::multiprecision::mpq_rational)->DenseRange(50, 200, 4); +BENCHMARK_TEMPLATE(BM_bernoulli, boost::multiprecision::number >)->DenseRange(50, 200, 4); +BENCHMARK_TEMPLATE(BM_bernoulli, mpq_class, mpz_class)->DenseRange(50, 200, 4); BENCHMARK_MAIN();