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