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