Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:58:17

0001 ///////////////////////////////////////////////////////////////////////////////
0002 //  Copyright 2011 John Maddock. Distributed under the Boost
0003 //  Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_MP_NUMBER_HPP
0007 #define BOOST_MP_NUMBER_HPP
0008 
0009 #include <cstdint>
0010 #include <boost/multiprecision/detail/standalone_config.hpp>
0011 #include <boost/multiprecision/detail/precision.hpp>
0012 #include <boost/multiprecision/detail/generic_interconvert.hpp>
0013 #include <boost/multiprecision/detail/number_compare.hpp>
0014 #include <boost/multiprecision/traits/is_restricted_conversion.hpp>
0015 #include <boost/multiprecision/traits/is_complex.hpp>
0016 #include <boost/multiprecision/traits/is_convertible_arithmetic.hpp>
0017 #include <boost/multiprecision/detail/hash.hpp>
0018 #include <boost/multiprecision/detail/number_base.hpp>
0019 #include <istream> // stream operators
0020 #include <cstdio>  // EOF
0021 #include <cctype>  // isspace
0022 #include <functional>  // std::hash
0023 #include <type_traits>
0024 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
0025 #include <string_view>
0026 #endif
0027 
0028 #ifndef BOOST_MP_STANDALONE
0029 #include <boost/core/nvp.hpp>
0030 #endif
0031 
0032 namespace boost {
0033 namespace multiprecision {
0034 
0035 #ifdef BOOST_MSVC
0036 // warning C4127: conditional expression is constant
0037 // warning C4714: function marked as __forceinline not inlined
0038 #pragma warning(push)
0039 #pragma warning(disable : 4127 4714 6326)
0040 #endif
0041 
0042 template <class Backend, expression_template_option ExpressionTemplates>
0043 class number
0044 {
0045    using self_type = number<Backend, ExpressionTemplates>;
0046 
0047  public:
0048    using backend_type = Backend                                 ;
0049    using value_type = typename component_type<self_type>::type;
0050 
0051    static constexpr expression_template_option et = ExpressionTemplates;
0052 
0053    BOOST_MP_FORCEINLINE constexpr number() noexcept(noexcept(Backend())) {}
0054    BOOST_MP_FORCEINLINE constexpr number(const number& e) noexcept(noexcept(Backend(std::declval<Backend const&>()))) = default;
0055    template <class V>
0056    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v, 
0057       typename std::enable_if<
0058       (boost::multiprecision::detail::is_convertible_arithmetic<V, Backend>::value 
0059             || std::is_same<std::string, V>::value 
0060             || std::is_convertible<V, const char*>::value) 
0061       && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value 
0062       && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
0063    {
0064       m_backend = canonical_value(v);
0065    }
0066    template <class V>
0067    BOOST_MP_FORCEINLINE constexpr number(const V& v, typename std::enable_if<
0068                                                          std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
0069 #ifndef BOOST_INTEL
0070        noexcept(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
0071 #endif
0072        : m_backend(canonical_value(v))
0073    {}
0074    template <class V, class U>
0075    BOOST_MP_FORCEINLINE constexpr number(const V& v, U digits10, 
0076       typename std::enable_if<
0077       (boost::multiprecision::detail::is_convertible_arithmetic<V, Backend>::value 
0078          || std::is_same<std::string, V>::value 
0079          || std::is_convertible<V, const char*>::value) 
0080       && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value 
0081       && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_complex) 
0082       && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_rational)
0083       && std::is_same<self_type, value_type>::value
0084       && std::is_integral<U>::value
0085       && (std::numeric_limits<U>::digits <= std::numeric_limits<unsigned>::digits)
0086       && std::is_constructible<Backend, typename detail::canonical<V, Backend>::type const&, unsigned>::value>::type* = nullptr)
0087        : m_backend(canonical_value(v), static_cast<unsigned>(digits10))
0088    {}
0089    //
0090    // Conversions from unscoped enum's are implicit:
0091    //
0092    template <class V>
0093    BOOST_MP_FORCEINLINE 
0094 #if !(defined(BOOST_MSVC) && (BOOST_MSVC <= 1900))
0095       constexpr 
0096 #endif
0097       number(const V& v, typename std::enable_if<
0098       std::is_enum<V>::value && std::is_convertible<V, int>::value && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
0099       : number(static_cast<typename std::underlying_type<V>::type>(v))
0100    {}
0101    //
0102    // Conversions from scoped enum's are explicit:
0103    //
0104    template <class V>
0105    BOOST_MP_FORCEINLINE explicit 
0106 #if !(defined(BOOST_MSVC) && (BOOST_MSVC <= 1900))
0107        constexpr
0108 #endif
0109        number(const V& v, typename std::enable_if<
0110       std::is_enum<V>::value && !std::is_convertible<V, int>::value && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
0111       : number(static_cast<typename std::underlying_type<V>::type>(v))
0112    {}
0113 
0114    template <class U>
0115    BOOST_MP_FORCEINLINE constexpr number(const number& e, U digits10, typename std::enable_if<std::is_constructible<Backend, const Backend&, unsigned>::value && std::is_integral<U>::value && (std::numeric_limits<U>::digits <= std::numeric_limits<unsigned>::digits)>::type* = nullptr)
0116        noexcept(noexcept(Backend(std::declval<Backend const&>(), std::declval<unsigned>())))
0117        : m_backend(e.m_backend, static_cast<unsigned>(digits10)) {}
0118    template <class V>
0119    explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v, typename std::enable_if<
0120                                                                                  (boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && !detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
0121        noexcept(noexcept(std::declval<Backend&>() = std::declval<typename detail::canonical<V, Backend>::type const&>()))
0122    {
0123       m_backend = canonical_value(v);
0124    }
0125    template <class V>
0126    explicit BOOST_MP_FORCEINLINE constexpr number(const V& v, typename std::enable_if<
0127                                                                   detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && (detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value || !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value)>::type* = nullptr)
0128        noexcept(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
0129        : m_backend(canonical_value(v)) {}
0130    template <class V>
0131    explicit BOOST_MP_FORCEINLINE constexpr number(const V& v, unsigned digits10, typename std::enable_if<(boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_complex) && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_rational)>::type* = nullptr)
0132        : m_backend(canonical_value(v), digits10) {}
0133 
0134    template <expression_template_option ET>
0135    BOOST_MP_FORCEINLINE constexpr number(const number<Backend, ET>& val)
0136        noexcept(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(val.backend()) {}
0137 
0138    template <class Other, expression_template_option ET>
0139    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val,
0140                                                         typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = nullptr)
0141        noexcept(noexcept(Backend(std::declval<Other const&>())))
0142        : m_backend(val.backend()) {}
0143 
0144    template <class Other, expression_template_option ET>
0145    explicit BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename std::enable_if<
0146                                                      (!detail::is_explicitly_convertible<Other, Backend>::value)>::type* = nullptr)
0147    {
0148       //
0149       // Attempt a generic interconvertion:
0150       //
0151       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard_1(val);
0152       detail::scoped_default_precision<number<Other, ET> >                    precision_guard_2(val);
0153       using detail::generic_interconvert;
0154       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0155       {
0156          if (precision_guard_1.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0157          {
0158             self_type t;
0159             generic_interconvert(t.backend(), val.backend(), number_category<Backend>(), number_category<Other>());
0160             *this = std::move(t);
0161             return;
0162          }
0163       }
0164       generic_interconvert(backend(), val.backend(), number_category<Backend>(), number_category<Other>());
0165    }
0166    template <class Other, expression_template_option ET>
0167    explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename std::enable_if<
0168                                                                                                    (detail::is_explicitly_convertible<Other, Backend>::value && (detail::is_restricted_conversion<Other, Backend>::value || !std::is_convertible<Other, Backend>::value))>::type* = nullptr) noexcept(noexcept(Backend(std::declval<Other const&>())))
0169        : m_backend(val.backend()) {}
0170 
0171    template <class V, class U>
0172    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
0173       typename std::enable_if<
0174          (std::is_convertible<V, value_type>::value
0175             && std::is_convertible<U, value_type>::value
0176             && !std::is_same<value_type, self_type>::value
0177             && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
0178             && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
0179       : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)))
0180    {
0181    }
0182    template <class V, class U>
0183    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(V&& v1, const U& v2,
0184       typename std::enable_if<
0185          (std::is_convertible<V, value_type>::value
0186             && std::is_convertible<U, value_type>::value
0187             && !std::is_same<value_type, self_type>::value
0188             && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
0189             && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
0190       : m_backend(canonical_value(detail::evaluate_if_expression(static_cast<V&&>(v1))), canonical_value(detail::evaluate_if_expression(v2)))
0191    {
0192    }
0193    template <class V, class U>
0194    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, U&& v2,
0195       typename std::enable_if<
0196       (std::is_convertible<V, value_type>::value
0197          && std::is_convertible<U, value_type>::value
0198          && !std::is_same<value_type, self_type>::value
0199          && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
0200          && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
0201       : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(static_cast<U&&>(v2))))
0202    {
0203    }
0204    template <class V, class U>
0205    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(V&& v1, U&& v2,
0206       typename std::enable_if<
0207       (std::is_convertible<V, value_type>::value
0208          && std::is_convertible<U, value_type>::value
0209          && !std::is_same<value_type, self_type>::value
0210          && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
0211          && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
0212       : m_backend(canonical_value(detail::evaluate_if_expression(static_cast<V&&>(v1))), canonical_value(detail::evaluate_if_expression(static_cast<U&&>(v2))))
0213    {
0214    }
0215    template <class V, class U>
0216    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
0217       typename std::enable_if<
0218          (std::is_convertible<V, value_type>::value 
0219             && std::is_convertible<U, value_type>::value 
0220             && !std::is_same<value_type, self_type>::value
0221             && (!std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
0222                || boost::multiprecision::detail::is_variable_precision<Backend>::value))>::type* = nullptr)
0223    {
0224       using default_ops::assign_components;
0225       // Copy precision options from this type to component_type:
0226       boost::multiprecision::detail::scoped_precision_options<value_type> scoped_opts(*this);
0227       // precision guards:
0228       detail::scoped_default_precision<self_type>  precision_guard(v1, v2, *this);
0229       detail::scoped_default_precision<value_type> component_precision_guard(v1, v2, *this);
0230       assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
0231    }
0232    template <class V, class U>
0233    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
0234                                         typename std::enable_if<
0235                                                                      (std::is_constructible<value_type, V>::value || std::is_convertible<V, std::string>::value) && (std::is_constructible<value_type, U>::value || std::is_convertible<U, std::string>::value) && !std::is_same<value_type, self_type>::value && !std::is_same<V, self_type>::value && !(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value)>::type* = nullptr)
0236    {
0237       using default_ops::assign_components;
0238       // Copy precision options from this type to component_type:
0239       boost::multiprecision::detail::scoped_precision_options<value_type> scoped_opts(*this);
0240       // precision guards:
0241       detail::scoped_default_precision<self_type>  precision_guard(v1, v2, *this);
0242       detail::scoped_default_precision<value_type> component_precision_guard(v1, v2, *this);
0243       assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
0244    }
0245 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
0246    //
0247    // Support for new types in C++17
0248    //
0249    template <class Traits>
0250    explicit inline BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& view)
0251    {
0252       using default_ops::assign_from_string_view;
0253       assign_from_string_view(this->backend(), view);
0254    }
0255    template <class Traits>
0256    explicit inline BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& view_x, const std::basic_string_view<char, Traits>& view_y)
0257    {
0258       using default_ops::assign_from_string_view;
0259       assign_from_string_view(this->backend(), view_x, view_y);
0260    }
0261    template <class Traits>
0262    explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& v, unsigned digits10)
0263        : m_backend(canonical_value(v), digits10) {}
0264    template <class Traits>
0265    BOOST_MP_CXX14_CONSTEXPR number& assign(const std::basic_string_view<char, Traits>& view)
0266    {
0267       using default_ops::assign_from_string_view;
0268       assign_from_string_view(this->backend(), view);
0269       return *this;
0270    }
0271 #endif
0272 
0273    template <class V, class U>
0274    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
0275                                                         typename std::enable_if<(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value && !std::is_same<value_type, self_type>::value)>::type* = nullptr)
0276        : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)), digits10)
0277    {}
0278    template <class V, class U>
0279    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
0280                                                                  typename std::enable_if<((std::is_constructible<value_type, V>::value || std::is_convertible<V, std::string>::value) && (std::is_constructible<value_type, U>::value || std::is_convertible<U, std::string>::value) && !std::is_same<value_type, self_type>::value) && !(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value)>::type* = nullptr)
0281        : m_backend(detail::evaluate_if_expression(v1), detail::evaluate_if_expression(v2), digits10) {}
0282 
0283    template <class Other, expression_template_option ET>
0284    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(
0285       const number<Other, ET>& v1, 
0286       const number<Other, ET>& v2, 
0287       typename std::enable_if<
0288          std::is_convertible<Other, Backend>::value 
0289          && (!std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const number<Other, ET>&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const number<Other, ET>&>()))>::type>::type, Backend>::type const&>::value || boost::multiprecision::detail::is_variable_precision<Backend>::value) >::type* = nullptr)
0290    {
0291       using default_ops::assign_components;
0292       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
0293       assign_components(m_backend, v1.backend(), v2.backend());
0294    }
0295 
0296    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0297    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0298    {
0299       using tag_type = std::integral_constant<bool, is_equivalent_number_type<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>;
0300       detail::scoped_default_precision<number<Backend, ExpressionTemplates> >                                       precision_guard(e);
0301       //
0302       // If the current precision of *this differs from that of expression e, then we
0303       // create a temporary (which will have the correct precision thanks to precision_guard)
0304       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0305       // which causes this code to be eliminated in the common case that this type is
0306       // not actually variable precision.  Pre C++17 this code should still be mostly
0307       // optimised away, but we can't prevent instantiation of the dead code leading
0308       // to longer build and possibly link times.
0309       //
0310       BOOST_IF_CONSTEXPR (std::is_same<self_type, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
0311       {
0312          BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0313             if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0314             {
0315                number t(e);
0316                return *this = std::move(t);
0317             }
0318       }
0319       do_assign(e, tag_type());
0320       return *this;
0321    }
0322    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0323    BOOST_MP_CXX14_CONSTEXPR number& assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0324    {
0325       using tag_type = std::integral_constant<bool, is_equivalent_number_type<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>;
0326 
0327       //
0328       // If the current precision of *this differs from that of expression e, then we
0329       // create a temporary (which will have the correct precision thanks to precision_guard)
0330       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0331       // which causes this code to be eliminated in the common case that this type is
0332       // not actually variable precision.  Pre C++17 this code should still be mostly
0333       // optimised away, but we can't prevent instantiation of the dead code leading
0334       // to longer build and possibly link times.
0335       //
0336       BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
0337       {
0338          BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0339          {
0340             const detail::scoped_default_precision<number<Backend, ExpressionTemplates>> precision_guard(e);
0341 
0342             if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0343             {
0344                number t;
0345                t.assign(e);
0346                return *this = std::move(t);
0347             }
0348          }
0349       }
0350       do_assign(e, tag_type());
0351       return *this;
0352    }
0353    BOOST_MP_CXX14_CONSTEXPR number& assign(const value_type& a, const value_type& b)
0354    {
0355       assign_components(backend(), a.backend(), b.backend());
0356       return *this;
0357    }
0358    template <class V, class U>
0359    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(std::is_convertible<V, value_type>::value&& std::is_convertible<U, value_type>::value && !std::is_same<value_type, self_type>::value), number&>::type 
0360       assign(const V& v1, const U& v2, unsigned Digits)
0361    {
0362       self_type r(v1, v2, Digits);
0363       boost::multiprecision::detail::scoped_source_precision<self_type> scope;
0364       return *this = r;
0365    }
0366    BOOST_MP_CXX14_CONSTEXPR number& assign(const value_type & a, const value_type & b, unsigned Digits)
0367    {
0368       this->precision(Digits);
0369       boost::multiprecision::detail::scoped_target_precision<self_type> scoped;
0370       assign_components(backend(), canonical_value(detail::evaluate_if_expression(a)), canonical_value(detail::evaluate_if_expression(b)));
0371       return *this;
0372    }
0373 
0374    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(const number& e)
0375        noexcept(noexcept(std::declval<Backend&>() = std::declval<Backend const&>())) = default;
0376 
0377    template <class V>
0378    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
0379    operator=(const V& v)
0380        noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
0381    {
0382       m_backend = canonical_value(v);
0383       return *this;
0384    }
0385    template <class V>
0386    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v)
0387        noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
0388    {
0389       m_backend = canonical_value(v);
0390       return *this;
0391    }
0392    template <class V, class U>
0393    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v, const U& digits10_or_component)
0394        noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
0395    {
0396       number t(v, digits10_or_component);
0397       boost::multiprecision::detail::scoped_source_precision<self_type> scope;
0398       static_cast<void>(scope);
0399       return *this = t;
0400    }
0401    template <class Other, expression_template_option ET>
0402    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!boost::multiprecision::detail::is_explicitly_convertible<Other, Backend>::value, number<Backend, ExpressionTemplates>&>::type
0403    assign(const number<Other, ET>& v)
0404    {
0405       //
0406       // Attempt a generic interconvertion:
0407       //
0408       using detail::generic_interconvert;
0409       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
0410       detail::scoped_default_precision<number<Other, ET> >                    precision_guard2(*this, v);
0411       //
0412       // If the current precision of *this differs from that of value v, then we
0413       // create a temporary (which will have the correct precision thanks to precision_guard)
0414       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0415       // which causes this code to be eliminated in the common case that this type is
0416       // not actually variable precision.  Pre C++17 this code should still be mostly
0417       // optimised away, but we can't prevent instantiation of the dead code leading
0418       // to longer build and possibly link times.
0419       //
0420       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0421       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0422       {
0423          number t(v);
0424          return *this = std::move(t);
0425       }
0426       generic_interconvert(backend(), v.backend(), number_category<Backend>(), number_category<Other>());
0427       return *this;
0428    }
0429 
0430    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0431    BOOST_MP_CXX14_CONSTEXPR number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = nullptr)
0432    {
0433       //
0434       // No preicsion guard here, we already have one in operator=
0435       //
0436       *this = e;
0437    }
0438    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0439    explicit BOOST_MP_CXX14_CONSTEXPR number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e,
0440                                             typename std::enable_if<!std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value && boost::multiprecision::detail::is_explicitly_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = nullptr)
0441    {
0442       //
0443       // No precision guard as assign has one already:
0444       //
0445       assign(e);
0446    }
0447 
0448    // rvalues:
0449    BOOST_MP_FORCEINLINE constexpr number(number&& r)
0450        noexcept(noexcept(Backend(std::declval<Backend>()))) = default;
0451    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(number&& r) noexcept(noexcept(std::declval<Backend&>() = std::declval<Backend>())) = default;
0452 
0453    template <class Other, expression_template_option ET>
0454    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(number<Other, ET>&& val,
0455                                                         typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = nullptr)
0456        noexcept(noexcept(Backend(std::declval<Other const&>())))
0457        : m_backend(static_cast<number<Other, ET>&&>(val).backend()) {}
0458    template <class Other, expression_template_option ET>
0459    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value), number&>::type 
0460          operator=(number<Other, ET>&& val)
0461             noexcept(noexcept(Backend(std::declval<Other const&>())))
0462    {
0463       m_backend = std::move(val).backend();
0464       return *this;
0465    }
0466 
0467    BOOST_MP_CXX14_CONSTEXPR number& operator+=(const self_type& val)
0468    {
0469       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
0470       //
0471       // If the current precision of *this differs from that of expression e, then we
0472       // create a temporary (which will have the correct precision thanks to precision_guard)
0473       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0474       // which causes this code to be eliminated in the common case that this type is
0475       // not actually variable precision.  Pre C++17 this code should still be mostly
0476       // optimised away, but we can't prevent instantiation of the dead code leading
0477       // to longer build and possibly link times.
0478       //
0479       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0480       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0481       {
0482          number t(*this + val);
0483          return *this = std::move(t);
0484       }
0485       do_add(detail::expression<detail::terminal, self_type>(val), detail::terminal());
0486       return *this;
0487    }
0488 
0489    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0490    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator+=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0491    {
0492       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0493       // Create a copy if e contains this, but not if we're just doing a
0494       //    x += x
0495       if ((contains_self(e) && !is_self(e)))
0496       {
0497          self_type temp(e);
0498          do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
0499       }
0500       else
0501       {
0502          do_add(e, tag());
0503       }
0504       return *this;
0505    }
0506 
0507    template <class Arg1, class Arg2, class Arg3, class Arg4>
0508    BOOST_MP_CXX14_CONSTEXPR number& operator+=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
0509    {
0510       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0511       //
0512       // If the current precision of *this differs from that of expression e, then we
0513       // create a temporary (which will have the correct precision thanks to precision_guard)
0514       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0515       // which causes this code to be eliminated in the common case that this type is
0516       // not actually variable precision.  Pre C++17 this code should still be mostly
0517       // optimised away, but we can't prevent instantiation of the dead code leading
0518       // to longer build and possibly link times.
0519       //
0520       BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
0521       {
0522          BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0523          if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0524             {
0525                number t(*this + e);
0526                return *this = std::move(t);
0527             }
0528       }
0529       //
0530       // Fused multiply-add:
0531       //
0532       using default_ops::eval_multiply_add;
0533       eval_multiply_add(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
0534       return *this;
0535    }
0536 
0537    template <class V>
0538    typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
0539       BOOST_MP_CXX14_CONSTEXPR operator+=(const V& v)
0540    {
0541       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
0542       //
0543       // If the current precision of *this differs from that of value v, then we
0544       // create a temporary (which will have the correct precision thanks to precision_guard)
0545       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0546       // which causes this code to be eliminated in the common case that this type is
0547       // not actually variable precision.  Pre C++17 this code should still be mostly
0548       // optimised away, but we can't prevent instantiation of the dead code leading
0549       // to longer build and possibly link times.
0550       //
0551       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0552       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0553          {
0554             number t(*this + v);
0555             return *this = std::move(t);
0556          }
0557 
0558       using default_ops::eval_add;
0559       eval_add(m_backend, canonical_value(v));
0560       return *this;
0561    }
0562 
0563    BOOST_MP_CXX14_CONSTEXPR number& operator-=(const self_type& val)
0564    {
0565       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
0566       //
0567       // If the current precision of *this differs from that of expression e, then we
0568       // create a temporary (which will have the correct precision thanks to precision_guard)
0569       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0570       // which causes this code to be eliminated in the common case that this type is
0571       // not actually variable precision.  Pre C++17 this code should still be mostly
0572       // optimised away, but we can't prevent instantiation of the dead code leading
0573       // to longer build and possibly link times.
0574       //
0575       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0576       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0577       {
0578          number t(*this - val);
0579          return *this = std::move(t);
0580       }
0581       do_subtract(detail::expression<detail::terminal, self_type>(val), detail::terminal());
0582       return *this;
0583    }
0584 
0585    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0586    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator-=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0587    {
0588       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0589       // Create a copy if e contains this:
0590       if (contains_self(e))
0591       {
0592          self_type temp(e);
0593          do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
0594       }
0595       else
0596       {
0597          do_subtract(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
0598       }
0599       return *this;
0600    }
0601 
0602    template <class V>
0603    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
0604    operator-=(const V& v)
0605    {
0606       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
0607       //
0608       // If the current precision of *this differs from that of value v, then we
0609       // create a temporary (which will have the correct precision thanks to precision_guard)
0610       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0611       // which causes this code to be eliminated in the common case that this type is
0612       // not actually variable precision.  Pre C++17 this code should still be mostly
0613       // optimised away, but we can't prevent instantiation of the dead code leading
0614       // to longer build and possibly link times.
0615       //
0616       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0617       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0618          {
0619             number t(*this - v);
0620             return *this = std::move(t);
0621          }
0622 
0623       using default_ops::eval_subtract;
0624       eval_subtract(m_backend, canonical_value(v));
0625       return *this;
0626    }
0627 
0628    template <class Arg1, class Arg2, class Arg3, class Arg4>
0629    BOOST_MP_CXX14_CONSTEXPR number& operator-=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
0630    {
0631       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0632       //
0633       // If the current precision of *this differs from that of expression e, then we
0634       // create a temporary (which will have the correct precision thanks to precision_guard)
0635       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0636       // which causes this code to be eliminated in the common case that this type is
0637       // not actually variable precision.  Pre C++17 this code should still be mostly
0638       // optimised away, but we can't prevent instantiation of the dead code leading
0639       // to longer build and possibly link times.
0640       //
0641       BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
0642       {
0643          BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0644          if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0645             {
0646                number t(*this - e);
0647                return *this = std::move(t);
0648             }
0649       }
0650       //
0651       // Fused multiply-subtract:
0652       //
0653       using default_ops::eval_multiply_subtract;
0654       eval_multiply_subtract(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
0655       return *this;
0656    }
0657 
0658    BOOST_MP_CXX14_CONSTEXPR number& operator*=(const self_type& e)
0659    {
0660       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0661       //
0662       // If the current precision of *this differs from that of expression e, then we
0663       // create a temporary (which will have the correct precision thanks to precision_guard)
0664       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0665       // which causes this code to be eliminated in the common case that this type is
0666       // not actually variable precision.  Pre C++17 this code should still be mostly
0667       // optimised away, but we can't prevent instantiation of the dead code leading
0668       // to longer build and possibly link times.
0669       //
0670       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0671       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0672       {
0673          number t(*this * e);
0674          return *this = std::move(t);
0675       }
0676       do_multiplies(detail::expression<detail::terminal, self_type>(e), detail::terminal());
0677       return *this;
0678    }
0679 
0680    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0681    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator*=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0682    {
0683       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0684       // Create a temporary if the RHS references *this, but not
0685       // if we're just doing an   x *= x;
0686       if ((contains_self(e) && !is_self(e)))
0687       {
0688          self_type temp(e);
0689          do_multiplies(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
0690       }
0691       else
0692       {
0693          do_multiplies(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
0694       }
0695       return *this;
0696    }
0697 
0698    template <class V>
0699    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
0700    operator*=(const V& v)
0701    {
0702       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
0703       //
0704       // If the current precision of *this differs from that of value v, then we
0705       // create a temporary (which will have the correct precision thanks to precision_guard)
0706       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0707       // which causes this code to be eliminated in the common case that this type is
0708       // not actually variable precision.  Pre C++17 this code should still be mostly
0709       // optimised away, but we can't prevent instantiation of the dead code leading
0710       // to longer build and possibly link times.
0711       //
0712       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0713       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0714          {
0715             number t(*this * v);
0716             return *this = std::move(t);
0717          }
0718 
0719       using default_ops::eval_multiply;
0720       eval_multiply(m_backend, canonical_value(v));
0721       return *this;
0722    }
0723 
0724    BOOST_MP_CXX14_CONSTEXPR number& operator%=(const self_type& e)
0725    {
0726       static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
0727       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0728       //
0729       // If the current precision of *this differs from that of expression e, then we
0730       // create a temporary (which will have the correct precision thanks to precision_guard)
0731       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0732       // which causes this code to be eliminated in the common case that this type is
0733       // not actually variable precision.  Pre C++17 this code should still be mostly
0734       // optimised away, but we can't prevent instantiation of the dead code leading
0735       // to longer build and possibly link times.
0736       //
0737       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0738       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0739       {
0740          number t(*this % e);
0741          return *this = std::move(t);
0742       }
0743       do_modulus(detail::expression<detail::terminal, self_type>(e), detail::terminal());
0744       return *this;
0745    }
0746    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0747    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator%=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0748    {
0749       static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
0750       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0751       // Create a temporary if the RHS references *this:
0752       if (contains_self(e))
0753       {
0754          self_type temp(e);
0755          do_modulus(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
0756       }
0757       else
0758       {
0759          do_modulus(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
0760       }
0761       return *this;
0762    }
0763    template <class V>
0764    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
0765    operator%=(const V& v)
0766    {
0767       static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
0768       using default_ops::eval_modulus;
0769       eval_modulus(m_backend, canonical_value(v));
0770       return *this;
0771    }
0772 
0773    //
0774    // These operators are *not* proto-ized.
0775    // The issue is that the increment/decrement must happen
0776    // even if the result of the operator *is never used*.
0777    // Possibly we could modify our expression wrapper to
0778    // execute the increment/decrement on destruction, but
0779    // correct implementation will be tricky, so defered for now...
0780    //
0781    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator++()
0782    {
0783       using default_ops::eval_increment;
0784       eval_increment(m_backend);
0785       return *this;
0786    }
0787 
0788    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator--()
0789    {
0790       using default_ops::eval_decrement;
0791       eval_decrement(m_backend);
0792       return *this;
0793    }
0794 
0795    inline BOOST_MP_CXX14_CONSTEXPR number operator++(int)
0796    {
0797       using default_ops::eval_increment;
0798       self_type temp(*this);
0799       eval_increment(m_backend);
0800       return temp;
0801    }
0802 
0803    inline BOOST_MP_CXX14_CONSTEXPR number operator--(int)
0804    {
0805       using default_ops::eval_decrement;
0806       self_type temp(*this);
0807       eval_decrement(m_backend);
0808       return temp;
0809    }
0810 
0811    template <class V>
0812    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<V>::value, number&>::type operator<<=(V val)
0813    {
0814       static_assert(number_category<Backend>::value == number_kind_integer, "The left-shift operation is only valid for integer types");
0815       detail::check_shift_range(val, std::integral_constant<bool, (sizeof(V) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<V>::value && boost::multiprecision::detail::is_integral<V>::value > ());
0816       eval_left_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
0817       return *this;
0818    }
0819 
0820    template <class V>
0821    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<V>::value, number&>::type operator>>=(V val)
0822    {
0823       static_assert(number_category<Backend>::value == number_kind_integer, "The right-shift operation is only valid for integer types");
0824       detail::check_shift_range(val, std::integral_constant<bool, (sizeof(V) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<V>::value && boost::multiprecision::detail::is_integral<V>::value>());
0825       eval_right_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
0826       return *this;
0827    }
0828 
0829    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator/=(const self_type& e)
0830    {
0831       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0832       //
0833       // If the current precision of *this differs from that of expression e, then we
0834       // create a temporary (which will have the correct precision thanks to precision_guard)
0835       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0836       // which causes this code to be eliminated in the common case that this type is
0837       // not actually variable precision.  Pre C++17 this code should still be mostly
0838       // optimised away, but we can't prevent instantiation of the dead code leading
0839       // to longer build and possibly link times.
0840       //
0841       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0842       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0843       {
0844          number t(*this / e);
0845          return *this = std::move(t);
0846       }
0847       do_divide(detail::expression<detail::terminal, self_type>(e), detail::terminal());
0848       return *this;
0849    }
0850 
0851    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0852    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator/=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0853    {
0854       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
0855       // Create a temporary if the RHS references *this:
0856       if (contains_self(e))
0857       {
0858          self_type temp(e);
0859          do_divide(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
0860       }
0861       else
0862       {
0863          do_divide(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
0864       }
0865       return *this;
0866    }
0867 
0868    template <class V>
0869    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
0870    operator/=(const V& v)
0871    {
0872       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
0873       //
0874       // If the current precision of *this differs from that of value v, then we
0875       // create a temporary (which will have the correct precision thanks to precision_guard)
0876       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
0877       // which causes this code to be eliminated in the common case that this type is
0878       // not actually variable precision.  Pre C++17 this code should still be mostly
0879       // optimised away, but we can't prevent instantiation of the dead code leading
0880       // to longer build and possibly link times.
0881       //
0882       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
0883       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
0884          {
0885             number t(*this / v);
0886             return *this = std::move(t);
0887          }
0888 
0889       using default_ops::eval_divide;
0890       eval_divide(m_backend, canonical_value(v));
0891       return *this;
0892    }
0893 
0894    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator&=(const self_type& e)
0895    {
0896       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
0897       do_bitwise_and(detail::expression<detail::terminal, self_type>(e), detail::terminal());
0898       return *this;
0899    }
0900 
0901    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0902    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator&=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0903    {
0904       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
0905       // Create a temporary if the RHS references *this, but not
0906       // if we're just doing an   x &= x;
0907       if (contains_self(e) && !is_self(e))
0908       {
0909          self_type temp(e);
0910          do_bitwise_and(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
0911       }
0912       else
0913       {
0914          do_bitwise_and(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
0915       }
0916       return *this;
0917    }
0918 
0919    template <class V>
0920    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
0921    operator&=(const V& v)
0922    {
0923       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
0924       using default_ops::eval_bitwise_and;
0925       eval_bitwise_and(m_backend, canonical_value(v));
0926       return *this;
0927    }
0928 
0929    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator|=(const self_type& e)
0930    {
0931       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
0932       do_bitwise_or(detail::expression<detail::terminal, self_type>(e), detail::terminal());
0933       return *this;
0934    }
0935 
0936    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0937    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator|=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0938    {
0939       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
0940       // Create a temporary if the RHS references *this, but not
0941       // if we're just doing an   x |= x;
0942       if (contains_self(e) && !is_self(e))
0943       {
0944          self_type temp(e);
0945          do_bitwise_or(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
0946       }
0947       else
0948       {
0949          do_bitwise_or(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
0950       }
0951       return *this;
0952    }
0953 
0954    template <class V>
0955    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
0956    operator|=(const V& v)
0957    {
0958       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
0959       using default_ops::eval_bitwise_or;
0960       eval_bitwise_or(m_backend, canonical_value(v));
0961       return *this;
0962    }
0963 
0964    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator^=(const self_type& e)
0965    {
0966       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
0967       do_bitwise_xor(detail::expression<detail::terminal, self_type>(e), detail::terminal());
0968       return *this;
0969    }
0970 
0971    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0972    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator^=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
0973    {
0974       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
0975       if (contains_self(e))
0976       {
0977          self_type temp(e);
0978          do_bitwise_xor(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
0979       }
0980       else
0981       {
0982          do_bitwise_xor(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
0983       }
0984       return *this;
0985    }
0986 
0987    template <class V>
0988    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
0989    operator^=(const V& v)
0990    {
0991       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
0992       using default_ops::eval_bitwise_xor;
0993       eval_bitwise_xor(m_backend, canonical_value(v));
0994       return *this;
0995    }
0996    //
0997    // swap:
0998    //
0999    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(self_type& other) noexcept(noexcept(std::declval<Backend>().swap(std::declval<Backend&>())))
1000    {
1001       m_backend.swap(other.backend());
1002    }
1003    //
1004    // Zero and sign:
1005    //
1006    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool is_zero() const
1007    {
1008       using default_ops::eval_is_zero;
1009       return eval_is_zero(m_backend);
1010    }
1011    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int sign() const
1012    {
1013       using default_ops::eval_get_sign;
1014       return eval_get_sign(m_backend);
1015    }
1016    //
1017    // String conversion functions:
1018    //
1019    std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0)) const
1020    {
1021       return m_backend.str(digits, f);
1022    }
1023 
1024    #ifndef BOOST_MP_STANDALONE
1025    template <class Archive>
1026    void serialize(Archive& ar, const unsigned int /*version*/)
1027    {
1028       ar& boost::make_nvp("backend", m_backend);
1029    }
1030    #endif
1031 
1032  private:
1033    template <class T>
1034    BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(T* result) const
1035    {
1036       using default_ops::eval_convert_to;
1037       eval_convert_to(result, m_backend);
1038    }
1039    template <class B2, expression_template_option ET>
1040    BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(number<B2, ET>* result) const
1041    {
1042       result->assign(*this);
1043    }
1044    BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(std::string* result) const
1045    {
1046       *result = this->str();
1047    }
1048 
1049  public:
1050    template <class T>
1051    BOOST_MP_CXX14_CONSTEXPR T convert_to() const
1052    {
1053       T result = T();
1054       convert_to_imp(&result);
1055       return result;
1056    }
1057    //
1058    // Use in boolean context, and explicit conversion operators:
1059    //
1060 #if BOOST_WORKAROUND(BOOST_MSVC, < 1900) || (defined(__apple_build_version__) && BOOST_WORKAROUND(__clang_major__, < 9))
1061    template <class T>
1062 #else
1063    template <class T, class = typename std::enable_if<std::is_enum<T>::value || !(std::is_constructible<T, detail::convertible_to<self_type const&> >::value || !std::is_default_constructible<T>::value || (!boost::multiprecision::detail::is_arithmetic<T>::value && !boost::multiprecision::detail::is_complex<T>::value)), T>::type>
1064 #endif
1065    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
1066    {
1067       return this->template convert_to<T>();
1068    }
1069    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
1070    {
1071       return !is_zero();
1072    }
1073    //
1074    // Default precision:
1075    //
1076    static BOOST_MP_CXX14_CONSTEXPR unsigned default_precision() noexcept
1077    {
1078       return Backend::default_precision();
1079    }
1080    static BOOST_MP_CXX14_CONSTEXPR void default_precision(unsigned digits10)
1081    {
1082       Backend::default_precision(digits10);
1083       Backend::thread_default_precision(digits10);
1084    }
1085    static BOOST_MP_CXX14_CONSTEXPR unsigned thread_default_precision() noexcept
1086    {
1087       return Backend::thread_default_precision();
1088    }
1089    static BOOST_MP_CXX14_CONSTEXPR void thread_default_precision(unsigned digits10)
1090    {
1091       Backend::thread_default_precision(digits10);
1092    }
1093    BOOST_MP_CXX14_CONSTEXPR unsigned precision() const noexcept
1094    {
1095       return m_backend.precision();
1096    }
1097    BOOST_MP_CXX14_CONSTEXPR void precision(unsigned digits10)
1098    {
1099       m_backend.precision(digits10);
1100    }
1101    //
1102    // Variable precision options:
1103    // 
1104    static constexpr variable_precision_options default_variable_precision_options()noexcept
1105    {
1106       return Backend::default_variable_precision_options();
1107    }
1108    static constexpr variable_precision_options thread_default_variable_precision_options()noexcept
1109    {
1110       return Backend::thread_default_variable_precision_options();
1111    }
1112    static BOOST_MP_CXX14_CONSTEXPR void default_variable_precision_options(variable_precision_options opts)
1113    {
1114       Backend::default_variable_precision_options(opts);
1115       Backend::thread_default_variable_precision_options(opts);
1116    }
1117    static BOOST_MP_CXX14_CONSTEXPR void thread_default_variable_precision_options(variable_precision_options opts)
1118    {
1119       Backend::thread_default_variable_precision_options(opts);
1120    }
1121    //
1122    // Comparison:
1123    //
1124    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int compare(const number<Backend, ExpressionTemplates>& o) const
1125        noexcept(noexcept(std::declval<Backend>().compare(std::declval<Backend>())))
1126    {
1127       return m_backend.compare(o.m_backend);
1128    }
1129    template <class V>
1130    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<V>::value && (number_category<Backend>::value != number_kind_complex), int>::type compare(const V& o) const
1131    {
1132       using default_ops::eval_get_sign;
1133       if (o == 0)
1134          return eval_get_sign(m_backend);
1135       return m_backend.compare(canonical_value(o));
1136    }
1137    template <class V>
1138    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<V>::value && (number_category<Backend>::value == number_kind_complex), int>::type compare(const V& o) const
1139    {
1140       using default_ops::eval_get_sign;
1141       return m_backend.compare(canonical_value(o));
1142    }
1143    //
1144    // Direct access to the underlying backend:
1145    //
1146    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend& backend() & noexcept
1147    {
1148       return m_backend;
1149    }
1150    BOOST_MP_FORCEINLINE constexpr const Backend& backend() const& noexcept { return m_backend; }
1151    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend&& backend() && noexcept { return static_cast<Backend&&>(m_backend); }
1152    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend const&& backend() const&& noexcept { return static_cast<Backend const&&>(m_backend); }
1153    //
1154    // Complex number real and imag:
1155    //
1156    BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
1157    real() const
1158    {
1159       using default_ops::eval_real;
1160       detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
1161       typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type                                   result;
1162       eval_real(result.backend(), backend());
1163       return result;
1164    }
1165    BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
1166    imag() const
1167    {
1168       using default_ops::eval_imag;
1169       detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
1170       typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type                                   result;
1171       eval_imag(result.backend(), backend());
1172       return result;
1173    }
1174    template <class T>
1175    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T, self_type>::value, self_type&>::type real(const T& val)
1176    {
1177       using default_ops::eval_set_real;
1178       eval_set_real(backend(), canonical_value(val));
1179       return *this;
1180    }
1181    template <class T>
1182    inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T, self_type>::value && number_category<self_type>::value == number_kind_complex, self_type&>::type imag(const T& val)
1183    {
1184       using default_ops::eval_set_imag;
1185       eval_set_imag(backend(), canonical_value(val));
1186       return *this;
1187    }
1188 
1189  private:
1190    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1191    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type 
1192       do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
1193    {
1194       // The result of the expression isn't the same type as this -
1195       // create a temporary result and assign it to *this:
1196       using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
1197       temp_type                                                                     t(e);
1198       *this = std::move(t);
1199    }
1200    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1201    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type 
1202       do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
1203    {
1204       // The result of the expression isn't the same type as this -
1205       // create a temporary result and assign it to *this:
1206       using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
1207       temp_type                                                                     t(e);
1208       this->assign(t);
1209    }
1210 
1211    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1212    BOOST_MP_CXX14_CONSTEXPR void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, true>&)
1213    {
1214       do_assign(e, tag());
1215    }
1216 
1217    template <class Exp>
1218    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::add_immediates&)
1219    {
1220       using default_ops::eval_add;
1221       boost::multiprecision::detail::maybe_promote_precision(this);
1222       eval_add(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1223    }
1224    template <class Exp>
1225    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::subtract_immediates&)
1226    {
1227       using default_ops::eval_subtract;
1228       boost::multiprecision::detail::maybe_promote_precision(this);
1229       eval_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1230    }
1231    template <class Exp>
1232    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_immediates&)
1233    {
1234       using default_ops::eval_multiply;
1235       boost::multiprecision::detail::maybe_promote_precision(this);
1236       eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1237    }
1238    template <class Exp>
1239    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_add&)
1240    {
1241       using default_ops::eval_multiply_add;
1242       boost::multiprecision::detail::maybe_promote_precision(this);
1243       eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
1244    }
1245    template <class Exp>
1246    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_subtract&)
1247    {
1248       using default_ops::eval_multiply_subtract;
1249       boost::multiprecision::detail::maybe_promote_precision(this);
1250       eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
1251    }
1252 
1253    template <class Exp>
1254    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divide_immediates&)
1255    {
1256       using default_ops::eval_divide;
1257       boost::multiprecision::detail::maybe_promote_precision(this);
1258       eval_divide(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1259    }
1260 
1261    template <class Exp>
1262    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::negate&)
1263    {
1264       using left_type = typename Exp::left_type;
1265       do_assign(e.left(), typename left_type::tag_type());
1266       m_backend.negate();
1267    }
1268    template <class Exp>
1269    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::plus&)
1270    {
1271       using left_type = typename Exp::left_type ;
1272       using right_type = typename Exp::right_type;
1273 
1274       constexpr int const left_depth  = left_type::depth;
1275       constexpr int const right_depth = right_type::depth;
1276 
1277       bool bl = contains_self(e.left());
1278       bool br = contains_self(e.right());
1279 
1280       if (bl && br)
1281       {
1282          self_type temp(e);
1283          temp.m_backend.swap(this->m_backend);
1284       }
1285       else if (bl && is_self(e.left()))
1286       {
1287          // Ignore the left node, it's *this, just add the right:
1288          do_add(e.right(), typename right_type::tag_type());
1289       }
1290       else if (br && is_self(e.right()))
1291       {
1292          // Ignore the right node, it's *this, just add the left:
1293          do_add(e.left(), typename left_type::tag_type());
1294       }
1295       else if (!br && (bl || (left_depth >= right_depth)))
1296       { // br is always false, but if bl is true we must take the this branch:
1297          do_assign(e.left(), typename left_type::tag_type());
1298          do_add(e.right(), typename right_type::tag_type());
1299       }
1300       else
1301       {
1302          do_assign(e.right(), typename right_type::tag_type());
1303          do_add(e.left(), typename left_type::tag_type());
1304       }
1305    }
1306    template <class Exp>
1307    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::minus&)
1308    {
1309       using left_type = typename Exp::left_type ;
1310       using right_type = typename Exp::right_type;
1311 
1312       constexpr int const left_depth  = left_type::depth;
1313       constexpr int const right_depth = right_type::depth;
1314 
1315       bool bl = contains_self(e.left());
1316       bool br = contains_self(e.right());
1317 
1318       if (bl && br)
1319       {
1320          self_type temp(e);
1321          temp.m_backend.swap(this->m_backend);
1322       }
1323       else if (bl && is_self(e.left()))
1324       {
1325          // Ignore the left node, it's *this, just subtract the right:
1326          do_subtract(e.right(), typename right_type::tag_type());
1327       }
1328       else if (br && is_self(e.right()))
1329       {
1330          // Ignore the right node, it's *this, just subtract the left and negate the result:
1331          do_subtract(e.left(), typename left_type::tag_type());
1332          m_backend.negate();
1333       }
1334       else if (!br && (bl || (left_depth >= right_depth)))
1335       { // br is always false, but if bl is true we must take the this branch:
1336          do_assign(e.left(), typename left_type::tag_type());
1337          do_subtract(e.right(), typename right_type::tag_type());
1338       }
1339       else
1340       {
1341          do_assign(e.right(), typename right_type::tag_type());
1342          do_subtract(e.left(), typename left_type::tag_type());
1343          m_backend.negate();
1344       }
1345    }
1346    template <class Exp>
1347    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiplies&)
1348    {
1349       using left_type = typename Exp::left_type ;
1350       using right_type = typename Exp::right_type;
1351 
1352       constexpr int const left_depth  = left_type::depth;
1353       constexpr int const right_depth = right_type::depth;
1354 
1355       bool bl = contains_self(e.left());
1356       bool br = contains_self(e.right());
1357 
1358       if (bl && br)
1359       {
1360          self_type temp(e);
1361          temp.m_backend.swap(this->m_backend);
1362       }
1363       else if (bl && is_self(e.left()))
1364       {
1365          // Ignore the left node, it's *this, just add the right:
1366          do_multiplies(e.right(), typename right_type::tag_type());
1367       }
1368       else if (br && is_self(e.right()))
1369       {
1370          // Ignore the right node, it's *this, just add the left:
1371          do_multiplies(e.left(), typename left_type::tag_type());
1372       }
1373       else if (!br && (bl || (left_depth >= right_depth)))
1374       { // br is always false, but if bl is true we must take the this branch:
1375          do_assign(e.left(), typename left_type::tag_type());
1376          do_multiplies(e.right(), typename right_type::tag_type());
1377       }
1378       else
1379       {
1380          do_assign(e.right(), typename right_type::tag_type());
1381          do_multiplies(e.left(), typename left_type::tag_type());
1382       }
1383    }
1384    template <class Exp>
1385    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divides&)
1386    {
1387       using left_type = typename Exp::left_type ;
1388       using right_type = typename Exp::right_type;
1389 
1390       bool bl = contains_self(e.left());
1391       bool br = contains_self(e.right());
1392 
1393       if (bl && is_self(e.left()))
1394       {
1395          // Ignore the left node, it's *this, just add the right:
1396          do_divide(e.right(), typename right_type::tag_type());
1397       }
1398       else if (br)
1399       {
1400          self_type temp(e);
1401          temp.m_backend.swap(this->m_backend);
1402       }
1403       else
1404       {
1405          do_assign(e.left(), typename left_type::tag_type());
1406          do_divide(e.right(), typename right_type::tag_type());
1407       }
1408    }
1409    template <class Exp>
1410    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus&)
1411    {
1412       //
1413       // This operation is only valid for integer backends:
1414       //
1415       static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
1416 
1417       using left_type = typename Exp::left_type ;
1418       using right_type = typename Exp::right_type;
1419 
1420       bool bl = contains_self(e.left());
1421       bool br = contains_self(e.right());
1422 
1423       if (bl && is_self(e.left()))
1424       {
1425          // Ignore the left node, it's *this, just add the right:
1426          do_modulus(e.right(), typename right_type::tag_type());
1427       }
1428       else if (br)
1429       {
1430          self_type temp(e);
1431          temp.m_backend.swap(this->m_backend);
1432       }
1433       else
1434       {
1435          do_assign(e.left(), typename left_type::tag_type());
1436          do_modulus(e.right(), typename right_type::tag_type());
1437       }
1438    }
1439    template <class Exp>
1440    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus_immediates&)
1441    {
1442       static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
1443       using default_ops::eval_modulus;
1444       boost::multiprecision::detail::maybe_promote_precision(this);
1445       eval_modulus(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1446    }
1447 
1448    template <class Exp>
1449    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and&)
1450    {
1451       //
1452       // This operation is only valid for integer backends:
1453       //
1454       static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1455 
1456       using left_type = typename Exp::left_type ;
1457       using right_type = typename Exp::right_type;
1458 
1459       constexpr int const left_depth  = left_type::depth;
1460       constexpr int const right_depth = right_type::depth;
1461 
1462       bool bl = contains_self(e.left());
1463       bool br = contains_self(e.right());
1464 
1465       if (bl && is_self(e.left()))
1466       {
1467          // Ignore the left node, it's *this, just add the right:
1468          do_bitwise_and(e.right(), typename right_type::tag_type());
1469       }
1470       else if (br && is_self(e.right()))
1471       {
1472          do_bitwise_and(e.left(), typename left_type::tag_type());
1473       }
1474       else if (!br && (bl || (left_depth >= right_depth)))
1475       {
1476          do_assign(e.left(), typename left_type::tag_type());
1477          do_bitwise_and(e.right(), typename right_type::tag_type());
1478       }
1479       else
1480       {
1481          do_assign(e.right(), typename right_type::tag_type());
1482          do_bitwise_and(e.left(), typename left_type::tag_type());
1483       }
1484    }
1485    template <class Exp>
1486    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and_immediates&)
1487    {
1488       static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1489       using default_ops::eval_bitwise_and;
1490       eval_bitwise_and(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1491    }
1492 
1493    template <class Exp>
1494    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or&)
1495    {
1496       //
1497       // This operation is only valid for integer backends:
1498       //
1499       static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1500 
1501       using left_type = typename Exp::left_type ;
1502       using right_type = typename Exp::right_type;
1503 
1504       constexpr int const left_depth  = left_type::depth;
1505       constexpr int const right_depth = right_type::depth;
1506 
1507       bool bl = contains_self(e.left());
1508       bool br = contains_self(e.right());
1509 
1510       if (bl && is_self(e.left()))
1511       {
1512          // Ignore the left node, it's *this, just add the right:
1513          do_bitwise_or(e.right(), typename right_type::tag_type());
1514       }
1515       else if (br && is_self(e.right()))
1516       {
1517          do_bitwise_or(e.left(), typename left_type::tag_type());
1518       }
1519       else if (!br && (bl || (left_depth >= right_depth)))
1520       {
1521          do_assign(e.left(), typename left_type::tag_type());
1522          do_bitwise_or(e.right(), typename right_type::tag_type());
1523       }
1524       else
1525       {
1526          do_assign(e.right(), typename right_type::tag_type());
1527          do_bitwise_or(e.left(), typename left_type::tag_type());
1528       }
1529    }
1530    template <class Exp>
1531    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or_immediates&)
1532    {
1533       static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1534       using default_ops::eval_bitwise_or;
1535       eval_bitwise_or(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1536    }
1537 
1538    template <class Exp>
1539    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor&)
1540    {
1541       //
1542       // This operation is only valid for integer backends:
1543       //
1544       static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1545 
1546       using left_type = typename Exp::left_type ;
1547       using right_type = typename Exp::right_type;
1548 
1549       constexpr int const left_depth  = left_type::depth;
1550       constexpr int const right_depth = right_type::depth;
1551 
1552       bool bl = contains_self(e.left());
1553       bool br = contains_self(e.right());
1554 
1555       if (bl && is_self(e.left()))
1556       {
1557          // Ignore the left node, it's *this, just add the right:
1558          do_bitwise_xor(e.right(), typename right_type::tag_type());
1559       }
1560       else if (br && is_self(e.right()))
1561       {
1562          do_bitwise_xor(e.left(), typename left_type::tag_type());
1563       }
1564       else if (!br && (bl || (left_depth >= right_depth)))
1565       {
1566          do_assign(e.left(), typename left_type::tag_type());
1567          do_bitwise_xor(e.right(), typename right_type::tag_type());
1568       }
1569       else
1570       {
1571          do_assign(e.right(), typename right_type::tag_type());
1572          do_bitwise_xor(e.left(), typename left_type::tag_type());
1573       }
1574    }
1575    template <class Exp>
1576    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor_immediates&)
1577    {
1578       static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1579       using default_ops::eval_bitwise_xor;
1580       eval_bitwise_xor(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1581    }
1582    template <class Exp>
1583    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::terminal&)
1584    {
1585       if (!is_self(e))
1586       {
1587          m_backend = canonical_value(e.value());
1588       }
1589    }
1590    template <class Exp>
1591    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::function&)
1592    {
1593       using tag_type = typename Exp::arity;
1594       boost::multiprecision::detail::maybe_promote_precision(this);
1595       do_assign_function(e, tag_type());
1596    }
1597    template <class Exp>
1598    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_left&)
1599    {
1600       // We can only shift by an integer value, not an arbitrary expression:
1601       using left_type = typename Exp::left_type   ;
1602       using right_type = typename Exp::right_type  ;
1603       using right_arity = typename right_type::arity;
1604       static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
1605       using right_value_type = typename right_type::result_type;
1606       static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
1607       using tag_type = typename left_type::tag_type;
1608       do_assign_left_shift(e.left(), canonical_value(e.right().value()), tag_type());
1609    }
1610 
1611    template <class Exp>
1612    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_right&)
1613    {
1614       // We can only shift by an integer value, not an arbitrary expression:
1615       using left_type = typename Exp::left_type   ;
1616       using right_type = typename Exp::right_type  ;
1617       using right_arity = typename right_type::arity;
1618       static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
1619       using right_value_type = typename right_type::result_type;
1620       static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
1621       using tag_type = typename left_type::tag_type;
1622       do_assign_right_shift(e.left(), canonical_value(e.right().value()), tag_type());
1623    }
1624 
1625    template <class Exp>
1626    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_complement&)
1627    {
1628       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
1629       using default_ops::eval_complement;
1630       self_type temp(e.left());
1631       eval_complement(m_backend, temp.backend());
1632    }
1633 
1634    template <class Exp>
1635    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::complement_immediates&)
1636    {
1637       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
1638       using default_ops::eval_complement;
1639       eval_complement(m_backend, canonical_value(e.left().value()));
1640    }
1641 
1642    template <class Exp, class Val>
1643    BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const detail::terminal&)
1644    {
1645       static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
1646       using default_ops::eval_right_shift;
1647       detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
1648       eval_right_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
1649    }
1650 
1651    template <class Exp, class Val>
1652    BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const detail::terminal&)
1653    {
1654       static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
1655       using default_ops::eval_left_shift;
1656       detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
1657       eval_left_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
1658    }
1659 
1660    template <class Exp, class Val, class Tag>
1661    BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const Tag&)
1662    {
1663       static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
1664       using default_ops::eval_right_shift;
1665       self_type temp(e);
1666       detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
1667       eval_right_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
1668    }
1669 
1670    template <class Exp, class Val, class Tag>
1671    BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const Tag&)
1672    {
1673       static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
1674       using default_ops::eval_left_shift;
1675       self_type temp(e);
1676       detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
1677       eval_left_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
1678    }
1679 
1680    template <class Exp>
1681    BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 1>&)
1682    {
1683       e.left().value()(&m_backend);
1684    }
1685    template <class Exp>
1686    BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 2>&)
1687    {
1688       using right_type = typename Exp::right_type     ;
1689       using tag_type = typename right_type::tag_type;
1690       do_assign_function_1(e.left().value(), e.right_ref(), tag_type());
1691    }
1692    template <class F, class Exp>
1693    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const detail::terminal&)
1694    {
1695       f(m_backend, function_arg_value(val));
1696    }
1697    template <class F, class Exp, class Tag>
1698    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const Tag&)
1699    {
1700       typename Exp::result_type t(val);
1701       f(m_backend, t.backend());
1702    }
1703    template <class Exp>
1704    BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 3>&)
1705    {
1706       using middle_type = typename Exp::middle_type     ;
1707       using tag_type = typename middle_type::tag_type;
1708       using end_type = typename Exp::right_type      ;
1709       using end_tag = typename end_type::tag_type   ;
1710       do_assign_function_2(e.left().value(), e.middle_ref(), e.right_ref(), tag_type(), end_tag());
1711    }
1712    template <class F, class Exp1, class Exp2>
1713    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const detail::terminal&)
1714    {
1715       f(m_backend, function_arg_value(val1), function_arg_value(val2));
1716    }
1717    template <class F, class Exp1, class Exp2, class Tag1>
1718    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const detail::terminal&)
1719    {
1720       typename Exp1::result_type temp1(val1);
1721       f(m_backend, std::move(temp1.backend()), function_arg_value(val2));
1722    }
1723    template <class F, class Exp1, class Exp2, class Tag2>
1724    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const Tag2&)
1725    {
1726       typename Exp2::result_type temp2(val2);
1727       f(m_backend, function_arg_value(val1), std::move(temp2.backend()));
1728    }
1729    template <class F, class Exp1, class Exp2, class Tag1, class Tag2>
1730    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const Tag2&)
1731    {
1732       typename Exp1::result_type temp1(val1);
1733       typename Exp2::result_type temp2(val2);
1734       f(m_backend, std::move(temp1.backend()), std::move(temp2.backend()));
1735    }
1736 
1737    template <class Exp>
1738    BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 4>&)
1739    {
1740       using left_type = typename Exp::left_middle_type ;
1741       using left_tag_type = typename left_type::tag_type   ;
1742       using middle_type = typename Exp::right_middle_type;
1743       using middle_tag_type = typename middle_type::tag_type ;
1744       using right_type = typename Exp::right_type       ;
1745       using right_tag_type = typename right_type::tag_type  ;
1746       do_assign_function_3a(e.left().value(), e.left_middle_ref(), e.right_middle_ref(), e.right_ref(), left_tag_type(), middle_tag_type(), right_tag_type());
1747    }
1748 
1749    template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
1750    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag2& t2, const Tag3& t3)
1751    {
1752       do_assign_function_3b(f, val1, val2, val3, t2, t3);
1753    }
1754    template <class F, class Exp1, class Exp2, class Exp3, class Tag1, class Tag2, class Tag3>
1755    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag1&, const Tag2& t2, const Tag3& t3)
1756    {
1757       typename Exp1::result_type t(val1);
1758       do_assign_function_3b(f, std::move(t), val2, val3, t2, t3);
1759    }
1760    template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
1761    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag3& t3)
1762    {
1763       do_assign_function_3c(f, val1, val2, val3, t3);
1764    }
1765    template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
1766    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag2& /*t2*/, const Tag3& t3)
1767    {
1768       typename Exp2::result_type t(val2);
1769       do_assign_function_3c(f, val1, std::move(t), val3, t3);
1770    }
1771    template <class F, class Exp1, class Exp2, class Exp3>
1772    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&)
1773    {
1774       f(m_backend, function_arg_value(val1), function_arg_value(val2), function_arg_value(val3));
1775    }
1776    template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
1777    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag3& /*t3*/)
1778    {
1779       typename Exp3::result_type t(val3);
1780       do_assign_function_3c(f, val1, val2, std::move(t), detail::terminal());
1781    }
1782 
1783    template <class Exp>
1784    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::terminal&)
1785    {
1786       using default_ops::eval_add;
1787       boost::multiprecision::detail::maybe_promote_precision(this);
1788       eval_add(m_backend, canonical_value(e.value()));
1789    }
1790 
1791    template <class Exp>
1792    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::negate&)
1793    {
1794       using left_type = typename Exp::left_type;
1795       boost::multiprecision::detail::maybe_promote_precision(this);
1796       do_subtract(e.left(), typename left_type::tag_type());
1797    }
1798 
1799    template <class Exp>
1800    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::plus&)
1801    {
1802       using left_type = typename Exp::left_type ;
1803       using right_type = typename Exp::right_type;
1804       do_add(e.left(), typename left_type::tag_type());
1805       do_add(e.right(), typename right_type::tag_type());
1806    }
1807 
1808    template <class Exp>
1809    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::minus&)
1810    {
1811       using left_type = typename Exp::left_type ;
1812       using right_type = typename Exp::right_type;
1813       do_add(e.left(), typename left_type::tag_type());
1814       do_subtract(e.right(), typename right_type::tag_type());
1815    }
1816 
1817    template <class Exp, class unknown>
1818    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const unknown&)
1819    {
1820       self_type temp(e);
1821       do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
1822    }
1823 
1824    template <class Exp>
1825    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::add_immediates&)
1826    {
1827       using default_ops::eval_add;
1828       boost::multiprecision::detail::maybe_promote_precision(this);
1829       eval_add(m_backend, canonical_value(e.left().value()));
1830       eval_add(m_backend, canonical_value(e.right().value()));
1831    }
1832    template <class Exp>
1833    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::subtract_immediates&)
1834    {
1835       using default_ops::eval_add;
1836       using default_ops::eval_subtract;
1837       boost::multiprecision::detail::maybe_promote_precision(this);
1838       eval_add(m_backend, canonical_value(e.left().value()));
1839       eval_subtract(m_backend, canonical_value(e.right().value()));
1840    }
1841    template <class Exp>
1842    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::terminal&)
1843    {
1844       using default_ops::eval_subtract;
1845       boost::multiprecision::detail::maybe_promote_precision(this);
1846       eval_subtract(m_backend, canonical_value(e.value()));
1847    }
1848 
1849    template <class Exp>
1850    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::negate&)
1851    {
1852       using left_type = typename Exp::left_type;
1853       do_add(e.left(), typename left_type::tag_type());
1854    }
1855 
1856    template <class Exp>
1857    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::plus&)
1858    {
1859       using left_type = typename Exp::left_type ;
1860       using right_type = typename Exp::right_type;
1861       do_subtract(e.left(), typename left_type::tag_type());
1862       do_subtract(e.right(), typename right_type::tag_type());
1863    }
1864 
1865    template <class Exp>
1866    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::minus&)
1867    {
1868       using left_type = typename Exp::left_type ;
1869       using right_type = typename Exp::right_type;
1870       do_subtract(e.left(), typename left_type::tag_type());
1871       do_add(e.right(), typename right_type::tag_type());
1872    }
1873    template <class Exp>
1874    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::add_immediates&)
1875    {
1876       using default_ops::eval_subtract;
1877       boost::multiprecision::detail::maybe_promote_precision(this);
1878       eval_subtract(m_backend, canonical_value(e.left().value()));
1879       eval_subtract(m_backend, canonical_value(e.right().value()));
1880    }
1881    template <class Exp>
1882    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::subtract_immediates&)
1883    {
1884       using default_ops::eval_add;
1885       using default_ops::eval_subtract;
1886       eval_subtract(m_backend, canonical_value(e.left().value()));
1887       eval_add(m_backend, canonical_value(e.right().value()));
1888    }
1889    template <class Exp, class unknown>
1890    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const unknown&)
1891    {
1892       self_type temp(e);
1893       do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
1894    }
1895 
1896    template <class Exp>
1897    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::terminal&)
1898    {
1899       using default_ops::eval_multiply;
1900       boost::multiprecision::detail::maybe_promote_precision(this);
1901       eval_multiply(m_backend, canonical_value(e.value()));
1902    }
1903 
1904    template <class Exp>
1905    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::negate&)
1906    {
1907       using left_type = typename Exp::left_type;
1908       do_multiplies(e.left(), typename left_type::tag_type());
1909       m_backend.negate();
1910    }
1911 
1912    template <class Exp>
1913    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiplies&)
1914    {
1915       using left_type = typename Exp::left_type ;
1916       using right_type = typename Exp::right_type;
1917       do_multiplies(e.left(), typename left_type::tag_type());
1918       do_multiplies(e.right(), typename right_type::tag_type());
1919    }
1920    //
1921    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1922    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1923    //
1924    template <class Exp>
1925    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
1926    do_multiplies(const Exp& e, const detail::divides&)
1927    {
1928       using left_type = typename Exp::left_type ;
1929       using right_type = typename Exp::right_type;
1930       do_multiplies(e.left(), typename left_type::tag_type());
1931       do_divide(e.right(), typename right_type::tag_type());
1932    }
1933 
1934    template <class Exp>
1935    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiply_immediates&)
1936    {
1937       using default_ops::eval_multiply;
1938       boost::multiprecision::detail::maybe_promote_precision(this);
1939       eval_multiply(m_backend, canonical_value(e.left().value()));
1940       eval_multiply(m_backend, canonical_value(e.right().value()));
1941    }
1942    //
1943    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1944    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1945    //
1946    template <class Exp>
1947    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
1948    do_multiplies(const Exp& e, const detail::divide_immediates&)
1949    {
1950       using default_ops::eval_divide;
1951       using default_ops::eval_multiply;
1952       boost::multiprecision::detail::maybe_promote_precision(this);
1953       eval_multiply(m_backend, canonical_value(e.left().value()));
1954       eval_divide(m_backend, canonical_value(e.right().value()));
1955    }
1956    template <class Exp, class unknown>
1957    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const unknown&)
1958    {
1959       using default_ops::eval_multiply;
1960       boost::multiprecision::detail::maybe_promote_precision(this);
1961       self_type temp(e);
1962       eval_multiply(m_backend, temp.m_backend);
1963    }
1964 
1965    template <class Exp>
1966    BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::terminal&)
1967    {
1968       using default_ops::eval_divide;
1969       boost::multiprecision::detail::maybe_promote_precision(this);
1970       eval_divide(m_backend, canonical_value(e.value()));
1971    }
1972 
1973    template <class Exp>
1974    BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::negate&)
1975    {
1976       using left_type = typename Exp::left_type;
1977       do_divide(e.left(), typename left_type::tag_type());
1978       m_backend.negate();
1979    }
1980    //
1981    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1982    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1983    //
1984    template <class Exp>
1985    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
1986    do_divide(const Exp& e, const detail::multiplies&)
1987    {
1988       using left_type = typename Exp::left_type ;
1989       using right_type = typename Exp::right_type;
1990       do_divide(e.left(), typename left_type::tag_type());
1991       do_divide(e.right(), typename right_type::tag_type());
1992    }
1993    //
1994    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1995    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1996    //
1997    template <class Exp>
1998    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
1999    do_divide(const Exp& e, const detail::divides&)
2000    {
2001       using left_type = typename Exp::left_type ;
2002       using right_type = typename Exp::right_type;
2003       do_divide(e.left(), typename left_type::tag_type());
2004       do_multiplies(e.right(), typename right_type::tag_type());
2005    }
2006    //
2007    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
2008    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
2009    //
2010    template <class Exp>
2011    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
2012    do_divides(const Exp& e, const detail::multiply_immediates&)
2013    {
2014       using default_ops::eval_divide;
2015       boost::multiprecision::detail::maybe_promote_precision(this);
2016       eval_divide(m_backend, canonical_value(e.left().value()));
2017       eval_divide(m_backend, canonical_value(e.right().value()));
2018    }
2019    //
2020    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
2021    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
2022    //
2023    template <class Exp>
2024    BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
2025    do_divides(const Exp& e, const detail::divide_immediates&)
2026    {
2027       using default_ops::eval_divide;
2028       using default_ops::eval_multiply;
2029       boost::multiprecision::detail::maybe_promote_precision(this);
2030       eval_divide(m_backend, canonical_value(e.left().value()));
2031       mutiply(m_backend, canonical_value(e.right().value()));
2032    }
2033 
2034    template <class Exp, class unknown>
2035    BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const unknown&)
2036    {
2037       using default_ops::eval_multiply;
2038       boost::multiprecision::detail::maybe_promote_precision(this);
2039       self_type temp(e);
2040       eval_divide(m_backend, temp.m_backend);
2041    }
2042 
2043    template <class Exp>
2044    BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const detail::terminal&)
2045    {
2046       static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
2047       using default_ops::eval_modulus;
2048       boost::multiprecision::detail::maybe_promote_precision(this);
2049       eval_modulus(m_backend, canonical_value(e.value()));
2050    }
2051 
2052    template <class Exp, class Unknown>
2053    BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const Unknown&)
2054    {
2055       static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
2056       using default_ops::eval_modulus;
2057       boost::multiprecision::detail::maybe_promote_precision(this);
2058       self_type temp(e);
2059       eval_modulus(m_backend, canonical_value(temp));
2060    }
2061 
2062    template <class Exp>
2063    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::terminal&)
2064    {
2065       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
2066       using default_ops::eval_bitwise_and;
2067       eval_bitwise_and(m_backend, canonical_value(e.value()));
2068    }
2069    template <class Exp>
2070    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::bitwise_and&)
2071    {
2072       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
2073       using left_type = typename Exp::left_type ;
2074       using right_type = typename Exp::right_type;
2075       do_bitwise_and(e.left(), typename left_type::tag_type());
2076       do_bitwise_and(e.right(), typename right_type::tag_type());
2077    }
2078    template <class Exp, class unknown>
2079    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const unknown&)
2080    {
2081       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
2082       using default_ops::eval_bitwise_and;
2083       self_type temp(e);
2084       eval_bitwise_and(m_backend, temp.m_backend);
2085    }
2086 
2087    template <class Exp>
2088    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::terminal&)
2089    {
2090       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
2091       using default_ops::eval_bitwise_or;
2092       eval_bitwise_or(m_backend, canonical_value(e.value()));
2093    }
2094    template <class Exp>
2095    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::bitwise_or&)
2096    {
2097       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
2098       using left_type = typename Exp::left_type ;
2099       using right_type = typename Exp::right_type;
2100       do_bitwise_or(e.left(), typename left_type::tag_type());
2101       do_bitwise_or(e.right(), typename right_type::tag_type());
2102    }
2103    template <class Exp, class unknown>
2104    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const unknown&)
2105    {
2106       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
2107       using default_ops::eval_bitwise_or;
2108       self_type temp(e);
2109       eval_bitwise_or(m_backend, temp.m_backend);
2110    }
2111 
2112    template <class Exp>
2113    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::terminal&)
2114    {
2115       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
2116       using default_ops::eval_bitwise_xor;
2117       eval_bitwise_xor(m_backend, canonical_value(e.value()));
2118    }
2119    template <class Exp>
2120    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::bitwise_xor&)
2121    {
2122       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
2123       using left_type = typename Exp::left_type ;
2124       using right_type = typename Exp::right_type;
2125       do_bitwise_xor(e.left(), typename left_type::tag_type());
2126       do_bitwise_xor(e.right(), typename right_type::tag_type());
2127    }
2128    template <class Exp, class unknown>
2129    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const unknown&)
2130    {
2131       static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
2132       using default_ops::eval_bitwise_xor;
2133       self_type temp(e);
2134       eval_bitwise_xor(m_backend, temp.m_backend);
2135    }
2136 
2137    // Tests if the expression contains a reference to *this:
2138    template <class Exp>
2139    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e) const noexcept
2140    {
2141       return contains_self(e, typename Exp::arity());
2142    }
2143    template <class Exp>
2144    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
2145    {
2146       return is_realy_self(e.value());
2147    }
2148    template <class Exp>
2149    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 1> const&) const noexcept
2150    {
2151       using child_type = typename Exp::left_type;
2152       return contains_self(e.left(), typename child_type::arity());
2153    }
2154    template <class Exp>
2155    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 2> const&) const noexcept
2156    {
2157       using child0_type = typename Exp::left_type ;
2158       using child1_type = typename Exp::right_type;
2159       return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.right(), typename child1_type::arity());
2160    }
2161    template <class Exp>
2162    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 3> const&) const noexcept
2163    {
2164       using child0_type = typename Exp::left_type  ;
2165       using child1_type = typename Exp::middle_type;
2166       using child2_type = typename Exp::right_type ;
2167       return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.middle(), typename child1_type::arity()) || contains_self(e.right(), typename child2_type::arity());
2168    }
2169    template <class Exp>
2170    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 4> const&) const noexcept
2171    {
2172       using child0_type = typename Exp::left_type;
2173       using child1_type = typename Exp::left_middle_type;
2174       using child2_type = typename Exp::right_middle_type;
2175       using child3_type = typename Exp::right_type;
2176       return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.left_middle(), typename child1_type::arity()) || contains_self(e.right_middle(), typename child2_type::arity()) || contains_self(e.right(), typename child3_type::arity());
2177    }
2178 
2179    // Test if the expression is a reference to *this:
2180    template <class Exp>
2181    BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e) const noexcept
2182    {
2183       return is_self(e, typename Exp::arity());
2184    }
2185    template <class Exp>
2186    BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
2187    {
2188       return is_realy_self(e.value());
2189    }
2190    template <class Exp, int v>
2191    BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp&, std::integral_constant<int, v> const&) const noexcept
2192    {
2193       return false;
2194    }
2195 
2196    template <class Val>
2197    BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const Val&) const noexcept { return false; }
2198    BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const self_type& v) const noexcept { return &v == this; }
2199 
2200    static BOOST_MP_FORCEINLINE constexpr const Backend& function_arg_value(const self_type& v) noexcept { return v.backend(); }
2201    template <class Other, expression_template_option ET2>
2202    static BOOST_MP_FORCEINLINE constexpr const Other& function_arg_value(const number<Other, ET2>& v) noexcept { return v.backend(); }
2203    template <class V>
2204    static BOOST_MP_FORCEINLINE constexpr const V& function_arg_value(const V& v) noexcept { return v; }
2205    template <class A1, class A2, class A3, class A4>
2206    static BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR const A1& function_arg_value(const detail::expression<detail::terminal, A1, A2, A3, A4>& exp) noexcept { return exp.value(); }
2207    template <class A2, class A3, class A4>
2208    static BOOST_MP_FORCEINLINE constexpr const Backend& function_arg_value(const detail::expression<detail::terminal, number<Backend>, A2, A3, A4>& exp) noexcept { return exp.value().backend(); }
2209    Backend                                                    m_backend;
2210 
2211  public:
2212    //
2213    // These shouldn't really need to be public, or even member functions, but it makes implementing
2214    // the non-member operators way easier if they are:
2215    //
2216    static BOOST_MP_FORCEINLINE constexpr const Backend& canonical_value(const self_type& v) noexcept { return v.m_backend; }
2217    template <class B2, expression_template_option ET>
2218    static BOOST_MP_FORCEINLINE constexpr const B2& canonical_value(const number<B2, ET>& v) noexcept { return v.backend(); }
2219    template <class B2, expression_template_option ET>
2220    static BOOST_MP_FORCEINLINE constexpr B2&& canonical_value(number<B2, ET>&& v) noexcept { return static_cast<number<B2, ET>&&>(v).backend(); }
2221    template <class V>
2222    static BOOST_MP_FORCEINLINE constexpr typename std::enable_if<!std::is_same<typename detail::canonical<V, Backend>::type, V>::value, typename detail::canonical<V, Backend>::type>::type
2223    canonical_value(const V& v) noexcept { return static_cast<typename detail::canonical<V, Backend>::type>(v); }
2224    template <class V>
2225    static BOOST_MP_FORCEINLINE constexpr typename std::enable_if<std::is_same<typename detail::canonical<V, Backend>::type, V>::value, const V&>::type
2226    canonical_value(const V& v) noexcept { return v; }
2227    static BOOST_MP_FORCEINLINE typename detail::canonical<std::string, Backend>::type canonical_value(const std::string& v) noexcept { return v.c_str(); }
2228 };
2229 
2230 template <class Backend, expression_template_option ExpressionTemplates>
2231 inline std::ostream& operator<<(std::ostream& os, const number<Backend, ExpressionTemplates>& r)
2232 {
2233    std::streamsize d  = os.precision();
2234    std::string     s  = r.str(d, os.flags());
2235    std::streamsize ss = os.width();
2236    if (ss > static_cast<std::streamsize>(s.size()))
2237    {
2238       char fill = os.fill();
2239       if ((os.flags() & std::ios_base::left) == std::ios_base::left)
2240          s.append(static_cast<std::string::size_type>(ss - static_cast<std::streamsize>(s.size())), fill);
2241       else
2242          s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(ss - static_cast<std::streamsize>(s.size())), fill);
2243    }
2244    return os << s;
2245 }
2246 
2247 template <class Backend, expression_template_option ExpressionTemplates>
2248 std::string to_string(const number<Backend, ExpressionTemplates>& val)
2249 {
2250   return val.str(6, std::ios_base::fixed|std::ios_base::showpoint);
2251 }
2252 
2253 namespace detail {
2254 
2255 template <class tag, class A1, class A2, class A3, class A4>
2256 inline std::ostream& operator<<(std::ostream& os, const expression<tag, A1, A2, A3, A4>& r)
2257 {
2258    using value_type = typename expression<tag, A1, A2, A3, A4>::result_type;
2259    value_type                                                    temp(r);
2260    return os << temp;
2261 }
2262 //
2263 // What follows is the input streaming code: this is not "proper" iostream code at all
2264 // but that's fiendishly hard to write when dealing with multiple backends all
2265 // with different requirements... yes we could deligate this to the backend author...
2266 // but we really want backends to be EASY to write!
2267 // For now just pull in all the characters that could possibly form the number
2268 // and let the backend's string parser make use of it.  This fixes most use cases
2269 // including CSV type formats such as those used by the Random lib.
2270 //
2271 inline std::string read_string_while(std::istream& is, std::string const& permitted_chars)
2272 {
2273    std::ios_base::iostate     state = std::ios_base::goodbit;
2274    const std::istream::sentry sentry_check(is);
2275    std::string                result;
2276 
2277    if (sentry_check)
2278    {
2279       int c = is.rdbuf()->sgetc();
2280 
2281       for (;; c = is.rdbuf()->snextc())
2282          if (std::istream::traits_type::eq_int_type(std::istream::traits_type::eof(), c))
2283          { // end of file:
2284             state |= std::ios_base::eofbit;
2285             break;
2286          }
2287          else if (permitted_chars.find_first_of(std::istream::traits_type::to_char_type(c)) == std::string::npos)
2288          {
2289             // Invalid numeric character, stop reading:
2290             //is.rdbuf()->sputbackc(static_cast<char>(c));
2291             break;
2292          }
2293          else
2294          {
2295             result.append(1, std::istream::traits_type::to_char_type(c));
2296          }
2297    }
2298 
2299    if (!result.size())
2300       state |= std::ios_base::failbit;
2301    is.setstate(state);
2302    return result;
2303 }
2304 
2305 } // namespace detail
2306 
2307 template <class Backend, expression_template_option ExpressionTemplates>
2308 inline std::istream& operator>>(std::istream& is, number<Backend, ExpressionTemplates>& r)
2309 {
2310    bool        hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
2311    bool        oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
2312    std::string s;
2313    switch (boost::multiprecision::number_category<number<Backend, ExpressionTemplates> >::value)
2314    {
2315    case boost::multiprecision::number_kind_integer:
2316       if (oct_format)
2317          s = detail::read_string_while(is, "+-01234567");
2318       else if (hex_format)
2319          s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789");
2320       else
2321          s = detail::read_string_while(is, "+-0123456789");
2322       break;
2323    case boost::multiprecision::number_kind_rational:
2324       if (oct_format)
2325          s = detail::read_string_while(is, "+-01234567/");
2326       else if (hex_format)
2327          s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789/");
2328       else
2329          s = detail::read_string_while(is, "+-0123456789/");
2330       break;
2331    case boost::multiprecision::number_kind_floating_point:
2332       BOOST_IF_CONSTEXPR(std::is_same<number<Backend, ExpressionTemplates>, typename number<Backend, ExpressionTemplates>::value_type>::value)
2333          s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
2334       else
2335          // Interval:
2336          s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY{,}");
2337       break;
2338    case boost::multiprecision::number_kind_complex:
2339       s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY,()");
2340       break;
2341    default:
2342       is >> s;
2343    }
2344    if (s.size())
2345    {
2346       if (hex_format && (number_category<Backend>::value == number_kind_integer) && ((s[0] != '0') || (s[1] != 'x')))
2347          s.insert(s.find_first_not_of("+-"), "0x");
2348       if (oct_format && (number_category<Backend>::value == number_kind_integer) && (s[0] != '0'))
2349          s.insert(s.find_first_not_of("+-"), "0");
2350       r.assign(s);
2351    }
2352    else if (!is.fail())
2353       is.setstate(std::istream::failbit);
2354    return is;
2355 }
2356 
2357 template <class Backend, expression_template_option ExpressionTemplates>
2358 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b)
2359     noexcept(noexcept(std::declval<number<Backend, ExpressionTemplates>&>() = std::declval<number<Backend, ExpressionTemplates>&>()))
2360 {
2361    a.swap(b);
2362 }
2363 //
2364 // Boost.Hash support, just call hash_value for the backend, which may or may not be supported:
2365 //
2366 template <class Backend, expression_template_option ExpressionTemplates>
2367 inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const number<Backend, ExpressionTemplates>& val)
2368 {
2369    return hash_value(val.backend());
2370 }
2371 
2372 namespace detail {
2373 
2374 BOOST_MP_FORCEINLINE bool istream_peek(std::istream& is, char& c, bool have_hex)
2375 {
2376    int i = is.peek();
2377    c = static_cast<char>(i);
2378    return (EOF != i) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')));
2379 }
2380 
2381 } // namespace detail
2382 
2383 } // namespace multiprecision
2384 
2385 template <class T>
2386 class rational;
2387 
2388 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2389 inline std::istream& operator>>(std::istream& is, rational<multiprecision::number<Backend, ExpressionTemplates> >& r)
2390 {
2391    std::string                                          s1;
2392    multiprecision::number<Backend, ExpressionTemplates> v1, v2;
2393    char                                                 c;
2394    bool                                                 have_hex   = false;
2395    bool                                                 hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
2396    bool                                                 oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
2397 
2398    while (multiprecision::detail::istream_peek(is, c, have_hex))
2399    {
2400       if (c == 'x' || c == 'X')
2401          have_hex = true;
2402       s1.append(1, c);
2403       is.get();
2404    }
2405    if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
2406       s1.insert(static_cast<std::string::size_type>(0), "0x");
2407    if (oct_format && (s1[0] != '0'))
2408       s1.insert(static_cast<std::string::size_type>(0), "0");
2409    v1.assign(s1);
2410    s1.erase();
2411    if (c == '/')
2412    {
2413       is.get();
2414       while (multiprecision::detail::istream_peek(is, c, have_hex))
2415       {
2416          if (c == 'x' || c == 'X')
2417             have_hex = true;
2418          s1.append(1, c);
2419          is.get();
2420       }
2421       if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
2422          s1.insert(static_cast<std::string::size_type>(0), "0x");
2423       if (oct_format && (s1[0] != '0'))
2424          s1.insert(static_cast<std::string::size_type>(0), "0");
2425       v2.assign(s1);
2426    }
2427    else
2428       v2 = 1;
2429    r.assign(v1, v2);
2430    return is;
2431 }
2432 
2433 template <class T, multiprecision::expression_template_option ExpressionTemplates>
2434 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> numerator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
2435 {
2436    return a.numerator();
2437 }
2438 
2439 template <class T, multiprecision::expression_template_option ExpressionTemplates>
2440 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> denominator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
2441 {
2442    return a.denominator();
2443 }
2444 
2445 template <class T, multiprecision::expression_template_option ExpressionTemplates>
2446 inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const rational<multiprecision::number<T, ExpressionTemplates> >& val)
2447 {
2448    std::size_t result = hash_value(val.numerator());
2449    boost::multiprecision::detail::hash_combine(result, hash_value(val.denominator()));
2450    return result;
2451 }
2452 
2453 namespace multiprecision {
2454 
2455 template <class I>
2456 struct component_type<boost::rational<I> >
2457 {
2458    using type = I;
2459 };
2460 
2461 } // namespace multiprecision
2462 
2463 #ifdef BOOST_MSVC
2464 #pragma warning(pop)
2465 #endif
2466 
2467 } // namespace boost
2468 
2469 namespace std {
2470 
2471 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
2472 struct hash<boost::multiprecision::number<Backend, ExpressionTemplates> >
2473 {
2474    BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::multiprecision::number<Backend, ExpressionTemplates>& val) const { return hash_value(val); }
2475 };
2476 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
2477 struct hash<boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> > >
2478 {
2479    BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> >& val) const
2480    {
2481       std::size_t result = hash_value(val.numerator());
2482       boost::multiprecision::detail::hash_combine(result, hash_value(val.denominator()));
2483       return result;
2484    }
2485 };
2486 
2487 } // namespace std
2488 
2489 #include <boost/multiprecision/detail/ublas_interop.hpp>
2490 
2491 #endif