1 ///////////////////////////////////////////////////////////////////////////////
2 //  Copyright 2011 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef BOOST_MATH_EXTENDED_REAL_HPP
7 #define BOOST_MATH_EXTENDED_REAL_HPP
8 
9 #include <boost/config.hpp>
10 #include <boost/cstdint.hpp>
11 #include <boost/mpl/max.hpp>
12 #include <boost/mpl/plus.hpp>
13 #include <boost/mpl/or.hpp>
14 #include <boost/mpl/find_if.hpp>
15 #include <boost/assert.hpp>
16 #include <boost/type_traits/remove_pointer.hpp>
17 #include <boost/type_traits/is_signed.hpp>
18 #include <boost/type_traits/is_unsigned.hpp>
19 #include <boost/type_traits/is_floating_point.hpp>
20 #include <boost/type_traits/is_integral.hpp>
21 #include <boost/type_traits/is_complex.hpp>
22 #include <boost/type_traits/make_unsigned.hpp>
23 #include <boost/type_traits/is_convertible.hpp>
24 #include <boost/throw_exception.hpp>
25 #include <boost/multiprecision/detail/precision.hpp>
26 #include <boost/multiprecision/detail/generic_interconvert.hpp>
27 #include <boost/multiprecision/detail/number_compare.hpp>
28 #include <boost/multiprecision/traits/is_restricted_conversion.hpp>
29 #include <boost/container_hash/hash.hpp>
30 #include <istream> // stream operators
31 #include <cstdio>  // EOF
32 #include <cctype>  // isspace
33 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
34 #include <string_view>
35 #endif
36 
37 namespace boost {
38 namespace multiprecision {
39 
40 #ifdef BOOST_MSVC
41 // warning C4127: conditional expression is constant
42 // warning C4714: function marked as __forceinline not inlined
43 #pragma warning(push)
44 #pragma warning(disable : 4127 4714 6326)
45 #endif
46 
47 template <class Backend, expression_template_option ExpressionTemplates>
48 class number
49 {
50    typedef number<Backend, ExpressionTemplates> self_type;
51 
52  public:
53    typedef Backend                                  backend_type;
54    typedef typename component_type<self_type>::type value_type;
number()55    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number() BOOST_MP_NOEXCEPT_IF(noexcept(Backend())) {}
number(const number & e)56    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e) BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(e.m_backend) {}
57    template <class V>
number(const V & v,typename boost::enable_if_c<(boost::is_arithmetic<V>::value||is_same<std::string,V>::value||is_convertible<V,const char * >::value)&&!is_convertible<typename detail::canonical<V,Backend>::type,Backend>::value &&!detail::is_restricted_conversion<typename detail::canonical<V,Backend>::type,Backend>::value &&!boost::is_same<V,__float128>::value>::type * =0)58    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v, typename boost::enable_if_c<
59                                                (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value) && !is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
60 #ifdef BOOST_HAS_FLOAT128
61                                                && !boost::is_same<V, __float128>::value
62 #endif
63                                                >::type* = 0)
64    {
65       m_backend = canonical_value(v);
66    }
67    template <class V>
number(const V & v,typename boost::enable_if_c<is_convertible<typename detail::canonical<V,Backend>::type,Backend>::value &&!detail::is_restricted_conversion<typename detail::canonical<V,Backend>::type,Backend>::value>::type * =0)68    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c<
69                                                                is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = 0)
70 #ifndef BOOST_INTEL
71        BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
72 #endif
73        : m_backend(canonical_value(v))
74    {}
75    template <class V>
number(const V & v,unsigned digits10,typename boost::enable_if_c<(boost::is_arithmetic<V>::value||is_same<std::string,V>::value||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)&&!boost::is_same<V,__float128>::value>::type * =0)76    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, unsigned digits10, typename boost::enable_if_c<(boost::is_arithmetic<V>::value || is_same<std::string, V>::value || 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)
77 #ifdef BOOST_HAS_FLOAT128
78                                                                                                           && !boost::is_same<V, __float128>::value
79 #endif
80                                                                                                           >::type* = 0)
81        : m_backend(canonical_value(v), digits10)
82    {}
number(const number & e,unsigned digits10)83    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e, unsigned digits10)
84        BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend const&>(), std::declval<unsigned>())))
85        : m_backend(e.m_backend, digits10) {}
86    template <class V>
number(const V & v,typename boost::enable_if_c<(boost::is_arithmetic<V>::value||is_same<std::string,V>::value||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 * =0)87    explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v, typename boost::enable_if_c<
88                                                         (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || 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* = 0)
89        BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<typename detail::canonical<V, Backend>::type const&>()))
90    {
91       m_backend = canonical_value(v);
92    }
93    template <class V>
number(const V & v,typename boost::enable_if_c<detail::is_explicitly_convertible<typename detail::canonical<V,Backend>::type,Backend>::value && (detail::is_restricted_conversion<typename detail::canonical<V,Backend>::type,Backend>::value||!is_convertible<typename detail::canonical<V,Backend>::type,Backend>::value)>::type * =0)94    explicit BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c<
95                                                                         detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && (detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value || !is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value)>::type* = 0)
96        BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
97        : m_backend(canonical_value(v)) {}
98    template <class V>
number(const V & v,unsigned digits10,typename boost::enable_if_c<(boost::is_arithmetic<V>::value||is_same<std::string,V>::value||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 * =0)99    explicit BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, unsigned digits10, typename boost::enable_if_c<(boost::is_arithmetic<V>::value || is_same<std::string, V>::value || 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* = 0)
100        : m_backend(canonical_value(v), digits10) {}
101 
102    template <expression_template_option ET>
number(const number<Backend,ET> & val)103    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number<Backend, ET>& val)
104        BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(val.backend()) {}
105 
106    template <class Other, expression_template_option ET>
number(const number<Other,ET> & val,typename boost::enable_if_c<(boost::is_convertible<Other,Backend>::value &&!detail::is_restricted_conversion<Other,Backend>::value)>::type * =0)107    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val,
108                                typename boost::enable_if_c<(boost::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0)
109        BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Other const&>())))
110        : m_backend(val.backend()) {}
111 
112    template <class Other, expression_template_option ET>
number(const number<Other,ET> & val,typename boost::enable_if_c<(!detail::is_explicitly_convertible<Other,Backend>::value)>::type * =0)113    explicit BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename boost::enable_if_c<
114                                                      (!detail::is_explicitly_convertible<Other, Backend>::value)>::type* = 0)
115    {
116       //
117       // Attempt a generic interconvertion:
118       //
119       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard_1(val);
120       detail::scoped_default_precision<number<Other, ET> >                    precision_guard_2(val);
121       using detail::generic_interconvert;
122       generic_interconvert(backend(), val.backend(), number_category<Backend>(), number_category<Other>());
123    }
124    template <class Other, expression_template_option ET>
number(const number<Other,ET> & val,typename boost::enable_if_c<(detail::is_explicitly_convertible<Other,Backend>::value && (detail::is_restricted_conversion<Other,Backend>::value||!boost::is_convertible<Other,Backend>::value))>::type * =0)125    explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename boost::enable_if_c<
126                                                                           (detail::is_explicitly_convertible<Other, Backend>::value && (detail::is_restricted_conversion<Other, Backend>::value || !boost::is_convertible<Other, Backend>::value))>::type* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Other const&>())))
127        : m_backend(val.backend()) {}
128 
129    template <class V, class U>
number(const V & v1,const U & v2,typename boost::enable_if_c<(is_convertible<V,value_type>::value && is_convertible<U,value_type>::value &&!is_same<typename component_type<self_type>::type,self_type>::value)>::type * =0)130    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
131                                typename boost::enable_if_c<(is_convertible<V, value_type>::value && is_convertible<U, value_type>::value && !is_same<typename component_type<self_type>::type, self_type>::value)>::type* = 0)
132    {
133       using default_ops::assign_components;
134       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
135       assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
136    }
137    template <class V, class U>
number(const V & v1,const U & v2,typename boost::enable_if_c<(is_constructible<value_type,V>::value||is_convertible<V,std::string>::value)&& (is_constructible<value_type,U>::value||is_convertible<U,std::string>::value)&&!is_same<typename component_type<self_type>::type,self_type>::value &&!is_same<V,self_type>::value &&!(is_convertible<V,value_type>::value && is_convertible<U,value_type>::value)>::type * =0)138    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
139                                         typename boost::enable_if_c<
140                                             (is_constructible<value_type, V>::value || is_convertible<V, std::string>::value) && (is_constructible<value_type, U>::value || is_convertible<U, std::string>::value) && !is_same<typename component_type<self_type>::type, self_type>::value && !is_same<V, self_type>::value && !(is_convertible<V, value_type>::value && is_convertible<U, value_type>::value)>::type* = 0)
141    {
142       using default_ops::assign_components;
143       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
144       assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
145    }
146 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
147    //
148    // Support for new types in C++17
149    //
150    template <class Traits>
number(const std::basic_string_view<char,Traits> & view)151    explicit inline BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& view)
152    {
153       using default_ops::assign_from_string_view;
154       assign_from_string_view(this->backend(), view);
155    }
156    template <class Traits>
number(const std::basic_string_view<char,Traits> & view_x,const std::basic_string_view<char,Traits> & view_y)157    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)
158    {
159       using default_ops::assign_from_string_view;
160       assign_from_string_view(this->backend(), view_x, view_y);
161    }
162    template <class Traits>
number(const std::basic_string_view<char,Traits> & v,unsigned digits10)163    explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& v, unsigned digits10)
164        : m_backend(canonical_value(v), digits10) {}
165    template <class Traits>
assign(const std::basic_string_view<char,Traits> & view)166    BOOST_MP_CXX14_CONSTEXPR number& assign(const std::basic_string_view<char, Traits>& view)
167    {
168       using default_ops::assign_from_string_view;
169       assign_from_string_view(this->backend(), view);
170       return *this;
171    }
172 #endif
173 
174    template <class V, class U>
number(const V & v1,const U & v2,unsigned digits10,typename boost::enable_if_c<(is_convertible<V,value_type>::value && is_convertible<U,value_type>::value &&!is_same<typename component_type<self_type>::type,self_type>::value)>::type * =0)175    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
176                                typename boost::enable_if_c<(is_convertible<V, value_type>::value && is_convertible<U, value_type>::value && !is_same<typename component_type<self_type>::type, self_type>::value)>::type* = 0)
177        : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)), digits10)
178    {}
179    template <class V, class U>
number(const V & v1,const U & v2,unsigned digits10,typename boost::enable_if_c<((is_constructible<value_type,V>::value||is_convertible<V,std::string>::value)&& (is_constructible<value_type,U>::value||is_convertible<U,std::string>::value)&&!is_same<typename component_type<self_type>::type,self_type>::value)&&!(is_convertible<V,value_type>::value && is_convertible<U,value_type>::value)>::type * =0)180    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
181                                         typename boost::enable_if_c<((is_constructible<value_type, V>::value || is_convertible<V, std::string>::value) && (is_constructible<value_type, U>::value || is_convertible<U, std::string>::value) && !is_same<typename component_type<self_type>::type, self_type>::value) && !(is_convertible<V, value_type>::value && is_convertible<U, value_type>::value)>::type* = 0)
182        : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)), digits10) {}
183 
184    template <class Other, expression_template_option ET>
number(const number<Other,ET> & v1,const number<Other,ET> & v2,typename boost::enable_if_c<boost::is_convertible<Other,Backend>::value>::type * =0)185    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& v1, const number<Other, ET>& v2, typename boost::enable_if_c<boost::is_convertible<Other, Backend>::value>::type* = 0)
186    {
187       using default_ops::assign_components;
188       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
189       assign_components(m_backend, v1.backend(), v2.backend());
190    }
191 
192    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
operator =(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)193    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<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)
194    {
195       typedef mpl::bool_<is_same<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value> tag_type;
196       detail::scoped_default_precision<number<Backend, ExpressionTemplates> >                                       precision_guard(e);
197       //
198       // If the current precision of *this differs from that of expression e, then we
199       // create a temporary (which will have the correct precision thanks to precision_guard)
200       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
201       // which causes this code to be eliminated in the common case that this type is
202       // not actually variable precision.  Pre C++17 this code should still be mostly
203       // optimised away, but we can't prevent instantiation of the dead code leading
204       // to longer build and possibly link times.
205       //
206       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
207       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
208       {
209          number t(e);
210          return *this = BOOST_MP_MOVE(t);
211       }
212       do_assign(e, tag_type());
213       return *this;
214    }
215    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
assign(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)216    BOOST_MP_CXX14_CONSTEXPR number& assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
217    {
218       typedef mpl::bool_<is_same<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value> tag_type;
219       detail::scoped_default_precision<number<Backend, ExpressionTemplates> >                                       precision_guard(e);
220       //
221       // If the current precision of *this differs from that of expression e, then we
222       // create a temporary (which will have the correct precision thanks to precision_guard)
223       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
224       // which causes this code to be eliminated in the common case that this type is
225       // not actually variable precision.  Pre C++17 this code should still be mostly
226       // optimised away, but we can't prevent instantiation of the dead code leading
227       // to longer build and possibly link times.
228       //
229       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
230       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
231       {
232          number t;
233          t.assign(e);
234          return *this = BOOST_MP_MOVE(t);
235       }
236       do_assign(e, tag_type());
237       return *this;
238    }
239 
operator =(const number & e)240    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(const number& e)
241        BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<Backend const&>()))
242    {
243       m_backend = e.m_backend;
244       return *this;
245    }
246 
247    template <class V>
248    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator =(const V & v)249    operator=(const V& v)
250        BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
251    {
252       m_backend = canonical_value(v);
253       return *this;
254    }
255    template <class V>
assign(const V & v)256    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v)
257        BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
258    {
259       m_backend = canonical_value(v);
260       return *this;
261    }
262    template <class V>
assign(const V & v,unsigned digits10)263    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v, unsigned digits10)
264        BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
265    {
266       number t(v, digits10);
267       return *this = t;
268    }
269    template <class Other, expression_template_option ET>
270    BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if<boost::multiprecision::detail::is_explicitly_convertible<Other, Backend>, number<Backend, ExpressionTemplates>&>::type
assign(const number<Other,ET> & v)271    assign(const number<Other, ET>& v)
272    {
273       //
274       // Attempt a generic interconvertion:
275       //
276       using detail::generic_interconvert;
277       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v);
278       detail::scoped_default_precision<number<Other, ET> >                    precision_guard2(v);
279       //
280       // If the current precision of *this differs from that of value v, then we
281       // create a temporary (which will have the correct precision thanks to precision_guard)
282       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
283       // which causes this code to be eliminated in the common case that this type is
284       // not actually variable precision.  Pre C++17 this code should still be mostly
285       // optimised away, but we can't prevent instantiation of the dead code leading
286       // to longer build and possibly link times.
287       //
288       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
289       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
290       {
291          number t(v);
292          return *this = BOOST_MP_MOVE(t);
293       }
294       generic_interconvert(backend(), v.backend(), number_category<Backend>(), number_category<Other>());
295       return *this;
296    }
297 
298    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
number(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e,typename boost::enable_if_c<is_convertible<typename detail::expression<tag,Arg1,Arg2,Arg3,Arg4>::result_type,self_type>::value>::type * =0)299    BOOST_MP_CXX14_CONSTEXPR number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, typename boost::enable_if_c<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = 0)
300    {
301       //
302       // No preicsion guard here, we already have one in operator=
303       //
304       *this = e;
305    }
306    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
number(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e,typename boost::enable_if_c<!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 * =0)307    explicit BOOST_MP_CXX14_CONSTEXPR number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e,
308                    typename boost::enable_if_c<!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* = 0)
309    {
310       //
311       // No precision guard as assign has one already:
312       //
313       assign(e);
314    }
315 
316 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
number(number && r)317    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(number&& r)
318        BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend>())))
319        : m_backend(static_cast<Backend&&>(r.m_backend))
320    {}
operator =(number && r)321    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(number&& r) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<Backend>()))
322    {
323       m_backend = static_cast<Backend&&>(r.m_backend);
324       return *this;
325    }
326 #endif
327 
operator +=(const self_type & val)328    BOOST_MP_CXX14_CONSTEXPR number& operator+=(const self_type& val)
329    {
330       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
331       //
332       // If the current precision of *this differs from that of expression e, then we
333       // create a temporary (which will have the correct precision thanks to precision_guard)
334       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
335       // which causes this code to be eliminated in the common case that this type is
336       // not actually variable precision.  Pre C++17 this code should still be mostly
337       // optimised away, but we can't prevent instantiation of the dead code leading
338       // to longer build and possibly link times.
339       //
340       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
341       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
342       {
343          number t(*this + val);
344          return *this = BOOST_MP_MOVE(t);
345       }
346       do_add(detail::expression<detail::terminal, self_type>(val), detail::terminal());
347       return *this;
348    }
349 
350    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
operator +=(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)351    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<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)
352    {
353       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
354       // Create a copy if e contains this, but not if we're just doing a
355       //    x += x
356       if ((contains_self(e) && !is_self(e)))
357       {
358          self_type temp(e);
359          do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
360       }
361       else
362       {
363          do_add(e, tag());
364       }
365       return *this;
366    }
367 
368    template <class Arg1, class Arg2, class Arg3, class Arg4>
operator +=(const detail::expression<detail::multiply_immediates,Arg1,Arg2,Arg3,Arg4> & e)369    BOOST_MP_CXX14_CONSTEXPR number& operator+=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
370    {
371       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
372       //
373       // If the current precision of *this differs from that of expression e, then we
374       // create a temporary (which will have the correct precision thanks to precision_guard)
375       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
376       // which causes this code to be eliminated in the common case that this type is
377       // not actually variable precision.  Pre C++17 this code should still be mostly
378       // optimised away, but we can't prevent instantiation of the dead code leading
379       // to longer build and possibly link times.
380       //
381       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
382       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
383       {
384          number t(*this + e);
385          return *this = BOOST_MP_MOVE(t);
386       }
387       //
388       // Fused multiply-add:
389       //
390       using default_ops::eval_multiply_add;
391       eval_multiply_add(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
392       return *this;
393    }
394 
395    template <class V>
396    typename boost::enable_if_c<boost::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator +=(const V & v)397       BOOST_MP_CXX14_CONSTEXPR operator+=(const V& v)
398    {
399       using default_ops::eval_add;
400       eval_add(m_backend, canonical_value(v));
401       return *this;
402    }
403 
operator -=(const self_type & val)404    BOOST_MP_CXX14_CONSTEXPR number& operator-=(const self_type& val)
405    {
406       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
407       //
408       // If the current precision of *this differs from that of expression e, then we
409       // create a temporary (which will have the correct precision thanks to precision_guard)
410       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
411       // which causes this code to be eliminated in the common case that this type is
412       // not actually variable precision.  Pre C++17 this code should still be mostly
413       // optimised away, but we can't prevent instantiation of the dead code leading
414       // to longer build and possibly link times.
415       //
416       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
417       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
418       {
419          number t(*this - val);
420          return *this = BOOST_MP_MOVE(t);
421       }
422       do_subtract(detail::expression<detail::terminal, self_type>(val), detail::terminal());
423       return *this;
424    }
425 
426    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
operator -=(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)427    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<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)
428    {
429       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
430       // Create a copy if e contains this:
431       if (contains_self(e))
432       {
433          self_type temp(e);
434          do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
435       }
436       else
437       {
438          do_subtract(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
439       }
440       return *this;
441    }
442 
443    template <class V>
444    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<boost::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator -=(const V & v)445    operator-=(const V& v)
446    {
447       using default_ops::eval_subtract;
448       eval_subtract(m_backend, canonical_value(v));
449       return *this;
450    }
451 
452    template <class Arg1, class Arg2, class Arg3, class Arg4>
operator -=(const detail::expression<detail::multiply_immediates,Arg1,Arg2,Arg3,Arg4> & e)453    BOOST_MP_CXX14_CONSTEXPR number& operator-=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
454    {
455       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
456       //
457       // If the current precision of *this differs from that of expression e, then we
458       // create a temporary (which will have the correct precision thanks to precision_guard)
459       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
460       // which causes this code to be eliminated in the common case that this type is
461       // not actually variable precision.  Pre C++17 this code should still be mostly
462       // optimised away, but we can't prevent instantiation of the dead code leading
463       // to longer build and possibly link times.
464       //
465       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
466       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
467       {
468          number t(*this - e);
469          return *this = BOOST_MP_MOVE(t);
470       }
471       //
472       // Fused multiply-subtract:
473       //
474       using default_ops::eval_multiply_subtract;
475       eval_multiply_subtract(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
476       return *this;
477    }
478 
operator *=(const self_type & e)479    BOOST_MP_CXX14_CONSTEXPR number& operator*=(const self_type& e)
480    {
481       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
482       //
483       // If the current precision of *this differs from that of expression e, then we
484       // create a temporary (which will have the correct precision thanks to precision_guard)
485       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
486       // which causes this code to be eliminated in the common case that this type is
487       // not actually variable precision.  Pre C++17 this code should still be mostly
488       // optimised away, but we can't prevent instantiation of the dead code leading
489       // to longer build and possibly link times.
490       //
491       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
492       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
493       {
494          number t(*this * e);
495          return *this = BOOST_MP_MOVE(t);
496       }
497       do_multiplies(detail::expression<detail::terminal, self_type>(e), detail::terminal());
498       return *this;
499    }
500 
501    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
operator *=(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)502    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<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)
503    {
504       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
505       // Create a temporary if the RHS references *this, but not
506       // if we're just doing an   x *= x;
507       if ((contains_self(e) && !is_self(e)))
508       {
509          self_type temp(e);
510          do_multiplies(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
511       }
512       else
513       {
514          do_multiplies(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
515       }
516       return *this;
517    }
518 
519    template <class V>
520    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<boost::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator *=(const V & v)521    operator*=(const V& v)
522    {
523       using default_ops::eval_multiply;
524       eval_multiply(m_backend, canonical_value(v));
525       return *this;
526    }
527 
operator %=(const self_type & e)528    BOOST_MP_CXX14_CONSTEXPR number& operator%=(const self_type& e)
529    {
530       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
531       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
532       //
533       // If the current precision of *this differs from that of expression e, then we
534       // create a temporary (which will have the correct precision thanks to precision_guard)
535       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
536       // which causes this code to be eliminated in the common case that this type is
537       // not actually variable precision.  Pre C++17 this code should still be mostly
538       // optimised away, but we can't prevent instantiation of the dead code leading
539       // to longer build and possibly link times.
540       //
541       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
542       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
543       {
544          number t(*this % e);
545          return *this = BOOST_MP_MOVE(t);
546       }
547       do_modulus(detail::expression<detail::terminal, self_type>(e), detail::terminal());
548       return *this;
549    }
550    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
operator %=(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)551    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<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)
552    {
553       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
554       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
555       // Create a temporary if the RHS references *this:
556       if (contains_self(e))
557       {
558          self_type temp(e);
559          do_modulus(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
560       }
561       else
562       {
563          do_modulus(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
564       }
565       return *this;
566    }
567    template <class V>
568    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<boost::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator %=(const V & v)569    operator%=(const V& v)
570    {
571       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
572       using default_ops::eval_modulus;
573       eval_modulus(m_backend, canonical_value(v));
574       return *this;
575    }
576 
577    //
578    // These operators are *not* proto-ized.
579    // The issue is that the increment/decrement must happen
580    // even if the result of the operator *is never used*.
581    // Possibly we could modify our expression wrapper to
582    // execute the increment/decrement on destruction, but
583    // correct implementation will be tricky, so defered for now...
584    //
operator ++()585    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator++()
586    {
587       using default_ops::eval_increment;
588       eval_increment(m_backend);
589       return *this;
590    }
591 
operator --()592    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator--()
593    {
594       using default_ops::eval_decrement;
595       eval_decrement(m_backend);
596       return *this;
597    }
598 
operator ++(int)599    inline BOOST_MP_CXX14_CONSTEXPR number operator++(int)
600    {
601       using default_ops::eval_increment;
602       self_type temp(*this);
603       eval_increment(m_backend);
604       return temp;
605    }
606 
operator --(int)607    inline BOOST_MP_CXX14_CONSTEXPR number operator--(int)
608    {
609       using default_ops::eval_decrement;
610       self_type temp(*this);
611       eval_decrement(m_backend);
612       return temp;
613    }
614 
615    template <class V>
operator <<=(V val)616    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<is_integral<V>::value, number&>::type operator<<=(V val)
617    {
618       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The left-shift operation is only valid for integer types");
619       detail::check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), mpl::bool_<is_signed<V>::value>());
620       eval_left_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
621       return *this;
622    }
623 
624    template <class V>
operator >>=(V val)625    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<is_integral<V>::value, number&>::type operator>>=(V val)
626    {
627       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The right-shift operation is only valid for integer types");
628       detail::check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), mpl::bool_<is_signed<V>::value>());
629       eval_right_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
630       return *this;
631    }
632 
operator /=(const self_type & e)633    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator/=(const self_type& e)
634    {
635       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
636       //
637       // If the current precision of *this differs from that of expression e, then we
638       // create a temporary (which will have the correct precision thanks to precision_guard)
639       // and then move the result into *this.  In C++17 we add a leading "if constexpr"
640       // which causes this code to be eliminated in the common case that this type is
641       // not actually variable precision.  Pre C++17 this code should still be mostly
642       // optimised away, but we can't prevent instantiation of the dead code leading
643       // to longer build and possibly link times.
644       //
645       BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
646       if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
647       {
648          number t(*this / e);
649          return *this = BOOST_MP_MOVE(t);
650       }
651       do_divide(detail::expression<detail::terminal, self_type>(e), detail::terminal());
652       return *this;
653    }
654 
655    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
operator /=(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)656    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<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)
657    {
658       detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
659       // Create a temporary if the RHS references *this:
660       if (contains_self(e))
661       {
662          self_type temp(e);
663          do_divide(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
664       }
665       else
666       {
667          do_divide(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
668       }
669       return *this;
670    }
671 
672    template <class V>
673    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<boost::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator /=(const V & v)674    operator/=(const V& v)
675    {
676       using default_ops::eval_divide;
677       eval_divide(m_backend, canonical_value(v));
678       return *this;
679    }
680 
operator &=(const self_type & e)681    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator&=(const self_type& e)
682    {
683       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
684       do_bitwise_and(detail::expression<detail::terminal, self_type>(e), detail::terminal());
685       return *this;
686    }
687 
688    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
operator &=(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)689    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<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)
690    {
691       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
692       // Create a temporary if the RHS references *this, but not
693       // if we're just doing an   x &= x;
694       if (contains_self(e) && !is_self(e))
695       {
696          self_type temp(e);
697          do_bitwise_and(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
698       }
699       else
700       {
701          do_bitwise_and(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
702       }
703       return *this;
704    }
705 
706    template <class V>
707    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<boost::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator &=(const V & v)708    operator&=(const V& v)
709    {
710       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
711       using default_ops::eval_bitwise_and;
712       eval_bitwise_and(m_backend, canonical_value(v));
713       return *this;
714    }
715 
operator |=(const self_type & e)716    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator|=(const self_type& e)
717    {
718       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
719       do_bitwise_or(detail::expression<detail::terminal, self_type>(e), detail::terminal());
720       return *this;
721    }
722 
723    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
operator |=(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)724    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<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)
725    {
726       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
727       // Create a temporary if the RHS references *this, but not
728       // if we're just doing an   x |= x;
729       if (contains_self(e) && !is_self(e))
730       {
731          self_type temp(e);
732          do_bitwise_or(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
733       }
734       else
735       {
736          do_bitwise_or(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
737       }
738       return *this;
739    }
740 
741    template <class V>
742    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<boost::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator |=(const V & v)743    operator|=(const V& v)
744    {
745       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
746       using default_ops::eval_bitwise_or;
747       eval_bitwise_or(m_backend, canonical_value(v));
748       return *this;
749    }
750 
operator ^=(const self_type & e)751    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator^=(const self_type& e)
752    {
753       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
754       do_bitwise_xor(detail::expression<detail::terminal, self_type>(e), detail::terminal());
755       return *this;
756    }
757 
758    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
operator ^=(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e)759    BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<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)
760    {
761       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
762       if (contains_self(e))
763       {
764          self_type temp(e);
765          do_bitwise_xor(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
766       }
767       else
768       {
769          do_bitwise_xor(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
770       }
771       return *this;
772    }
773 
774    template <class V>
775    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<boost::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
operator ^=(const V & v)776    operator^=(const V& v)
777    {
778       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
779       using default_ops::eval_bitwise_xor;
780       eval_bitwise_xor(m_backend, canonical_value(v));
781       return *this;
782    }
783    //
784    // swap:
785    //
swap(self_type & other)786    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(self_type& other) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend>().swap(std::declval<Backend&>())))
787    {
788       m_backend.swap(other.backend());
789    }
790    //
791    // Zero and sign:
792    //
is_zero() const793    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool is_zero() const
794    {
795       using default_ops::eval_is_zero;
796       return eval_is_zero(m_backend);
797    }
sign() const798    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int sign() const
799    {
800       using default_ops::eval_get_sign;
801       return eval_get_sign(m_backend);
802    }
803    //
804    // String conversion functions:
805    //
str(std::streamsize digits=0,std::ios_base::fmtflags f=std::ios_base::fmtflags (0)) const806    std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0)) const
807    {
808       return m_backend.str(digits, f);
809    }
810    template <class Archive>
serialize(Archive & ar,const unsigned int)811    void serialize(Archive& ar, const unsigned int /*version*/)
812    {
813       ar& boost::make_nvp("backend", m_backend);
814    }
815 
816  private:
817    template <class T>
convert_to_imp(T * result) const818    BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(T* result) const
819    {
820       using default_ops::eval_convert_to;
821       eval_convert_to(result, m_backend);
822    }
823    template <class B2, expression_template_option ET>
convert_to_imp(number<B2,ET> * result) const824    BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(number<B2, ET>* result) const
825    {
826       result->assign(*this);
827    }
convert_to_imp(std::string * result) const828    BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(std::string* result) const
829    {
830       *result = this->str();
831    }
832 
833  public:
834    template <class T>
convert_to() const835    BOOST_MP_CXX14_CONSTEXPR T convert_to() const
836    {
837       T result = T();
838       convert_to_imp(&result);
839       return result;
840    }
841    //
842    // Use in boolean context, and explicit conversion operators:
843    //
844 #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
845 #if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
846    //
847    // Horrible workaround for gcc-4.6.x which always prefers the template
848    // operator bool() rather than the non-template operator when converting to
849    // an arithmetic type:
850    //
851    template <class T, typename boost::enable_if_c<is_same<T, bool>::value, int>::type = 0>
operator T() const852    explicit operator T() const
853    {
854       using default_ops::eval_is_zero;
855       return !eval_is_zero(backend());
856    }
857    template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value, int>::type = 0>
operator T() const858    explicit operator T() const
859    {
860       return this->template convert_to<T>();
861    }
862 #else
863 #if BOOST_WORKAROUND(BOOST_MSVC, < 1900) || (defined(__apple_build_version__) && BOOST_WORKAROUND(__clang_major__, < 9))
864    template <class T>
865 #else
866    template <class T, class = typename boost::disable_if_c<boost::is_constructible<T, self_type const&>::value || !boost::is_default_constructible<T>::value || (!boost::is_arithmetic<T>::value && !boost::is_complex<T>::value), T>::type>
867 #endif
operator T() const868    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
869    {
870       return this->template convert_to<T>();
871    }
operator bool() const872    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
873    {
874       return !is_zero();
875    }
876 #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
operator void() const877    BOOST_MP_FORCEINLINE explicit operator void() const
878    {}
879 #endif
880 #endif
881 #else
882    typedef bool (self_type::*unmentionable_type)() const;
883 
operator unmentionable_type() const884    BOOST_MP_FORCEINLINE operator unmentionable_type() const
885    {
886       return is_zero() ? 0 : &self_type::is_zero;
887    }
888 #endif
889    //
890    // Default precision:
891    //
default_precision()892    static BOOST_MP_CXX14_CONSTEXPR unsigned default_precision() BOOST_NOEXCEPT
893    {
894       return Backend::default_precision();
895    }
default_precision(unsigned digits10)896    static BOOST_MP_CXX14_CONSTEXPR void default_precision(unsigned digits10)
897    {
898       Backend::default_precision(digits10);
899    }
precision() const900    BOOST_MP_CXX14_CONSTEXPR unsigned precision() const BOOST_NOEXCEPT
901    {
902       return m_backend.precision();
903    }
precision(unsigned digits10)904    BOOST_MP_CXX14_CONSTEXPR void precision(unsigned digits10)
905    {
906       m_backend.precision(digits10);
907    }
908    //
909    // Comparison:
910    //
compare(const number<Backend,ExpressionTemplates> & o) const911    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int compare(const number<Backend, ExpressionTemplates>& o) const
912        BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend>().compare(std::declval<Backend>())))
913    {
914       return m_backend.compare(o.m_backend);
915    }
916    template <class V>
compare(const V & o) const917    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<is_arithmetic<V>::value && (number_category<Backend>::value != number_kind_complex), int>::type compare(const V& o) const
918    {
919       using default_ops::eval_get_sign;
920       if (o == 0)
921          return eval_get_sign(m_backend);
922       return m_backend.compare(canonical_value(o));
923    }
924    template <class V>
compare(const V & o) const925    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<is_arithmetic<V>::value && (number_category<Backend>::value == number_kind_complex), int>::type compare(const V& o) const
926    {
927       using default_ops::eval_get_sign;
928       return m_backend.compare(canonical_value(o));
929    }
930    //
931    // Direct access to the underlying backend:
932    //
933 #if !(defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || defined(BOOST_NO_CXX11_REF_QUALIFIERS) || BOOST_WORKAROUND(BOOST_GCC, < 50000))
backend()934    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend& backend() & BOOST_NOEXCEPT
935    {
936       return m_backend;
937    }
backend() const938    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& backend() const& BOOST_NOEXCEPT { return m_backend; }
backend()939    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend&& backend() && BOOST_NOEXCEPT { return static_cast<Backend&&>(m_backend); }
backend() const940    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend const&& backend() const&& BOOST_NOEXCEPT { return static_cast<Backend const&&>(m_backend); }
941 #else
backend()942    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend& backend() BOOST_NOEXCEPT
943    {
944       return m_backend;
945    }
backend() const946    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& backend() const BOOST_NOEXCEPT { return m_backend; }
947 #endif
948    //
949    // Complex number real and imag:
950    //
951    BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
real() const952    real() const
953    {
954       using default_ops::eval_real;
955       detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
956       typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type                                   result;
957       eval_real(result.backend(), backend());
958       return result;
959    }
960    BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
imag() const961    imag() const
962    {
963       using default_ops::eval_imag;
964       detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
965       typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type                                   result;
966       eval_imag(result.backend(), backend());
967       return result;
968    }
969    template <class T>
real(const T & val)970    inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<boost::is_convertible<T, self_type>::value, self_type&>::type real(const T& val)
971    {
972       using default_ops::eval_set_real;
973       eval_set_real(backend(), canonical_value(val));
974       return *this;
975    }
976    template <class T>
imag(const T & val)977    inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<boost::is_convertible<T, self_type>::value && number_category<self_type>::value == number_kind_complex, self_type&>::type imag(const T& val)
978    {
979       using default_ops::eval_set_imag;
980       eval_set_imag(backend(), canonical_value(val));
981       return *this;
982    }
983 
984  private:
985    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
do_assign(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e,const mpl::true_ &)986    BOOST_MP_CXX14_CONSTEXPR void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const mpl::true_&)
987    {
988       do_assign(e, tag());
989    }
990    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
do_assign(const detail::expression<tag,Arg1,Arg2,Arg3,Arg4> & e,const mpl::false_ &)991    BOOST_MP_CXX14_CONSTEXPR void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const mpl::false_&)
992    {
993       // The result of the expression isn't the same type as this -
994       // create a temporary result and assign it to *this:
995       typedef typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type temp_type;
996       temp_type                                                                     t(e);
997       this->assign(t);
998    }
999 
1000    template <class Exp>
do_assign(const Exp & e,const detail::add_immediates &)1001    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::add_immediates&)
1002    {
1003       using default_ops::eval_add;
1004       boost::multiprecision::detail::maybe_promote_precision(this);
1005       eval_add(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1006    }
1007    template <class Exp>
do_assign(const Exp & e,const detail::subtract_immediates &)1008    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::subtract_immediates&)
1009    {
1010       using default_ops::eval_subtract;
1011       boost::multiprecision::detail::maybe_promote_precision(this);
1012       eval_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1013    }
1014    template <class Exp>
do_assign(const Exp & e,const detail::multiply_immediates &)1015    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_immediates&)
1016    {
1017       using default_ops::eval_multiply;
1018       boost::multiprecision::detail::maybe_promote_precision(this);
1019       eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1020    }
1021    template <class Exp>
do_assign(const Exp & e,const detail::multiply_add &)1022    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_add&)
1023    {
1024       using default_ops::eval_multiply_add;
1025       boost::multiprecision::detail::maybe_promote_precision(this);
1026       eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
1027    }
1028    template <class Exp>
do_assign(const Exp & e,const detail::multiply_subtract &)1029    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_subtract&)
1030    {
1031       using default_ops::eval_multiply_subtract;
1032       boost::multiprecision::detail::maybe_promote_precision(this);
1033       eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
1034    }
1035 
1036    template <class Exp>
do_assign(const Exp & e,const detail::divide_immediates &)1037    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divide_immediates&)
1038    {
1039       using default_ops::eval_divide;
1040       boost::multiprecision::detail::maybe_promote_precision(this);
1041       eval_divide(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1042    }
1043 
1044    template <class Exp>
do_assign(const Exp & e,const detail::negate &)1045    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::negate&)
1046    {
1047       typedef typename Exp::left_type left_type;
1048       do_assign(e.left(), typename left_type::tag_type());
1049       m_backend.negate();
1050    }
1051    template <class Exp>
do_assign(const Exp & e,const detail::plus &)1052    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::plus&)
1053    {
1054       typedef typename Exp::left_type  left_type;
1055       typedef typename Exp::right_type right_type;
1056 
1057       BOOST_CONSTEXPR int const left_depth  = left_type::depth;
1058       BOOST_CONSTEXPR int const right_depth = right_type::depth;
1059 
1060       bool bl = contains_self(e.left());
1061       bool br = contains_self(e.right());
1062 
1063       if (bl && br)
1064       {
1065          self_type temp(e);
1066          temp.m_backend.swap(this->m_backend);
1067       }
1068       else if (bl && is_self(e.left()))
1069       {
1070          // Ignore the left node, it's *this, just add the right:
1071          do_add(e.right(), typename right_type::tag_type());
1072       }
1073       else if (br && is_self(e.right()))
1074       {
1075          // Ignore the right node, it's *this, just add the left:
1076          do_add(e.left(), typename left_type::tag_type());
1077       }
1078       else if (!br && (bl || (left_depth >= right_depth)))
1079       { // br is always false, but if bl is true we must take the this branch:
1080          do_assign(e.left(), typename left_type::tag_type());
1081          do_add(e.right(), typename right_type::tag_type());
1082       }
1083       else
1084       {
1085          do_assign(e.right(), typename right_type::tag_type());
1086          do_add(e.left(), typename left_type::tag_type());
1087       }
1088    }
1089    template <class Exp>
do_assign(const Exp & e,const detail::minus &)1090    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::minus&)
1091    {
1092       typedef typename Exp::left_type  left_type;
1093       typedef typename Exp::right_type right_type;
1094 
1095       BOOST_CONSTEXPR int const left_depth  = left_type::depth;
1096       BOOST_CONSTEXPR int const right_depth = right_type::depth;
1097 
1098       bool bl = contains_self(e.left());
1099       bool br = contains_self(e.right());
1100 
1101       if (bl && br)
1102       {
1103          self_type temp(e);
1104          temp.m_backend.swap(this->m_backend);
1105       }
1106       else if (bl && is_self(e.left()))
1107       {
1108          // Ignore the left node, it's *this, just subtract the right:
1109          do_subtract(e.right(), typename right_type::tag_type());
1110       }
1111       else if (br && is_self(e.right()))
1112       {
1113          // Ignore the right node, it's *this, just subtract the left and negate the result:
1114          do_subtract(e.left(), typename left_type::tag_type());
1115          m_backend.negate();
1116       }
1117       else if (!br && (bl || (left_depth >= right_depth)))
1118       { // br is always false, but if bl is true we must take the this branch:
1119          do_assign(e.left(), typename left_type::tag_type());
1120          do_subtract(e.right(), typename right_type::tag_type());
1121       }
1122       else
1123       {
1124          do_assign(e.right(), typename right_type::tag_type());
1125          do_subtract(e.left(), typename left_type::tag_type());
1126          m_backend.negate();
1127       }
1128    }
1129    template <class Exp>
do_assign(const Exp & e,const detail::multiplies &)1130    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiplies&)
1131    {
1132       typedef typename Exp::left_type  left_type;
1133       typedef typename Exp::right_type right_type;
1134 
1135       BOOST_CONSTEXPR int const left_depth  = left_type::depth;
1136       BOOST_CONSTEXPR int const right_depth = right_type::depth;
1137 
1138       bool bl = contains_self(e.left());
1139       bool br = contains_self(e.right());
1140 
1141       if (bl && br)
1142       {
1143          self_type temp(e);
1144          temp.m_backend.swap(this->m_backend);
1145       }
1146       else if (bl && is_self(e.left()))
1147       {
1148          // Ignore the left node, it's *this, just add the right:
1149          do_multiplies(e.right(), typename right_type::tag_type());
1150       }
1151       else if (br && is_self(e.right()))
1152       {
1153          // Ignore the right node, it's *this, just add the left:
1154          do_multiplies(e.left(), typename left_type::tag_type());
1155       }
1156       else if (!br && (bl || (left_depth >= right_depth)))
1157       { // br is always false, but if bl is true we must take the this branch:
1158          do_assign(e.left(), typename left_type::tag_type());
1159          do_multiplies(e.right(), typename right_type::tag_type());
1160       }
1161       else
1162       {
1163          do_assign(e.right(), typename right_type::tag_type());
1164          do_multiplies(e.left(), typename left_type::tag_type());
1165       }
1166    }
1167    template <class Exp>
do_assign(const Exp & e,const detail::divides &)1168    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divides&)
1169    {
1170       typedef typename Exp::left_type  left_type;
1171       typedef typename Exp::right_type right_type;
1172 
1173       bool bl = contains_self(e.left());
1174       bool br = contains_self(e.right());
1175 
1176       if (bl && is_self(e.left()))
1177       {
1178          // Ignore the left node, it's *this, just add the right:
1179          do_divide(e.right(), typename right_type::tag_type());
1180       }
1181       else if (br)
1182       {
1183          self_type temp(e);
1184          temp.m_backend.swap(this->m_backend);
1185       }
1186       else
1187       {
1188          do_assign(e.left(), typename left_type::tag_type());
1189          do_divide(e.right(), typename right_type::tag_type());
1190       }
1191    }
1192    template <class Exp>
do_assign(const Exp & e,const detail::modulus &)1193    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus&)
1194    {
1195       //
1196       // This operation is only valid for integer backends:
1197       //
1198       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
1199 
1200       typedef typename Exp::left_type  left_type;
1201       typedef typename Exp::right_type right_type;
1202 
1203       bool bl = contains_self(e.left());
1204       bool br = contains_self(e.right());
1205 
1206       if (bl && is_self(e.left()))
1207       {
1208          // Ignore the left node, it's *this, just add the right:
1209          do_modulus(e.right(), typename right_type::tag_type());
1210       }
1211       else if (br)
1212       {
1213          self_type temp(e);
1214          temp.m_backend.swap(this->m_backend);
1215       }
1216       else
1217       {
1218          do_assign(e.left(), typename left_type::tag_type());
1219          do_modulus(e.right(), typename right_type::tag_type());
1220       }
1221    }
1222    template <class Exp>
do_assign(const Exp & e,const detail::modulus_immediates &)1223    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus_immediates&)
1224    {
1225       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
1226       using default_ops::eval_modulus;
1227       boost::multiprecision::detail::maybe_promote_precision(this);
1228       eval_modulus(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1229    }
1230 
1231    template <class Exp>
do_assign(const Exp & e,const detail::bitwise_and &)1232    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and&)
1233    {
1234       //
1235       // This operation is only valid for integer backends:
1236       //
1237       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1238 
1239       typedef typename Exp::left_type  left_type;
1240       typedef typename Exp::right_type right_type;
1241 
1242       BOOST_CONSTEXPR int const left_depth  = left_type::depth;
1243       BOOST_CONSTEXPR int const right_depth = right_type::depth;
1244 
1245       bool bl = contains_self(e.left());
1246       bool br = contains_self(e.right());
1247 
1248       if (bl && is_self(e.left()))
1249       {
1250          // Ignore the left node, it's *this, just add the right:
1251          do_bitwise_and(e.right(), typename right_type::tag_type());
1252       }
1253       else if (br && is_self(e.right()))
1254       {
1255          do_bitwise_and(e.left(), typename left_type::tag_type());
1256       }
1257       else if (!br && (bl || (left_depth >= right_depth)))
1258       {
1259          do_assign(e.left(), typename left_type::tag_type());
1260          do_bitwise_and(e.right(), typename right_type::tag_type());
1261       }
1262       else
1263       {
1264          do_assign(e.right(), typename right_type::tag_type());
1265          do_bitwise_and(e.left(), typename left_type::tag_type());
1266       }
1267    }
1268    template <class Exp>
do_assign(const Exp & e,const detail::bitwise_and_immediates &)1269    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and_immediates&)
1270    {
1271       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1272       using default_ops::eval_bitwise_and;
1273       eval_bitwise_and(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1274    }
1275 
1276    template <class Exp>
do_assign(const Exp & e,const detail::bitwise_or &)1277    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or&)
1278    {
1279       //
1280       // This operation is only valid for integer backends:
1281       //
1282       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1283 
1284       typedef typename Exp::left_type  left_type;
1285       typedef typename Exp::right_type right_type;
1286 
1287       BOOST_CONSTEXPR int const left_depth  = left_type::depth;
1288       BOOST_CONSTEXPR int const right_depth = right_type::depth;
1289 
1290       bool bl = contains_self(e.left());
1291       bool br = contains_self(e.right());
1292 
1293       if (bl && is_self(e.left()))
1294       {
1295          // Ignore the left node, it's *this, just add the right:
1296          do_bitwise_or(e.right(), typename right_type::tag_type());
1297       }
1298       else if (br && is_self(e.right()))
1299       {
1300          do_bitwise_or(e.left(), typename left_type::tag_type());
1301       }
1302       else if (!br && (bl || (left_depth >= right_depth)))
1303       {
1304          do_assign(e.left(), typename left_type::tag_type());
1305          do_bitwise_or(e.right(), typename right_type::tag_type());
1306       }
1307       else
1308       {
1309          do_assign(e.right(), typename right_type::tag_type());
1310          do_bitwise_or(e.left(), typename left_type::tag_type());
1311       }
1312    }
1313    template <class Exp>
do_assign(const Exp & e,const detail::bitwise_or_immediates &)1314    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or_immediates&)
1315    {
1316       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1317       using default_ops::eval_bitwise_or;
1318       eval_bitwise_or(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1319    }
1320 
1321    template <class Exp>
do_assign(const Exp & e,const detail::bitwise_xor &)1322    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor&)
1323    {
1324       //
1325       // This operation is only valid for integer backends:
1326       //
1327       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1328 
1329       typedef typename Exp::left_type  left_type;
1330       typedef typename Exp::right_type right_type;
1331 
1332       BOOST_CONSTEXPR int const left_depth  = left_type::depth;
1333       BOOST_CONSTEXPR int const right_depth = right_type::depth;
1334 
1335       bool bl = contains_self(e.left());
1336       bool br = contains_self(e.right());
1337 
1338       if (bl && is_self(e.left()))
1339       {
1340          // Ignore the left node, it's *this, just add the right:
1341          do_bitwise_xor(e.right(), typename right_type::tag_type());
1342       }
1343       else if (br && is_self(e.right()))
1344       {
1345          do_bitwise_xor(e.left(), typename left_type::tag_type());
1346       }
1347       else if (!br && (bl || (left_depth >= right_depth)))
1348       {
1349          do_assign(e.left(), typename left_type::tag_type());
1350          do_bitwise_xor(e.right(), typename right_type::tag_type());
1351       }
1352       else
1353       {
1354          do_assign(e.right(), typename right_type::tag_type());
1355          do_bitwise_xor(e.left(), typename left_type::tag_type());
1356       }
1357    }
1358    template <class Exp>
do_assign(const Exp & e,const detail::bitwise_xor_immediates &)1359    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor_immediates&)
1360    {
1361       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1362       using default_ops::eval_bitwise_xor;
1363       eval_bitwise_xor(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1364    }
1365    template <class Exp>
do_assign(const Exp & e,const detail::terminal &)1366    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::terminal&)
1367    {
1368       if (!is_self(e))
1369       {
1370          m_backend = canonical_value(e.value());
1371       }
1372    }
1373    template <class Exp>
do_assign(const Exp & e,const detail::function &)1374    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::function&)
1375    {
1376       typedef typename Exp::arity tag_type;
1377       boost::multiprecision::detail::maybe_promote_precision(this);
1378       do_assign_function(e, tag_type());
1379    }
1380    template <class Exp>
do_assign(const Exp & e,const detail::shift_left &)1381    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_left&)
1382    {
1383       // We can only shift by an integer value, not an arbitrary expression:
1384       typedef typename Exp::left_type    left_type;
1385       typedef typename Exp::right_type   right_type;
1386       typedef typename right_type::arity right_arity;
1387       BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
1388       typedef typename right_type::result_type right_value_type;
1389       BOOST_STATIC_ASSERT_MSG(is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
1390       typedef typename left_type::tag_type tag_type;
1391       do_assign_left_shift(e.left(), canonical_value(e.right().value()), tag_type());
1392    }
1393 
1394    template <class Exp>
do_assign(const Exp & e,const detail::shift_right &)1395    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_right&)
1396    {
1397       // We can only shift by an integer value, not an arbitrary expression:
1398       typedef typename Exp::left_type    left_type;
1399       typedef typename Exp::right_type   right_type;
1400       typedef typename right_type::arity right_arity;
1401       BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
1402       typedef typename right_type::result_type right_value_type;
1403       BOOST_STATIC_ASSERT_MSG(is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
1404       typedef typename left_type::tag_type tag_type;
1405       do_assign_right_shift(e.left(), canonical_value(e.right().value()), tag_type());
1406    }
1407 
1408    template <class Exp>
do_assign(const Exp & e,const detail::bitwise_complement &)1409    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_complement&)
1410    {
1411       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
1412       using default_ops::eval_complement;
1413       self_type temp(e.left());
1414       eval_complement(m_backend, temp.backend());
1415    }
1416 
1417    template <class Exp>
do_assign(const Exp & e,const detail::complement_immediates &)1418    BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::complement_immediates&)
1419    {
1420       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
1421       using default_ops::eval_complement;
1422       eval_complement(m_backend, canonical_value(e.left().value()));
1423    }
1424 
1425    template <class Exp, class Val>
do_assign_right_shift(const Exp & e,const Val & val,const detail::terminal &)1426    BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const detail::terminal&)
1427    {
1428       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
1429       using default_ops::eval_right_shift;
1430       detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), mpl::bool_<is_signed<Val>::value>());
1431       eval_right_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
1432    }
1433 
1434    template <class Exp, class Val>
do_assign_left_shift(const Exp & e,const Val & val,const detail::terminal &)1435    BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const detail::terminal&)
1436    {
1437       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
1438       using default_ops::eval_left_shift;
1439       detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), mpl::bool_<is_signed<Val>::value>());
1440       eval_left_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
1441    }
1442 
1443    template <class Exp, class Val, class Tag>
do_assign_right_shift(const Exp & e,const Val & val,const Tag &)1444    BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const Tag&)
1445    {
1446       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
1447       using default_ops::eval_right_shift;
1448       self_type temp(e);
1449       detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), mpl::bool_<is_signed<Val>::value>());
1450       eval_right_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
1451    }
1452 
1453    template <class Exp, class Val, class Tag>
do_assign_left_shift(const Exp & e,const Val & val,const Tag &)1454    BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const Tag&)
1455    {
1456       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
1457       using default_ops::eval_left_shift;
1458       self_type temp(e);
1459       detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), mpl::bool_<is_signed<Val>::value>());
1460       eval_left_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
1461    }
1462 
1463    template <class Exp>
do_assign_function(const Exp & e,const mpl::int_<1> &)1464    BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const mpl::int_<1>&)
1465    {
1466       e.left().value()(&m_backend);
1467    }
1468    template <class Exp>
do_assign_function(const Exp & e,const mpl::int_<2> &)1469    BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const mpl::int_<2>&)
1470    {
1471       typedef typename Exp::right_type      right_type;
1472       typedef typename right_type::tag_type tag_type;
1473       do_assign_function_1(e.left().value(), e.right_ref(), tag_type());
1474    }
1475    template <class F, class Exp>
do_assign_function_1(const F & f,const Exp & val,const detail::terminal &)1476    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const detail::terminal&)
1477    {
1478       f(m_backend, function_arg_value(val));
1479    }
1480    template <class F, class Exp, class Tag>
do_assign_function_1(const F & f,const Exp & val,const Tag &)1481    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const Tag&)
1482    {
1483       typename Exp::result_type t(val);
1484       f(m_backend, t.backend());
1485    }
1486    template <class Exp>
do_assign_function(const Exp & e,const mpl::int_<3> &)1487    BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const mpl::int_<3>&)
1488    {
1489       typedef typename Exp::middle_type      middle_type;
1490       typedef typename middle_type::tag_type tag_type;
1491       typedef typename Exp::right_type       end_type;
1492       typedef typename end_type::tag_type    end_tag;
1493       do_assign_function_2(e.left().value(), e.middle_ref(), e.right_ref(), tag_type(), end_tag());
1494    }
1495    template <class F, class Exp1, class Exp2>
do_assign_function_2(const F & f,const Exp1 & val1,const Exp2 & val2,const detail::terminal &,const detail::terminal &)1496    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const detail::terminal&)
1497    {
1498       f(m_backend, function_arg_value(val1), function_arg_value(val2));
1499    }
1500    template <class F, class Exp1, class Exp2, class Tag1>
do_assign_function_2(const F & f,const Exp1 & val1,const Exp2 & val2,const Tag1 &,const detail::terminal &)1501    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const detail::terminal&)
1502    {
1503       typename Exp1::result_type temp1(val1);
1504       f(m_backend, BOOST_MP_MOVE(temp1.backend()), function_arg_value(val2));
1505    }
1506    template <class F, class Exp1, class Exp2, class Tag2>
do_assign_function_2(const F & f,const Exp1 & val1,const Exp2 & val2,const detail::terminal &,const Tag2 &)1507    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const Tag2&)
1508    {
1509       typename Exp2::result_type temp2(val2);
1510       f(m_backend, function_arg_value(val1), BOOST_MP_MOVE(temp2.backend()));
1511    }
1512    template <class F, class Exp1, class Exp2, class Tag1, class Tag2>
do_assign_function_2(const F & f,const Exp1 & val1,const Exp2 & val2,const Tag1 &,const Tag2 &)1513    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const Tag2&)
1514    {
1515       typename Exp1::result_type temp1(val1);
1516       typename Exp2::result_type temp2(val2);
1517       f(m_backend, BOOST_MP_MOVE(temp1.backend()), BOOST_MP_MOVE(temp2.backend()));
1518    }
1519 
1520    template <class Exp>
do_assign_function(const Exp & e,const mpl::int_<4> &)1521    BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const mpl::int_<4>&)
1522    {
1523       typedef typename Exp::left_middle_type  left_type;
1524       typedef typename left_type::tag_type    left_tag_type;
1525       typedef typename Exp::right_middle_type middle_type;
1526       typedef typename middle_type::tag_type  middle_tag_type;
1527       typedef typename Exp::right_type        right_type;
1528       typedef typename right_type::tag_type   right_tag_type;
1529       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());
1530    }
1531    template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
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)1532    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)
1533    {
1534       do_assign_function_3b(f, val1, val2, val3, t2, t3);
1535    }
1536    template <class F, class Exp1, class Exp2, class Exp3, class Tag1, class Tag2, class Tag3>
do_assign_function_3a(const F & f,const Exp1 & val1,const Exp2 & val2,const Exp3 & val3,const Tag1 &,const Tag2 & t2,const Tag3 & t3)1537    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)
1538    {
1539       typename Exp1::result_type t(val1);
1540       do_assign_function_3b(f, BOOST_MP_MOVE(t), val2, val3, t2, t3);
1541    }
1542    template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
do_assign_function_3b(const F & f,const Exp1 & val1,const Exp2 & val2,const Exp3 & val3,const detail::terminal &,const Tag3 & t3)1543    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)
1544    {
1545       do_assign_function_3c(f, val1, val2, val3, t3);
1546    }
1547    template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
do_assign_function_3b(const F & f,const Exp1 & val1,const Exp2 & val2,const Exp3 & val3,const Tag2 &,const Tag3 & t3)1548    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)
1549    {
1550       typename Exp2::result_type t(val2);
1551       do_assign_function_3c(f, val1, BOOST_MP_MOVE(t), val3, t3);
1552    }
1553    template <class F, class Exp1, class Exp2, class Exp3>
do_assign_function_3c(const F & f,const Exp1 & val1,const Exp2 & val2,const Exp3 & val3,const detail::terminal &)1554    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&)
1555    {
1556       f(m_backend, function_arg_value(val1), function_arg_value(val2), function_arg_value(val3));
1557    }
1558    template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
do_assign_function_3c(const F & f,const Exp1 & val1,const Exp2 & val2,const Exp3 & val3,const Tag3 &)1559    BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag3& /*t3*/)
1560    {
1561       typename Exp3::result_type t(val3);
1562       do_assign_function_3c(f, val1, val2, BOOST_MP_MOVE(t), detail::terminal());
1563    }
1564 
1565    template <class Exp>
do_add(const Exp & e,const detail::terminal &)1566    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::terminal&)
1567    {
1568       using default_ops::eval_add;
1569       boost::multiprecision::detail::maybe_promote_precision(this);
1570       eval_add(m_backend, canonical_value(e.value()));
1571    }
1572 
1573    template <class Exp>
do_add(const Exp & e,const detail::negate &)1574    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::negate&)
1575    {
1576       typedef typename Exp::left_type left_type;
1577       boost::multiprecision::detail::maybe_promote_precision(this);
1578       do_subtract(e.left(), typename left_type::tag_type());
1579    }
1580 
1581    template <class Exp>
do_add(const Exp & e,const detail::plus &)1582    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::plus&)
1583    {
1584       typedef typename Exp::left_type  left_type;
1585       typedef typename Exp::right_type right_type;
1586       do_add(e.left(), typename left_type::tag_type());
1587       do_add(e.right(), typename right_type::tag_type());
1588    }
1589 
1590    template <class Exp>
do_add(const Exp & e,const detail::minus &)1591    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::minus&)
1592    {
1593       typedef typename Exp::left_type  left_type;
1594       typedef typename Exp::right_type right_type;
1595       do_add(e.left(), typename left_type::tag_type());
1596       do_subtract(e.right(), typename right_type::tag_type());
1597    }
1598 
1599    template <class Exp, class unknown>
do_add(const Exp & e,const unknown &)1600    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const unknown&)
1601    {
1602       self_type temp(e);
1603       do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
1604    }
1605 
1606    template <class Exp>
do_add(const Exp & e,const detail::add_immediates &)1607    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::add_immediates&)
1608    {
1609       using default_ops::eval_add;
1610       boost::multiprecision::detail::maybe_promote_precision(this);
1611       eval_add(m_backend, canonical_value(e.left().value()));
1612       eval_add(m_backend, canonical_value(e.right().value()));
1613    }
1614    template <class Exp>
do_add(const Exp & e,const detail::subtract_immediates &)1615    BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::subtract_immediates&)
1616    {
1617       using default_ops::eval_add;
1618       using default_ops::eval_subtract;
1619       boost::multiprecision::detail::maybe_promote_precision(this);
1620       eval_add(m_backend, canonical_value(e.left().value()));
1621       eval_subtract(m_backend, canonical_value(e.right().value()));
1622    }
1623    template <class Exp>
do_subtract(const Exp & e,const detail::terminal &)1624    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::terminal&)
1625    {
1626       using default_ops::eval_subtract;
1627       boost::multiprecision::detail::maybe_promote_precision(this);
1628       eval_subtract(m_backend, canonical_value(e.value()));
1629    }
1630 
1631    template <class Exp>
do_subtract(const Exp & e,const detail::negate &)1632    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::negate&)
1633    {
1634       typedef typename Exp::left_type left_type;
1635       do_add(e.left(), typename left_type::tag_type());
1636    }
1637 
1638    template <class Exp>
do_subtract(const Exp & e,const detail::plus &)1639    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::plus&)
1640    {
1641       typedef typename Exp::left_type  left_type;
1642       typedef typename Exp::right_type right_type;
1643       do_subtract(e.left(), typename left_type::tag_type());
1644       do_subtract(e.right(), typename right_type::tag_type());
1645    }
1646 
1647    template <class Exp>
do_subtract(const Exp & e,const detail::minus &)1648    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::minus&)
1649    {
1650       typedef typename Exp::left_type  left_type;
1651       typedef typename Exp::right_type right_type;
1652       do_subtract(e.left(), typename left_type::tag_type());
1653       do_add(e.right(), typename right_type::tag_type());
1654    }
1655    template <class Exp>
do_subtract(const Exp & e,const detail::add_immediates &)1656    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::add_immediates&)
1657    {
1658       using default_ops::eval_subtract;
1659       boost::multiprecision::detail::maybe_promote_precision(this);
1660       eval_subtract(m_backend, canonical_value(e.left().value()));
1661       eval_subtract(m_backend, canonical_value(e.right().value()));
1662    }
1663    template <class Exp>
do_subtract(const Exp & e,const detail::subtract_immediates &)1664    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::subtract_immediates&)
1665    {
1666       using default_ops::eval_add;
1667       using default_ops::eval_subtract;
1668       eval_subtract(m_backend, canonical_value(e.left().value()));
1669       eval_add(m_backend, canonical_value(e.right().value()));
1670    }
1671    template <class Exp, class unknown>
do_subtract(const Exp & e,const unknown &)1672    BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const unknown&)
1673    {
1674       self_type temp(e);
1675       do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
1676    }
1677 
1678    template <class Exp>
do_multiplies(const Exp & e,const detail::terminal &)1679    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::terminal&)
1680    {
1681       using default_ops::eval_multiply;
1682       boost::multiprecision::detail::maybe_promote_precision(this);
1683       eval_multiply(m_backend, canonical_value(e.value()));
1684    }
1685 
1686    template <class Exp>
do_multiplies(const Exp & e,const detail::negate &)1687    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::negate&)
1688    {
1689       typedef typename Exp::left_type left_type;
1690       do_multiplies(e.left(), typename left_type::tag_type());
1691       m_backend.negate();
1692    }
1693 
1694    template <class Exp>
do_multiplies(const Exp & e,const detail::multiplies &)1695    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiplies&)
1696    {
1697       typedef typename Exp::left_type  left_type;
1698       typedef typename Exp::right_type right_type;
1699       do_multiplies(e.left(), typename left_type::tag_type());
1700       do_multiplies(e.right(), typename right_type::tag_type());
1701    }
1702    //
1703    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1704    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1705    //
1706    template <class Exp>
1707    BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
do_multiplies(const Exp & e,const detail::divides &)1708    do_multiplies(const Exp& e, const detail::divides&)
1709    {
1710       typedef typename Exp::left_type  left_type;
1711       typedef typename Exp::right_type right_type;
1712       do_multiplies(e.left(), typename left_type::tag_type());
1713       do_divide(e.right(), typename right_type::tag_type());
1714    }
1715 
1716    template <class Exp>
do_multiplies(const Exp & e,const detail::multiply_immediates &)1717    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiply_immediates&)
1718    {
1719       using default_ops::eval_multiply;
1720       boost::multiprecision::detail::maybe_promote_precision(this);
1721       eval_multiply(m_backend, canonical_value(e.left().value()));
1722       eval_multiply(m_backend, canonical_value(e.right().value()));
1723    }
1724    //
1725    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1726    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1727    //
1728    template <class Exp>
1729    BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
do_multiplies(const Exp & e,const detail::divide_immediates &)1730    do_multiplies(const Exp& e, const detail::divide_immediates&)
1731    {
1732       using default_ops::eval_divide;
1733       using default_ops::eval_multiply;
1734       boost::multiprecision::detail::maybe_promote_precision(this);
1735       eval_multiply(m_backend, canonical_value(e.left().value()));
1736       eval_divide(m_backend, canonical_value(e.right().value()));
1737    }
1738    template <class Exp, class unknown>
do_multiplies(const Exp & e,const unknown &)1739    BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const unknown&)
1740    {
1741       using default_ops::eval_multiply;
1742       boost::multiprecision::detail::maybe_promote_precision(this);
1743       self_type temp(e);
1744       eval_multiply(m_backend, temp.m_backend);
1745    }
1746 
1747    template <class Exp>
do_divide(const Exp & e,const detail::terminal &)1748    BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::terminal&)
1749    {
1750       using default_ops::eval_divide;
1751       boost::multiprecision::detail::maybe_promote_precision(this);
1752       eval_divide(m_backend, canonical_value(e.value()));
1753    }
1754 
1755    template <class Exp>
do_divide(const Exp & e,const detail::negate &)1756    BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::negate&)
1757    {
1758       typedef typename Exp::left_type left_type;
1759       do_divide(e.left(), typename left_type::tag_type());
1760       m_backend.negate();
1761    }
1762    //
1763    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1764    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1765    //
1766    template <class Exp>
1767    BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
do_divide(const Exp & e,const detail::multiplies &)1768    do_divide(const Exp& e, const detail::multiplies&)
1769    {
1770       typedef typename Exp::left_type  left_type;
1771       typedef typename Exp::right_type right_type;
1772       do_divide(e.left(), typename left_type::tag_type());
1773       do_divide(e.right(), typename right_type::tag_type());
1774    }
1775    //
1776    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1777    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1778    //
1779    template <class Exp>
1780    BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
do_divide(const Exp & e,const detail::divides &)1781    do_divide(const Exp& e, const detail::divides&)
1782    {
1783       typedef typename Exp::left_type  left_type;
1784       typedef typename Exp::right_type right_type;
1785       do_divide(e.left(), typename left_type::tag_type());
1786       do_multiplies(e.right(), typename right_type::tag_type());
1787    }
1788    //
1789    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1790    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1791    //
1792    template <class Exp>
1793    BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
do_divides(const Exp & e,const detail::multiply_immediates &)1794    do_divides(const Exp& e, const detail::multiply_immediates&)
1795    {
1796       using default_ops::eval_divide;
1797       boost::multiprecision::detail::maybe_promote_precision(this);
1798       eval_divide(m_backend, canonical_value(e.left().value()));
1799       eval_divide(m_backend, canonical_value(e.right().value()));
1800    }
1801    //
1802    // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1803    // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1804    //
1805    template <class Exp>
1806    BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
do_divides(const Exp & e,const detail::divide_immediates &)1807    do_divides(const Exp& e, const detail::divide_immediates&)
1808    {
1809       using default_ops::eval_divide;
1810       using default_ops::eval_multiply;
1811       boost::multiprecision::detail::maybe_promote_precision(this);
1812       eval_divide(m_backend, canonical_value(e.left().value()));
1813       mutiply(m_backend, canonical_value(e.right().value()));
1814    }
1815 
1816    template <class Exp, class unknown>
do_divide(const Exp & e,const unknown &)1817    BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const unknown&)
1818    {
1819       using default_ops::eval_multiply;
1820       boost::multiprecision::detail::maybe_promote_precision(this);
1821       self_type temp(e);
1822       eval_divide(m_backend, temp.m_backend);
1823    }
1824 
1825    template <class Exp>
do_modulus(const Exp & e,const detail::terminal &)1826    BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const detail::terminal&)
1827    {
1828       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
1829       using default_ops::eval_modulus;
1830       boost::multiprecision::detail::maybe_promote_precision(this);
1831       eval_modulus(m_backend, canonical_value(e.value()));
1832    }
1833 
1834    template <class Exp, class Unknown>
do_modulus(const Exp & e,const Unknown &)1835    BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const Unknown&)
1836    {
1837       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
1838       using default_ops::eval_modulus;
1839       boost::multiprecision::detail::maybe_promote_precision(this);
1840       self_type temp(e);
1841       eval_modulus(m_backend, canonical_value(temp));
1842    }
1843 
1844    template <class Exp>
do_bitwise_and(const Exp & e,const detail::terminal &)1845    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::terminal&)
1846    {
1847       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
1848       using default_ops::eval_bitwise_and;
1849       eval_bitwise_and(m_backend, canonical_value(e.value()));
1850    }
1851    template <class Exp>
do_bitwise_and(const Exp & e,const detail::bitwise_and &)1852    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::bitwise_and&)
1853    {
1854       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
1855       typedef typename Exp::left_type  left_type;
1856       typedef typename Exp::right_type right_type;
1857       do_bitwise_and(e.left(), typename left_type::tag_type());
1858       do_bitwise_and(e.right(), typename right_type::tag_type());
1859    }
1860    template <class Exp, class unknown>
do_bitwise_and(const Exp & e,const unknown &)1861    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const unknown&)
1862    {
1863       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
1864       using default_ops::eval_bitwise_and;
1865       self_type temp(e);
1866       eval_bitwise_and(m_backend, temp.m_backend);
1867    }
1868 
1869    template <class Exp>
do_bitwise_or(const Exp & e,const detail::terminal &)1870    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::terminal&)
1871    {
1872       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
1873       using default_ops::eval_bitwise_or;
1874       eval_bitwise_or(m_backend, canonical_value(e.value()));
1875    }
1876    template <class Exp>
do_bitwise_or(const Exp & e,const detail::bitwise_or &)1877    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::bitwise_or&)
1878    {
1879       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
1880       typedef typename Exp::left_type  left_type;
1881       typedef typename Exp::right_type right_type;
1882       do_bitwise_or(e.left(), typename left_type::tag_type());
1883       do_bitwise_or(e.right(), typename right_type::tag_type());
1884    }
1885    template <class Exp, class unknown>
do_bitwise_or(const Exp & e,const unknown &)1886    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const unknown&)
1887    {
1888       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
1889       using default_ops::eval_bitwise_or;
1890       self_type temp(e);
1891       eval_bitwise_or(m_backend, temp.m_backend);
1892    }
1893 
1894    template <class Exp>
do_bitwise_xor(const Exp & e,const detail::terminal &)1895    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::terminal&)
1896    {
1897       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
1898       using default_ops::eval_bitwise_xor;
1899       eval_bitwise_xor(m_backend, canonical_value(e.value()));
1900    }
1901    template <class Exp>
do_bitwise_xor(const Exp & e,const detail::bitwise_xor &)1902    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::bitwise_xor&)
1903    {
1904       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
1905       typedef typename Exp::left_type  left_type;
1906       typedef typename Exp::right_type right_type;
1907       do_bitwise_xor(e.left(), typename left_type::tag_type());
1908       do_bitwise_xor(e.right(), typename right_type::tag_type());
1909    }
1910    template <class Exp, class unknown>
do_bitwise_xor(const Exp & e,const unknown &)1911    BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const unknown&)
1912    {
1913       BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
1914       using default_ops::eval_bitwise_xor;
1915       self_type temp(e);
1916       eval_bitwise_xor(m_backend, temp.m_backend);
1917    }
1918 
1919    // Tests if the expression contains a reference to *this:
1920    template <class Exp>
contains_self(const Exp & e) const1921    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e) const BOOST_NOEXCEPT
1922    {
1923       return contains_self(e, typename Exp::arity());
1924    }
1925    template <class Exp>
contains_self(const Exp & e,mpl::int_<0> const &) const1926    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, mpl::int_<0> const&) const BOOST_NOEXCEPT
1927    {
1928       return is_realy_self(e.value());
1929    }
1930    template <class Exp>
contains_self(const Exp & e,mpl::int_<1> const &) const1931    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, mpl::int_<1> const&) const BOOST_NOEXCEPT
1932    {
1933       typedef typename Exp::left_type child_type;
1934       return contains_self(e.left(), typename child_type::arity());
1935    }
1936    template <class Exp>
contains_self(const Exp & e,mpl::int_<2> const &) const1937    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, mpl::int_<2> const&) const BOOST_NOEXCEPT
1938    {
1939       typedef typename Exp::left_type  child0_type;
1940       typedef typename Exp::right_type child1_type;
1941       return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.right(), typename child1_type::arity());
1942    }
1943    template <class Exp>
contains_self(const Exp & e,mpl::int_<3> const &) const1944    BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, mpl::int_<3> const&) const BOOST_NOEXCEPT
1945    {
1946       typedef typename Exp::left_type   child0_type;
1947       typedef typename Exp::middle_type child1_type;
1948       typedef typename Exp::right_type  child2_type;
1949       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());
1950    }
1951 
1952    // Test if the expression is a reference to *this:
1953    template <class Exp>
is_self(const Exp & e) const1954    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp& e) const BOOST_NOEXCEPT
1955    {
1956       return is_self(e, typename Exp::arity());
1957    }
1958    template <class Exp>
is_self(const Exp & e,mpl::int_<0> const &) const1959    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp& e, mpl::int_<0> const&) const BOOST_NOEXCEPT
1960    {
1961       return is_realy_self(e.value());
1962    }
1963    template <class Exp, int v>
is_self(const Exp &,mpl::int_<v> const &) const1964    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp&, mpl::int_<v> const&) const BOOST_NOEXCEPT
1965    {
1966       return false;
1967    }
1968 
1969    template <class Val>
is_realy_self(const Val &) const1970    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_realy_self(const Val&) const BOOST_NOEXCEPT { return false; }
is_realy_self(const self_type & v) const1971    BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_realy_self(const self_type& v) const BOOST_NOEXCEPT { return &v == this; }
1972 
function_arg_value(const self_type & v)1973    static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& function_arg_value(const self_type& v) BOOST_NOEXCEPT { return v.backend(); }
1974    template <class Other, expression_template_option ET2>
function_arg_value(const number<Other,ET2> & v)1975    static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Other& function_arg_value(const number<Other, ET2>& v) BOOST_NOEXCEPT { return v.backend(); }
1976    template <class V>
function_arg_value(const V & v)1977    static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const V& function_arg_value(const V& v) BOOST_NOEXCEPT { return v; }
1978    template <class A1, class A2, class A3, class A4>
function_arg_value(const detail::expression<detail::terminal,A1,A2,A3,A4> & exp)1979    static BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR const A1& function_arg_value(const detail::expression<detail::terminal, A1, A2, A3, A4>& exp) BOOST_NOEXCEPT { return exp.value(); }
1980    template <class A2, class A3, class A4>
function_arg_value(const detail::expression<detail::terminal,number<Backend>,A2,A3,A4> & exp)1981    static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& function_arg_value(const detail::expression<detail::terminal, number<Backend>, A2, A3, A4>& exp) BOOST_NOEXCEPT { return exp.value().backend(); }
1982    Backend                                                    m_backend;
1983 
1984  public:
1985    //
1986    // These shouldn't really need to be public, or even member functions, but it makes implementing
1987    // the non-member operators way easier if they are:
1988    //
canonical_value(const self_type & v)1989    static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& canonical_value(const self_type& v) BOOST_NOEXCEPT { return v.m_backend; }
1990    template <class B2, expression_template_option ET>
canonical_value(const number<B2,ET> & v)1991    static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const B2& canonical_value(const number<B2, ET>& v) BOOST_NOEXCEPT { return v.backend(); }
1992    template <class V>
1993    static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR typename boost::disable_if<is_same<typename detail::canonical<V, Backend>::type, V>, typename detail::canonical<V, Backend>::type>::type
canonical_value(const V & v)1994    canonical_value(const V& v) BOOST_NOEXCEPT { return static_cast<typename detail::canonical<V, Backend>::type>(v); }
1995    template <class V>
1996    static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR typename boost::enable_if_c<is_same<typename detail::canonical<V, Backend>::type, V>::value, const V&>::type
canonical_value(const V & v)1997    canonical_value(const V& v) BOOST_NOEXCEPT { return v; }
canonical_value(const std::string & v)1998    static BOOST_MP_FORCEINLINE typename detail::canonical<std::string, Backend>::type canonical_value(const std::string& v) BOOST_NOEXCEPT { return v.c_str(); }
1999 };
2000 
2001 template <class Backend, expression_template_option ExpressionTemplates>
operator <<(std::ostream & os,const number<Backend,ExpressionTemplates> & r)2002 inline std::ostream& operator<<(std::ostream& os, const number<Backend, ExpressionTemplates>& r)
2003 {
2004    std::streamsize d  = os.precision();
2005    std::string     s  = r.str(d, os.flags());
2006    std::streamsize ss = os.width();
2007    if (ss > static_cast<std::streamsize>(s.size()))
2008    {
2009       char fill = os.fill();
2010       if ((os.flags() & std::ios_base::left) == std::ios_base::left)
2011          s.append(static_cast<std::string::size_type>(ss - s.size()), fill);
2012       else
2013          s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(ss - s.size()), fill);
2014    }
2015    return os << s;
2016 }
2017 
2018 namespace detail {
2019 
2020 template <class tag, class A1, class A2, class A3, class A4>
operator <<(std::ostream & os,const expression<tag,A1,A2,A3,A4> & r)2021 inline std::ostream& operator<<(std::ostream& os, const expression<tag, A1, A2, A3, A4>& r)
2022 {
2023    typedef typename expression<tag, A1, A2, A3, A4>::result_type value_type;
2024    value_type                                                    temp(r);
2025    return os << temp;
2026 }
2027 //
2028 // What follows is the input streaming code: this is not "proper" iostream code at all
2029 // but that's fiendishly hard to write when dealing with multiple backends all
2030 // with different requirements... yes we could deligate this to the backend author...
2031 // but we really want backends to be EASY to write!
2032 // For now just pull in all the characters that could possibly form the number
2033 // and let the backend's string parser make use of it.  This fixes most use cases
2034 // including CSV type formats such as those used by the Random lib.
2035 //
read_string_while(std::istream & is,std::string const & permitted_chars)2036 inline std::string read_string_while(std::istream& is, std::string const& permitted_chars)
2037 {
2038    std::ios_base::iostate     state = std::ios_base::goodbit;
2039    const std::istream::sentry sentry_check(is);
2040    std::string                result;
2041 
2042    if (sentry_check)
2043    {
2044       int c = is.rdbuf()->sgetc();
2045 
2046       for (;; c = is.rdbuf()->snextc())
2047          if (std::istream::traits_type::eq_int_type(std::istream::traits_type::eof(), c))
2048          { // end of file:
2049             state |= std::ios_base::eofbit;
2050             break;
2051          }
2052          else if (permitted_chars.find_first_of(std::istream::traits_type::to_char_type(c)) == std::string::npos)
2053          {
2054             // Invalid numeric character, stop reading:
2055             //is.rdbuf()->sputbackc(static_cast<char>(c));
2056             break;
2057          }
2058          else
2059          {
2060             result.append(1, std::istream::traits_type::to_char_type(c));
2061          }
2062    }
2063 
2064    if (!result.size())
2065       state |= std::ios_base::failbit;
2066    is.setstate(state);
2067    return result;
2068 }
2069 
2070 } // namespace detail
2071 
2072 template <class Backend, expression_template_option ExpressionTemplates>
operator >>(std::istream & is,number<Backend,ExpressionTemplates> & r)2073 inline std::istream& operator>>(std::istream& is, number<Backend, ExpressionTemplates>& r)
2074 {
2075    bool        hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
2076    bool        oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
2077    std::string s;
2078    switch (boost::multiprecision::number_category<number<Backend, ExpressionTemplates> >::value)
2079    {
2080    case boost::multiprecision::number_kind_integer:
2081       if (oct_format)
2082          s = detail::read_string_while(is, "+-01234567");
2083       else if (hex_format)
2084          s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789");
2085       else
2086          s = detail::read_string_while(is, "+-0123456789");
2087       break;
2088    case boost::multiprecision::number_kind_floating_point:
2089       s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
2090       break;
2091    default:
2092       is >> s;
2093    }
2094    if (s.size())
2095    {
2096       if (hex_format && (number_category<Backend>::value == number_kind_integer) && ((s[0] != '0') || (s[1] != 'x')))
2097          s.insert(s.find_first_not_of("+-"), "0x");
2098       if (oct_format && (number_category<Backend>::value == number_kind_integer) && (s[0] != '0'))
2099          s.insert(s.find_first_not_of("+-"), "0");
2100       r.assign(s);
2101    }
2102    else if (!is.fail())
2103       is.setstate(std::istream::failbit);
2104    return is;
2105 }
2106 
2107 template <class Backend, expression_template_option ExpressionTemplates>
swap(number<Backend,ExpressionTemplates> & a,number<Backend,ExpressionTemplates> & b)2108 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b)
2109     BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<number<Backend, ExpressionTemplates>&>() = std::declval<number<Backend, ExpressionTemplates>&>()))
2110 {
2111    a.swap(b);
2112 }
2113 //
2114 // Boost.Hash support, just call hash_value for the backend, which may or may not be supported:
2115 //
2116 template <class Backend, expression_template_option ExpressionTemplates>
hash_value(const number<Backend,ExpressionTemplates> & val)2117 inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const number<Backend, ExpressionTemplates>& val)
2118 {
2119    return hash_value(val.backend());
2120 }
2121 
2122 } // namespace multiprecision
2123 
2124 template <class T>
2125 class rational;
2126 
2127 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
operator >>(std::istream & is,rational<multiprecision::number<Backend,ExpressionTemplates>> & r)2128 inline std::istream& operator>>(std::istream& is, rational<multiprecision::number<Backend, ExpressionTemplates> >& r)
2129 {
2130    std::string                                          s1;
2131    multiprecision::number<Backend, ExpressionTemplates> v1, v2;
2132    char                                                 c;
2133    bool                                                 have_hex   = false;
2134    bool                                                 hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
2135    bool                                                 oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
2136 
2137    while ((EOF != (c = static_cast<char>(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
2138    {
2139       if (c == 'x' || c == 'X')
2140          have_hex = true;
2141       s1.append(1, c);
2142       is.get();
2143    }
2144    if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
2145       s1.insert(static_cast<std::string::size_type>(0), "0x");
2146    if (oct_format && (s1[0] != '0'))
2147       s1.insert(static_cast<std::string::size_type>(0), "0");
2148    v1.assign(s1);
2149    s1.erase();
2150    if (c == '/')
2151    {
2152       is.get();
2153       while ((EOF != (c = static_cast<char>(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
2154       {
2155          if (c == 'x' || c == 'X')
2156             have_hex = true;
2157          s1.append(1, c);
2158          is.get();
2159       }
2160       if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
2161          s1.insert(static_cast<std::string::size_type>(0), "0x");
2162       if (oct_format && (s1[0] != '0'))
2163          s1.insert(static_cast<std::string::size_type>(0), "0");
2164       v2.assign(s1);
2165    }
2166    else
2167       v2 = 1;
2168    r.assign(v1, v2);
2169    return is;
2170 }
2171 
2172 template <class T, multiprecision::expression_template_option ExpressionTemplates>
numerator(const rational<multiprecision::number<T,ExpressionTemplates>> & a)2173 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> numerator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
2174 {
2175    return a.numerator();
2176 }
2177 
2178 template <class T, multiprecision::expression_template_option ExpressionTemplates>
denominator(const rational<multiprecision::number<T,ExpressionTemplates>> & a)2179 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> denominator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
2180 {
2181    return a.denominator();
2182 }
2183 
2184 template <class T, multiprecision::expression_template_option ExpressionTemplates>
hash_value(const rational<multiprecision::number<T,ExpressionTemplates>> & val)2185 inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const rational<multiprecision::number<T, ExpressionTemplates> >& val)
2186 {
2187    std::size_t result = hash_value(val.numerator());
2188    boost::hash_combine(result, hash_value(val.denominator()));
2189    return result;
2190 }
2191 
2192 namespace multiprecision {
2193 
2194 template <class I>
2195 struct component_type<boost::rational<I> >
2196 {
2197    typedef I type;
2198 };
2199 
2200 } // namespace multiprecision
2201 
2202 #ifdef BOOST_MSVC
2203 #pragma warning(pop)
2204 #endif
2205 
2206 } // namespace boost
2207 
2208 #ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
2209 
2210 #include <functional>
2211 
2212 namespace std {
2213 
2214 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
2215 struct hash<boost::multiprecision::number<Backend, ExpressionTemplates> >
2216 {
operator ()std::hash2217    BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::multiprecision::number<Backend, ExpressionTemplates>& val) const { return hash_value(val); }
2218 };
2219 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
2220 struct hash<boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> > >
2221 {
operator ()std::hash2222    BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> >& val) const
2223    {
2224       std::size_t result = hash_value(val.numerator());
2225       boost::hash_combine(result, hash_value(val.denominator()));
2226       return result;
2227    }
2228 };
2229 
2230 } // namespace std
2231 
2232 #endif
2233 
2234 #include <boost/multiprecision/detail/ublas_interop.hpp>
2235 
2236 #endif
2237