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