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