]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/multiprecision/detail/default_ops.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / multiprecision / detail / default_ops.hpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright 2011-21 John Maddock.
3 // Copyright 2021 Iskandarov Lev. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7 #ifndef BOOST_MATH_BIG_NUM_DEF_OPS
8 #define BOOST_MATH_BIG_NUM_DEF_OPS
9
10 #include <boost/multiprecision/detail/standalone_config.hpp>
11 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
12 #include <boost/multiprecision/detail/number_base.hpp>
13 #include <boost/multiprecision/detail/assert.hpp>
14 #include <boost/multiprecision/traits/is_backend.hpp>
15 #include <boost/multiprecision/detail/fpclassify.hpp>
16 #include <cstdint>
17 #include <complex>
18 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
19 #include <string_view>
20 #endif
21
22 #ifdef BOOST_MP_MATH_AVAILABLE
23 #include <boost/math/special_functions/fpclassify.hpp>
24 #include <boost/math/special_functions/next.hpp>
25 #include <boost/math/special_functions/hypot.hpp>
26 #include <boost/math/policies/error_handling.hpp>
27 #endif
28
29 #ifndef INSTRUMENT_BACKEND
30 #ifndef BOOST_MP_INSTRUMENT
31 #define INSTRUMENT_BACKEND(x)
32 #else
33 #define INSTRUMENT_BACKEND(x) \
34 std::cout << BOOST_STRINGIZE(x) << " = " << x.str(0, std::ios_base::scientific) << std::endl;
35 #endif
36 #endif
37
38 namespace boost {
39 namespace multiprecision {
40
41 namespace detail {
42
43 template <class To, class From>
44 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_floating_point>& /*to_type*/, const std::integral_constant<int, number_kind_integer>& /*from_type*/);
45 template <class To, class From>
46 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_integer>& /*to_type*/, const std::integral_constant<int, number_kind_integer>& /*from_type*/);
47 template <class To, class From>
48 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_floating_point>& /*to_type*/, const std::integral_constant<int, number_kind_floating_point>& /*from_type*/);
49 template <class To, class From>
50 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_rational>& /*to_type*/, const std::integral_constant<int, number_kind_rational>& /*from_type*/);
51 template <class To, class From>
52 void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_rational>& /*to_type*/, const std::integral_constant<int, number_kind_integer>& /*from_type*/);
53
54 template <class Integer>
55 BOOST_MP_CXX14_CONSTEXPR Integer karatsuba_sqrt(const Integer& x, Integer& r, size_t bits);
56
57 } // namespace detail
58
59 namespace default_ops {
60
61 template <class T>
62 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_backend<T>::value, int>::type eval_signbit(const T& val);
63
64 template <class T>
65 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!boost::multiprecision::detail::is_backend<T>::value, int>::type eval_signbit(const T& val) { return val < 0; }
66
67 inline int eval_signbit(float val) { return (std::signbit)(val); }
68 inline int eval_signbit(double val) { return (std::signbit)(val); }
69 inline int eval_signbit(long double val) { return (std::signbit)(val); }
70 #ifdef BOOST_HAS_FLOAT128
71 extern "C" int signbitq(float128_type) throw();
72 inline int eval_signbit(float128_type val) { return signbitq(val); }
73 #endif
74
75 template <class T>
76 BOOST_MP_CXX14_CONSTEXPR bool eval_is_zero(const T& val);
77
78 #ifdef BOOST_MSVC
79 // warning C4127: conditional expression is constant
80 // warning C4146: unary minus operator applied to unsigned type, result still unsigned
81 #pragma warning(push)
82 #pragma warning(disable : 4127 4146)
83 #endif
84 //
85 // Default versions of mixed arithmetic, these just construct a temporary
86 // from the arithmetic value and then do the arithmetic on that, two versions
87 // of each depending on whether the backend can be directly constructed from type V.
88 //
89 // Note that we have to provide *all* the template parameters to class number when used in
90 // enable_if as MSVC-10 won't compile the code if we rely on a computed-default parameter.
91 // Since the result of the test doesn't depend on whether expression templates are on or off
92 // we just use et_on everywhere. We could use a BOOST_WORKAROUND but that just obfuscates the
93 // code even more....
94 //
95 template <class T, class V>
96 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<V, T>::value>::type
97 eval_add(T& result, V const& v)
98 {
99 T t;
100 t = v;
101 eval_add(result, t);
102 }
103 template <class T, class V>
104 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, T>::value>::type
105 eval_add(T& result, V const& v)
106 {
107 T t(v);
108 eval_add(result, t);
109 }
110 template <class T, class V>
111 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<V, T>::value>::type
112 eval_subtract(T& result, V const& v)
113 {
114 T t;
115 t = v;
116 eval_subtract(result, t);
117 }
118 template <class T, class V>
119 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, T>::value>::type
120 eval_subtract(T& result, V const& v)
121 {
122 T t(v);
123 eval_subtract(result, t);
124 }
125 template <class T, class V>
126 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<V, T>::value>::type
127 eval_multiply(T& result, V const& v)
128 {
129 T t;
130 t = v;
131 eval_multiply(result, t);
132 }
133 template <class T, class V>
134 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, T>::value>::type
135 eval_multiply(T& result, V const& v)
136 {
137 T t(v);
138 eval_multiply(result, t);
139 }
140
141 template <class T, class U, class V>
142 BOOST_MP_CXX14_CONSTEXPR void eval_multiply(T& t, const U& u, const V& v);
143
144 template <class T, class U, class V>
145 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(!std::is_same<T, U>::value && std::is_same<T, V>::value)>::type eval_multiply_add(T& t, const U& u, const V& v)
146 {
147 T z;
148 eval_multiply(z, u, v);
149 eval_add(t, z);
150 }
151 template <class T, class U, class V>
152 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value && std::is_same<T, V>::value>::type eval_multiply_add(T& t, const U& u, const V& v)
153 {
154 eval_multiply_add(t, v, u);
155 }
156 template <class T, class U, class V>
157 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(!std::is_same<T, U>::value && std::is_same<T, V>::value)>::type eval_multiply_subtract(T& t, const U& u, const V& v)
158 {
159 T z;
160 eval_multiply(z, u, v);
161 eval_subtract(t, z);
162 }
163 template <class T, class U, class V>
164 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value && std::is_same<T, V>::value>::type eval_multiply_subtract(T& t, const U& u, const V& v)
165 {
166 eval_multiply_subtract(t, v, u);
167 }
168 template <class T, class V>
169 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
170 eval_divide(T& result, V const& v)
171 {
172 T t;
173 t = v;
174 eval_divide(result, t);
175 }
176 template <class T, class V>
177 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
178 eval_divide(T& result, V const& v)
179 {
180 T t(v);
181 eval_divide(result, t);
182 }
183 template <class T, class V>
184 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
185 eval_modulus(T& result, V const& v)
186 {
187 T t;
188 t = v;
189 eval_modulus(result, t);
190 }
191 template <class T, class V>
192 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
193 eval_modulus(T& result, V const& v)
194 {
195 T t(v);
196 eval_modulus(result, t);
197 }
198 template <class T, class V>
199 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
200 eval_bitwise_and(T& result, V const& v)
201 {
202 T t;
203 t = v;
204 eval_bitwise_and(result, t);
205 }
206 template <class T, class V>
207 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
208 eval_bitwise_and(T& result, V const& v)
209 {
210 T t(v);
211 eval_bitwise_and(result, t);
212 }
213 template <class T, class V>
214 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
215 eval_bitwise_or(T& result, V const& v)
216 {
217 T t;
218 t = v;
219 eval_bitwise_or(result, t);
220 }
221 template <class T, class V>
222 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
223 eval_bitwise_or(T& result, V const& v)
224 {
225 T t(v);
226 eval_bitwise_or(result, t);
227 }
228 template <class T, class V>
229 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
230 eval_bitwise_xor(T& result, V const& v)
231 {
232 T t;
233 t = v;
234 eval_bitwise_xor(result, t);
235 }
236 template <class T, class V>
237 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
238 eval_bitwise_xor(T& result, V const& v)
239 {
240 T t(v);
241 eval_bitwise_xor(result, t);
242 }
243
244 template <class T, class V>
245 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
246 eval_complement(T& result, V const& v)
247 {
248 T t;
249 t = v;
250 eval_complement(result, t);
251 }
252 template <class T, class V>
253 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
254 eval_complement(T& result, V const& v)
255 {
256 T t(v);
257 eval_complement(result, t);
258 }
259
260 //
261 // Default versions of 3-arg arithmetic functions, these mostly just forward to the 2 arg versions:
262 //
263 template <class T, class U, class V>
264 BOOST_MP_CXX14_CONSTEXPR void eval_add(T& t, const U& u, const V& v);
265
266 template <class T>
267 inline BOOST_MP_CXX14_CONSTEXPR void eval_add_default(T& t, const T& u, const T& v)
268 {
269 if (&t == &v)
270 {
271 eval_add(t, u);
272 }
273 else if (&t == &u)
274 {
275 eval_add(t, v);
276 }
277 else
278 {
279 t = u;
280 eval_add(t, v);
281 }
282 }
283 template <class T, class U>
284 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_add_default(T& t, const T& u, const U& v)
285 {
286 T vv;
287 vv = v;
288 eval_add(t, u, vv);
289 }
290 template <class T, class U>
291 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_add_default(T& t, const T& u, const U& v)
292 {
293 T vv(v);
294 eval_add(t, u, vv);
295 }
296 template <class T, class U>
297 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_add_default(T& t, const U& u, const T& v)
298 {
299 eval_add(t, v, u);
300 }
301 template <class T, class U, class V>
302 inline BOOST_MP_CXX14_CONSTEXPR void eval_add_default(T& t, const U& u, const V& v)
303 {
304 BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
305 {
306 if ((void*)&t == (void*)&v)
307 {
308 eval_add(t, u);
309 }
310 else
311 {
312 t = u;
313 eval_add(t, v);
314 }
315 }
316 else
317 {
318 t = u;
319 eval_add(t, v);
320 }
321 }
322 template <class T, class U, class V>
323 inline BOOST_MP_CXX14_CONSTEXPR void eval_add(T& t, const U& u, const V& v)
324 {
325 eval_add_default(t, u, v);
326 }
327
328 template <class T, class U, class V>
329 void BOOST_MP_CXX14_CONSTEXPR eval_subtract(T& t, const U& u, const V& v);
330
331 template <class T>
332 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract_default(T& t, const T& u, const T& v)
333 {
334 if ((&t == &v) && is_signed_number<T>::value)
335 {
336 eval_subtract(t, u);
337 t.negate();
338 }
339 else if (&t == &u)
340 {
341 eval_subtract(t, v);
342 }
343 else
344 {
345 t = u;
346 eval_subtract(t, v);
347 }
348 }
349 template <class T, class U>
350 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_subtract_default(T& t, const T& u, const U& v)
351 {
352 T vv;
353 vv = v;
354 eval_subtract(t, u, vv);
355 }
356 template <class T, class U>
357 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_subtract_default(T& t, const T& u, const U& v)
358 {
359 T vv(v);
360 eval_subtract(t, u, vv);
361 }
362 template <class T, class U>
363 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && is_signed_number<T>::value && (number_category<T>::value != number_kind_complex)>::type eval_subtract_default(T& t, const U& u, const T& v)
364 {
365 eval_subtract(t, v, u);
366 if(!eval_is_zero(t) || (eval_signbit(u) != eval_signbit(v)))
367 t.negate();
368 }
369 template <class T, class U>
370 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && is_signed_number<T>::value && (number_category<T>::value == number_kind_complex)>::type eval_subtract_default(T& t, const U& u, const T& v)
371 {
372 eval_subtract(t, v, u);
373 t.negate();
374 }
375 template <class T, class U>
376 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v)
377 {
378 T temp;
379 temp = u;
380 eval_subtract(t, temp, v);
381 }
382 template <class T, class U>
383 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v)
384 {
385 T temp(u);
386 eval_subtract(t, temp, v);
387 }
388 template <class T, class U, class V>
389 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract_default(T& t, const U& u, const V& v)
390 {
391 BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
392 {
393 if ((void*)&t == (void*)&v)
394 {
395 eval_subtract(t, u);
396 t.negate();
397 }
398 else
399 {
400 t = u;
401 eval_subtract(t, v);
402 }
403 }
404 else
405 {
406 t = u;
407 eval_subtract(t, v);
408 }
409 }
410 template <class T, class U, class V>
411 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(T& t, const U& u, const V& v)
412 {
413 eval_subtract_default(t, u, v);
414 }
415
416 template <class T>
417 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply_default(T& t, const T& u, const T& v)
418 {
419 if (&t == &v)
420 {
421 eval_multiply(t, u);
422 }
423 else if (&t == &u)
424 {
425 eval_multiply(t, v);
426 }
427 else
428 {
429 t = u;
430 eval_multiply(t, v);
431 }
432 }
433 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
434 template <class T, class U>
435 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_multiply_default(T& t, const T& u, const U& v)
436 {
437 T vv;
438 vv = v;
439 eval_multiply(t, u, vv);
440 }
441 template <class T, class U>
442 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_multiply_default(T& t, const T& u, const U& v)
443 {
444 T vv(v);
445 eval_multiply(t, u, vv);
446 }
447 template <class T, class U>
448 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_multiply_default(T& t, const U& u, const T& v)
449 {
450 eval_multiply(t, v, u);
451 }
452 #endif
453 template <class T, class U, class V>
454 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply_default(T& t, const U& u, const V& v)
455 {
456 BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
457 {
458 if ((void*)&t == (void*)&v)
459 {
460 eval_multiply(t, u);
461 }
462 else
463 {
464 t = number<T>::canonical_value(u);
465 eval_multiply(t, v);
466 }
467 }
468 else
469 {
470 t = number<T>::canonical_value(u);
471 eval_multiply(t, v);
472 }
473 }
474 template <class T, class U, class V>
475 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply(T& t, const U& u, const V& v)
476 {
477 eval_multiply_default(t, u, v);
478 }
479
480 template <class T>
481 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply_add(T& t, const T& u, const T& v, const T& x)
482 {
483 if ((void*)&x == (void*)&t)
484 {
485 T z;
486 z = number<T>::canonical_value(x);
487 eval_multiply_add(t, u, v, z);
488 }
489 else
490 {
491 eval_multiply(t, u, v);
492 eval_add(t, x);
493 }
494 }
495
496 template <class T, class U>
497 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_same<T, U>::value, T>::type make_T(const U& u)
498 {
499 T t;
500 t = number<T>::canonical_value(u);
501 return t;
502 }
503 template <class T>
504 inline BOOST_MP_CXX14_CONSTEXPR const T& make_T(const T& t)
505 {
506 return t;
507 }
508
509 template <class T, class U, class V, class X>
510 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(!std::is_same<T, U>::value && std::is_same<T, V>::value)>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x)
511 {
512 eval_multiply_add(t, make_T<T>(u), make_T<T>(v), make_T<T>(x));
513 }
514 template <class T, class U, class V, class X>
515 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value && std::is_same<T, V>::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x)
516 {
517 eval_multiply_add(t, v, u, x);
518 }
519 template <class T, class U, class V, class X>
520 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(!std::is_same<T, U>::value && std::is_same<T, V>::value)>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x)
521 {
522 if ((void*)&x == (void*)&t)
523 {
524 T z;
525 z = x;
526 eval_multiply_subtract(t, u, v, z);
527 }
528 else
529 {
530 eval_multiply(t, u, v);
531 eval_subtract(t, x);
532 }
533 }
534 template <class T, class U, class V, class X>
535 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value && std::is_same<T, V>::value>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x)
536 {
537 eval_multiply_subtract(t, v, u, x);
538 }
539
540 template <class T, class U, class V>
541 BOOST_MP_CXX14_CONSTEXPR void eval_divide(T& t, const U& u, const V& v);
542
543 template <class T>
544 inline BOOST_MP_CXX14_CONSTEXPR void eval_divide_default(T& t, const T& u, const T& v)
545 {
546 if (&t == &u)
547 eval_divide(t, v);
548 else if (&t == &v)
549 {
550 T temp;
551 eval_divide(temp, u, v);
552 temp.swap(t);
553 }
554 else
555 {
556 t = u;
557 eval_divide(t, v);
558 }
559 }
560 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
561 template <class T, class U>
562 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_divide_default(T& t, const T& u, const U& v)
563 {
564 T vv;
565 vv = v;
566 eval_divide(t, u, vv);
567 }
568 template <class T, class U>
569 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_divide_default(T& t, const T& u, const U& v)
570 {
571 T vv(v);
572 eval_divide(t, u, vv);
573 }
574 template <class T, class U>
575 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_divide_default(T& t, const U& u, const T& v)
576 {
577 T uu;
578 uu = u;
579 eval_divide(t, uu, v);
580 }
581 template <class T, class U>
582 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_divide_default(T& t, const U& u, const T& v)
583 {
584 T uu(u);
585 eval_divide(t, uu, v);
586 }
587 #endif
588 template <class T, class U, class V>
589 inline BOOST_MP_CXX14_CONSTEXPR void eval_divide_default(T& t, const U& u, const V& v)
590 {
591 BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
592 {
593 if ((void*)&t == (void*)&v)
594 {
595 T temp;
596 temp = u;
597 eval_divide(temp, v);
598 t = temp;
599 }
600 else
601 {
602 t = u;
603 eval_divide(t, v);
604 }
605 }
606 else
607 {
608 t = u;
609 eval_divide(t, v);
610 }
611 }
612 template <class T, class U, class V>
613 inline BOOST_MP_CXX14_CONSTEXPR void eval_divide(T& t, const U& u, const V& v)
614 {
615 eval_divide_default(t, u, v);
616 }
617
618 template <class T, class U, class V>
619 BOOST_MP_CXX14_CONSTEXPR void eval_modulus(T& t, const U& u, const V& v);
620
621 template <class T>
622 inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus_default(T& t, const T& u, const T& v)
623 {
624 if (&t == &u)
625 eval_modulus(t, v);
626 else if (&t == &v)
627 {
628 T temp;
629 eval_modulus(temp, u, v);
630 temp.swap(t);
631 }
632 else
633 {
634 t = u;
635 eval_modulus(t, v);
636 }
637 }
638 template <class T, class U>
639 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_modulus_default(T& t, const T& u, const U& v)
640 {
641 T vv;
642 vv = v;
643 eval_modulus(t, u, vv);
644 }
645 template <class T, class U>
646 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_modulus_default(T& t, const T& u, const U& v)
647 {
648 T vv(v);
649 eval_modulus(t, u, vv);
650 }
651 template <class T, class U>
652 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_modulus_default(T& t, const U& u, const T& v)
653 {
654 T uu;
655 uu = u;
656 eval_modulus(t, uu, v);
657 }
658 template <class T, class U>
659 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_modulus_default(T& t, const U& u, const T& v)
660 {
661 T uu(u);
662 eval_modulus(t, uu, v);
663 }
664 template <class T, class U, class V>
665 inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus_default(T& t, const U& u, const V& v)
666 {
667 BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
668 {
669 if ((void*)&t == (void*)&v)
670 {
671 T temp(u);
672 eval_modulus(temp, v);
673 t = temp;
674 }
675 else
676 {
677 t = u;
678 eval_modulus(t, v);
679 }
680 }
681 else
682 {
683 t = u;
684 eval_modulus(t, v);
685 }
686 }
687 template <class T, class U, class V>
688 inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus(T& t, const U& u, const V& v)
689 {
690 eval_modulus_default(t, u, v);
691 }
692
693 template <class T, class U, class V>
694 BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and(T& t, const U& u, const V& v);
695
696 template <class T>
697 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and_default(T& t, const T& u, const T& v)
698 {
699 if (&t == &v)
700 {
701 eval_bitwise_and(t, u);
702 }
703 else if (&t == &u)
704 {
705 eval_bitwise_and(t, v);
706 }
707 else
708 {
709 t = u;
710 eval_bitwise_and(t, v);
711 }
712 }
713 template <class T, class U>
714 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<U, T>::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v)
715 {
716 T vv;
717 vv = v;
718 eval_bitwise_and(t, u, vv);
719 }
720 template <class T, class U>
721 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, T>::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v)
722 {
723 T vv(v);
724 eval_bitwise_and(t, u, vv);
725 }
726 template <class T, class U>
727 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_bitwise_and_default(T& t, const U& u, const T& v)
728 {
729 eval_bitwise_and(t, v, u);
730 }
731 template <class T, class U, class V>
732 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_same<T, U>::value || std::is_same<T, V>::value>::type eval_bitwise_and_default(T& t, const U& u, const V& v)
733 {
734 t = u;
735 eval_bitwise_and(t, v);
736 }
737 template <class T, class U, class V>
738 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and(T& t, const U& u, const V& v)
739 {
740 eval_bitwise_and_default(t, u, v);
741 }
742
743 template <class T, class U, class V>
744 BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or(T& t, const U& u, const V& v);
745
746 template <class T>
747 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or_default(T& t, const T& u, const T& v)
748 {
749 if (&t == &v)
750 {
751 eval_bitwise_or(t, u);
752 }
753 else if (&t == &u)
754 {
755 eval_bitwise_or(t, v);
756 }
757 else
758 {
759 t = u;
760 eval_bitwise_or(t, v);
761 }
762 }
763 template <class T, class U>
764 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v)
765 {
766 T vv;
767 vv = v;
768 eval_bitwise_or(t, u, vv);
769 }
770 template <class T, class U>
771 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v)
772 {
773 T vv(v);
774 eval_bitwise_or(t, u, vv);
775 }
776 template <class T, class U>
777 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_bitwise_or_default(T& t, const U& u, const T& v)
778 {
779 eval_bitwise_or(t, v, u);
780 }
781 template <class T, class U, class V>
782 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or_default(T& t, const U& u, const V& v)
783 {
784 BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
785 {
786 if ((void*)&t == (void*)&v)
787 {
788 eval_bitwise_or(t, u);
789 }
790 else
791 {
792 t = u;
793 eval_bitwise_or(t, v);
794 }
795 }
796 else
797 {
798 t = u;
799 eval_bitwise_or(t, v);
800 }
801 }
802 template <class T, class U, class V>
803 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or(T& t, const U& u, const V& v)
804 {
805 eval_bitwise_or_default(t, u, v);
806 }
807
808 template <class T, class U, class V>
809 BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor(T& t, const U& u, const V& v);
810
811 template <class T>
812 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor_default(T& t, const T& u, const T& v)
813 {
814 if (&t == &v)
815 {
816 eval_bitwise_xor(t, u);
817 }
818 else if (&t == &u)
819 {
820 eval_bitwise_xor(t, v);
821 }
822 else
823 {
824 t = u;
825 eval_bitwise_xor(t, v);
826 }
827 }
828 template <class T, class U>
829 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && !std::is_convertible<U, T>::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v)
830 {
831 T vv;
832 vv = v;
833 eval_bitwise_xor(t, u, vv);
834 }
835 template <class T, class U>
836 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value && std::is_convertible<U, T>::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v)
837 {
838 T vv(v);
839 eval_bitwise_xor(t, u, vv);
840 }
841 template <class T, class U>
842 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<U, number<T, et_on> >::value>::type eval_bitwise_xor_default(T& t, const U& u, const T& v)
843 {
844 eval_bitwise_xor(t, v, u);
845 }
846 template <class T, class U, class V>
847 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor_default(T& t, const U& u, const V& v)
848 {
849 BOOST_IF_CONSTEXPR(std::is_same<T, V>::value)
850 {
851 if ((void*)&t == (void*)&v)
852 {
853 eval_bitwise_xor(t, u);
854 }
855 else
856 {
857 t = u;
858 eval_bitwise_xor(t, v);
859 }
860 }
861 else
862 {
863 t = u;
864 eval_bitwise_xor(t, v);
865 }
866 }
867 template <class T, class U, class V>
868 inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor(T& t, const U& u, const V& v)
869 {
870 eval_bitwise_xor_default(t, u, v);
871 }
872
873 template <class T>
874 inline BOOST_MP_CXX14_CONSTEXPR void eval_increment(T& val)
875 {
876 using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
877 eval_add(val, static_cast<ui_type>(1u));
878 }
879 template <class T>
880 inline BOOST_MP_CXX14_CONSTEXPR void eval_decrement(T& val)
881 {
882 using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
883 eval_subtract(val, static_cast<ui_type>(1u));
884 }
885
886 template <class T, class U, class V>
887 inline BOOST_MP_CXX14_CONSTEXPR void eval_left_shift(T& result, const U& arg, const V val)
888 {
889 result = arg;
890 eval_left_shift(result, val);
891 }
892
893 template <class T, class U, class V>
894 inline BOOST_MP_CXX14_CONSTEXPR void eval_right_shift(T& result, const U& arg, const V val)
895 {
896 result = arg;
897 eval_right_shift(result, val);
898 }
899
900 template <class T>
901 inline BOOST_MP_CXX14_CONSTEXPR bool eval_is_zero(const T& val)
902 {
903 using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
904 return val.compare(static_cast<ui_type>(0)) == 0;
905 }
906 template <class T>
907 inline BOOST_MP_CXX14_CONSTEXPR int eval_get_sign(const T& val)
908 {
909 using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
910 return val.compare(static_cast<ui_type>(0));
911 }
912
913 template <class T, class V, class U>
914 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::false_type&, const std::false_type&)
915 {
916 using component_number_type = typename component_type<number<T> >::type;
917
918 boost::multiprecision::detail::scoped_precision_options<component_number_type> sp(result);
919 (void)sp;
920
921 component_number_type x(v1), y(v2);
922 assign_components(result, x.backend(), y.backend());
923 }
924 template <class T, class V, class U>
925 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::true_type&, const std::false_type&)
926 {
927 boost::multiprecision::detail::scoped_source_precision<number<V>> scope;
928 (void)scope;
929 assign_components_imp2(result, number<V>(v1), v2, std::false_type(), std::false_type());
930 }
931 template <class T, class V, class U>
932 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::true_type&, const std::true_type&)
933 {
934 boost::multiprecision::detail::scoped_source_precision<number<V>> scope1;
935 boost::multiprecision::detail::scoped_source_precision<number<U>> scope2;
936 (void)scope1;
937 (void)scope2;
938 assign_components_imp2(result, number<V>(v1), number<U>(v2), std::false_type(), std::false_type());
939 }
940 template <class T, class V, class U>
941 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::false_type&, const std::true_type&)
942 {
943 boost::multiprecision::detail::scoped_source_precision<number<U>> scope;
944 (void)scope;
945 assign_components_imp2(result, v1, number<U>(v2), std::false_type(), std::false_type());
946 }
947
948
949 template <class T, class V, class U>
950 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp(T& result, const V& v1, const U& v2, const std::integral_constant<int, number_kind_rational>&)
951 {
952 result = v1;
953 T t;
954 t = v2;
955 eval_divide(result, t);
956 }
957
958 template <class T, class V, class U, int N>
959 inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp(T& result, const V& v1, const U& v2, const std::integral_constant<int, N>&)
960 {
961 assign_components_imp2(result, v1, v2, boost::multiprecision::detail::is_backend<V>(), boost::multiprecision::detail::is_backend<U>());
962 }
963
964 template <class T, class V, class U>
965 inline BOOST_MP_CXX14_CONSTEXPR void assign_components(T& result, const V& v1, const U& v2)
966 {
967 return assign_components_imp(result, v1, v2, typename number_category<T>::type());
968 }
969 #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
970 template <class Result, class Traits>
971 inline void assign_from_string_view(Result& result, const std::basic_string_view<char, Traits>& view)
972 {
973 // since most (all?) backends require a const char* to construct from, we just
974 // convert to that:
975 std::string s(view);
976 result = s.c_str();
977 }
978 template <class Result, class Traits>
979 inline void assign_from_string_view(Result& result, const std::basic_string_view<char, Traits>& view_x, const std::basic_string_view<char, Traits>& view_y)
980 {
981 // since most (all?) backends require a const char* to construct from, we just
982 // convert to that:
983 std::string x(view_x), y(view_y);
984 assign_components(result, x.c_str(), y.c_str());
985 }
986 #endif
987 template <class R, int b>
988 struct has_enough_bits
989 {
990 template <class T>
991 struct type : public std::integral_constant<bool, !std::is_same<R, T>::value && (std::numeric_limits<T>::digits >= b)>
992 {};
993 };
994
995 template <class R>
996 struct terminal
997 {
998 BOOST_MP_CXX14_CONSTEXPR terminal(const R& v) : value(v) {}
999 BOOST_MP_CXX14_CONSTEXPR terminal() {}
1000 BOOST_MP_CXX14_CONSTEXPR terminal& operator=(R val)
1001 {
1002 value = val;
1003 return *this;
1004 }
1005 R value;
1006 BOOST_MP_CXX14_CONSTEXPR operator R() const { return value; }
1007 };
1008
1009 template <class Tuple, int i, class T, bool = (i == std::tuple_size<Tuple>::value)>
1010 struct find_index_of_type
1011 {
1012 static constexpr int value =
1013 std::is_same<T, typename std::tuple_element<static_cast<std::size_t>(i), Tuple>::type>::value
1014 ? i
1015 : find_index_of_type<Tuple, i + 1, T>::value;
1016 };
1017 template <class Tuple, int i, class T>
1018 struct find_index_of_type<Tuple, i, T, true>
1019 {
1020 static constexpr int value = -1;
1021 };
1022
1023
1024 template <class R, class B>
1025 struct calculate_next_larger_type
1026 {
1027 // Find which list we're looking through:
1028 using list_type = typename std::conditional<
1029 boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value,
1030 typename B::signed_types,
1031 typename std::conditional<
1032 boost::multiprecision::detail::is_unsigned<R>::value,
1033 typename B::unsigned_types,
1034 typename B::float_types>::type>::type;
1035 static constexpr int start = find_index_of_type<list_type, 0, R>::value;
1036 static constexpr int index_of_type = boost::multiprecision::detail::find_index_of_large_enough_type<list_type, start == INT_MAX ? 0 : start + 1, boost::multiprecision::detail::bits_of<R>::value> ::value;
1037 using type = typename boost::multiprecision::detail::dereference_tuple<index_of_type, list_type, terminal<R> >::type;
1038 };
1039
1040 template <class R, class T>
1041 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<R>::value, bool>::type check_in_range(const T& t)
1042 {
1043 // Can t fit in an R?
1044 if ((t > 0) && std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (t > (std::numeric_limits<R>::max)()))
1045 return true;
1046 else
1047 return false;
1048 }
1049
1050 template <class R, class B>
1051 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<R>::value>::type eval_convert_to(R* result, const B& backend)
1052 {
1053 using next_type = typename calculate_next_larger_type<R, B>::type;
1054 next_type n = next_type();
1055 eval_convert_to(&n, backend);
1056 BOOST_IF_CONSTEXPR(!boost::multiprecision::detail::is_unsigned<R>::value && std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded)
1057 {
1058 if(n > (next_type)(std::numeric_limits<R>::max)())
1059 {
1060 *result = (std::numeric_limits<R>::max)();
1061 return;
1062 }
1063 }
1064 BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_specialized&& std::numeric_limits<R>::is_bounded)
1065 {
1066 if (n < (next_type)(std::numeric_limits<R>::min)())
1067 {
1068 *result = (std::numeric_limits<R>::min)();
1069 return;
1070 }
1071 }
1072 *result = static_cast<R>(n);
1073 }
1074
1075 template <class R, class B>
1076 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !boost::multiprecision::detail::is_integral<R>::value && !std::is_enum<R>::value>::type eval_convert_to(R* result, const B& backend)
1077 {
1078 using next_type = typename calculate_next_larger_type<R, B>::type;
1079 next_type n = next_type();
1080 eval_convert_to(&n, backend);
1081 BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded)
1082 {
1083 if ((n > (next_type)(std::numeric_limits<R>::max)() || (n < (next_type) - (std::numeric_limits<R>::max)())))
1084 {
1085 *result = n > 0 ? (std::numeric_limits<R>::max)() : -(std::numeric_limits<R>::max)();
1086 }
1087 else
1088 *result = static_cast<R>(n);
1089 }
1090 else
1091 *result = static_cast<R>(n);
1092 }
1093
1094 template <class R, class B>
1095 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_enum<R>::value>::type eval_convert_to(R* result, const B& backend)
1096 {
1097 typename std::underlying_type<R>::type t{};
1098 eval_convert_to(&t, backend);
1099 *result = static_cast<R>(t);
1100 }
1101
1102 #ifndef BOOST_MP_STANDALONE
1103 template <class R, class B>
1104 inline void last_chance_eval_convert_to(terminal<R>* result, const B& backend, const std::integral_constant<bool, false>&)
1105 {
1106 //
1107 // We ran out of types to try for the conversion, try
1108 // a lexical_cast and hope for the best:
1109 //
1110 BOOST_IF_CONSTEXPR (std::numeric_limits<R>::is_integer && !std::numeric_limits<R>::is_signed)
1111 if (eval_get_sign(backend) < 0)
1112 BOOST_MP_THROW_EXCEPTION(std::range_error("Attempt to convert negative value to an unsigned integer results in undefined behaviour"));
1113 BOOST_MP_TRY {
1114 result->value = boost::lexical_cast<R>(backend.str(0, std::ios_base::fmtflags(0)));
1115 }
1116 BOOST_MP_CATCH (const bad_lexical_cast&)
1117 {
1118 if (eval_get_sign(backend) < 0)
1119 {
1120 BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_integer && !std::numeric_limits<R>::is_signed)
1121 *result = (std::numeric_limits<R>::max)(); // we should never get here, exception above will be raised.
1122 else BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_integer)
1123 *result = (std::numeric_limits<R>::min)();
1124 else
1125 *result = -(std::numeric_limits<R>::max)();
1126 }
1127 else
1128 *result = (std::numeric_limits<R>::max)();
1129 }
1130 BOOST_MP_CATCH_END
1131 }
1132
1133 template <class R, class B>
1134 inline void last_chance_eval_convert_to(terminal<R>* result, const B& backend, const std::integral_constant<bool, true>&)
1135 {
1136 //
1137 // Last chance conversion to an unsigned integer.
1138 // We ran out of types to try for the conversion, try
1139 // a lexical_cast and hope for the best:
1140 //
1141 if (eval_get_sign(backend) < 0)
1142 BOOST_MP_THROW_EXCEPTION(std::range_error("Attempt to convert negative value to an unsigned integer results in undefined behaviour"));
1143 BOOST_MP_TRY {
1144 B t(backend);
1145 R mask = ~static_cast<R>(0u);
1146 eval_bitwise_and(t, mask);
1147 result->value = boost::lexical_cast<R>(t.str(0, std::ios_base::fmtflags(0)));
1148 }
1149 BOOST_MP_CATCH (const bad_lexical_cast&)
1150 {
1151 // We should never really get here...
1152 *result = (std::numeric_limits<R>::max)();
1153 }
1154 BOOST_MP_CATCH_END
1155 }
1156 #else // Using standalone mode
1157
1158 template <class R, class B>
1159 inline void last_chance_eval_convert_to(terminal<R>*, const B&, const std::integral_constant<bool, false>&)
1160 {
1161 static_assert(sizeof(R) == 1, "This type can not be used in standalone mode. Please de-activate and file a bug at https://github.com/boostorg/multiprecision/");
1162 }
1163
1164 template <class R, class B>
1165 inline void last_chance_eval_convert_to(terminal<R>* result, const B& backend, const std::integral_constant<bool, true>&)
1166 {
1167 static_assert(sizeof(R) == 1, "This type can not be used in standalone mode. Please de-activate and file a bug at https://github.com/boostorg/multiprecision/");
1168 }
1169 #endif
1170
1171 template <class R, class B>
1172 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(terminal<R>* result, const B& backend)
1173 {
1174 using tag_type = std::integral_constant<bool, boost::multiprecision::detail::is_unsigned<R>::value && number_category<B>::value == number_kind_integer>;
1175 last_chance_eval_convert_to(result, backend, tag_type());
1176 }
1177
1178 template <class B1, class B2, expression_template_option et>
1179 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(terminal<number<B1, et> >* result, const B2& backend)
1180 {
1181 //
1182 // We ran out of types to try for the conversion, try
1183 // a generic conversion and hope for the best:
1184 //
1185 boost::multiprecision::detail::generic_interconvert(result->value.backend(), backend, number_category<B1>(), number_category<B2>());
1186 }
1187
1188 template <class B>
1189 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::string* result, const B& backend)
1190 {
1191 *result = backend.str(0, std::ios_base::fmtflags(0));
1192 }
1193
1194 template <class B>
1195 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex<float>* result, const B& backend)
1196 {
1197 using scalar_type = typename scalar_result_from_possible_complex<multiprecision::number<B> >::type;
1198 scalar_type re, im;
1199 eval_real(re.backend(), backend);
1200 eval_imag(im.backend(), backend);
1201
1202 *result = std::complex<float>(re.template convert_to<float>(), im.template convert_to<float>());
1203 }
1204
1205 template <class B>
1206 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex<double>* result, const B& backend)
1207 {
1208 using scalar_type = typename scalar_result_from_possible_complex<multiprecision::number<B> >::type;
1209 scalar_type re, im;
1210 eval_real(re.backend(), backend);
1211 eval_imag(im.backend(), backend);
1212
1213 *result = std::complex<double>(re.template convert_to<double>(), im.template convert_to<double>());
1214 }
1215
1216 template <class B>
1217 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex<long double>* result, const B& backend)
1218 {
1219 using scalar_type = typename scalar_result_from_possible_complex<multiprecision::number<B> >::type;
1220 scalar_type re, im;
1221 eval_real(re.backend(), backend);
1222 eval_imag(im.backend(), backend);
1223
1224 *result = std::complex<long double>(re.template convert_to<long double>(), im.template convert_to<long double>());
1225 }
1226
1227 //
1228 // Functions:
1229 //
1230 template <class T, class U>
1231 inline BOOST_MP_CXX14_CONSTEXPR void eval_abs(T& result, const U& arg)
1232 {
1233 using type_list = typename U::signed_types ;
1234 using front = typename std::tuple_element<0, type_list>::type;
1235 result = arg;
1236 if (arg.compare(front(0)) < 0)
1237 result.negate();
1238 }
1239 template <class T, class U>
1240 inline BOOST_MP_CXX14_CONSTEXPR void eval_fabs(T& result, const U& arg)
1241 {
1242 static_assert(number_category<T>::value == number_kind_floating_point, "The fabs function is only valid for floating point types.");
1243 using type_list = typename U::signed_types ;
1244 using front = typename std::tuple_element<0, type_list>::type;
1245 result = arg;
1246 if (arg.compare(front(0)) < 0)
1247 result.negate();
1248 }
1249
1250 template <class Backend>
1251 inline BOOST_MP_CXX14_CONSTEXPR int eval_fpclassify(const Backend& arg)
1252 {
1253 static_assert(number_category<Backend>::value == number_kind_floating_point, "The fpclassify function is only valid for floating point types.");
1254 return eval_is_zero(arg) ? FP_ZERO : FP_NORMAL;
1255 }
1256
1257 template <class T>
1258 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmod(T& result, const T& a, const T& b)
1259 {
1260 static_assert(number_category<T>::value == number_kind_floating_point, "The fmod function is only valid for floating point types.");
1261 if ((&result == &a) || (&result == &b))
1262 {
1263 T temp;
1264 eval_fmod(temp, a, b);
1265 result = temp;
1266 return;
1267 }
1268 switch (eval_fpclassify(a))
1269 {
1270 case FP_ZERO:
1271 result = a;
1272 return;
1273 case FP_INFINITE:
1274 case FP_NAN:
1275 result = std::numeric_limits<number<T> >::quiet_NaN().backend();
1276 errno = EDOM;
1277 return;
1278 }
1279 switch (eval_fpclassify(b))
1280 {
1281 case FP_ZERO:
1282 case FP_NAN:
1283 result = std::numeric_limits<number<T> >::quiet_NaN().backend();
1284 errno = EDOM;
1285 return;
1286 }
1287 T n;
1288 eval_divide(result, a, b);
1289 if (eval_get_sign(result) < 0)
1290 eval_ceil(n, result);
1291 else
1292 eval_floor(n, result);
1293 eval_multiply(n, b);
1294 eval_subtract(result, a, n);
1295 }
1296 template <class T, class A>
1297 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_fmod(T& result, const T& x, const A& a)
1298 {
1299 using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1300 using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1301 cast_type c;
1302 c = a;
1303 eval_fmod(result, x, c);
1304 }
1305
1306 template <class T, class A>
1307 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_fmod(T& result, const A& x, const T& a)
1308 {
1309 using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1310 using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1311 cast_type c;
1312 c = x;
1313 eval_fmod(result, c, a);
1314 }
1315
1316 template <class T>
1317 BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a);
1318
1319 template <class T>
1320 inline BOOST_MP_CXX14_CONSTEXPR void eval_remquo(T& result, const T& a, const T& b, int* pi)
1321 {
1322 static_assert(number_category<T>::value == number_kind_floating_point, "The remquo function is only valid for floating point types.");
1323 if ((&result == &a) || (&result == &b))
1324 {
1325 T temp;
1326 eval_remquo(temp, a, b, pi);
1327 result = temp;
1328 return;
1329 }
1330 T n;
1331 eval_divide(result, a, b);
1332 eval_round(n, result);
1333 eval_convert_to(pi, n);
1334 eval_multiply(n, b);
1335 eval_subtract(result, a, n);
1336 if (eval_is_zero(result))
1337 {
1338 if (eval_signbit(a))
1339 result.negate();
1340 }
1341 }
1342 template <class T, class A>
1343 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_remquo(T& result, const T& x, const A& a, int* pi)
1344 {
1345 using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1346 using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1347 cast_type c = cast_type();
1348 c = a;
1349 eval_remquo(result, x, c, pi);
1350 }
1351 template <class T, class A>
1352 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_remquo(T& result, const A& x, const T& a, int* pi)
1353 {
1354 using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1355 using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1356 cast_type c = cast_type();
1357 c = x;
1358 eval_remquo(result, c, a, pi);
1359 }
1360 template <class T, class U, class V>
1361 inline BOOST_MP_CXX14_CONSTEXPR void eval_remainder(T& result, const U& a, const V& b)
1362 {
1363 int i(0);
1364 eval_remquo(result, a, b, &i);
1365 }
1366
1367 template <class B>
1368 BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const B& a, const B& b);
1369 template <class T, class U>
1370 BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const T& a, const U& b);
1371 template <class B>
1372 BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const B& a, const B& b);
1373 template <class T, class U>
1374 BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const T& a, const U& b);
1375
1376 template <class T>
1377 inline BOOST_MP_CXX14_CONSTEXPR void eval_fdim(T& result, const T& a, const T& b)
1378 {
1379 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1380 const ui_type zero = 0u;
1381 switch (eval_fpclassify(b))
1382 {
1383 case FP_NAN:
1384 case FP_INFINITE:
1385 result = zero;
1386 return;
1387 }
1388 switch (eval_fpclassify(a))
1389 {
1390 case FP_NAN:
1391 result = zero;
1392 return;
1393 case FP_INFINITE:
1394 result = a;
1395 return;
1396 }
1397 if (eval_gt(a, b))
1398 {
1399 eval_subtract(result, a, b);
1400 }
1401 else
1402 result = zero;
1403 }
1404
1405 template <class T, class A>
1406 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value>::type eval_fdim(T& result, const T& a, const A& b)
1407 {
1408 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1409 using arithmetic_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1410 const ui_type zero = 0u;
1411 arithmetic_type canonical_b = b;
1412 switch (BOOST_MP_FPCLASSIFY(b))
1413 {
1414 case FP_NAN:
1415 case FP_INFINITE:
1416 result = zero;
1417 return;
1418 }
1419 switch (eval_fpclassify(a))
1420 {
1421 case FP_NAN:
1422 result = zero;
1423 return;
1424 case FP_INFINITE:
1425 result = a;
1426 return;
1427 }
1428 if (eval_gt(a, canonical_b))
1429 {
1430 eval_subtract(result, a, canonical_b);
1431 }
1432 else
1433 result = zero;
1434 }
1435
1436 template <class T, class A>
1437 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value>::type eval_fdim(T& result, const A& a, const T& b)
1438 {
1439 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1440 using arithmetic_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1441 const ui_type zero = 0u;
1442 arithmetic_type canonical_a = a;
1443 switch (eval_fpclassify(b))
1444 {
1445 case FP_NAN:
1446 case FP_INFINITE:
1447 result = zero;
1448 return;
1449 }
1450 switch (BOOST_MP_FPCLASSIFY(a))
1451 {
1452 case FP_NAN:
1453 result = zero;
1454 return;
1455 case FP_INFINITE:
1456 result = std::numeric_limits<number<T> >::infinity().backend();
1457 return;
1458 }
1459 if (eval_gt(canonical_a, b))
1460 {
1461 eval_subtract(result, canonical_a, b);
1462 }
1463 else
1464 result = zero;
1465 }
1466
1467 template <class T>
1468 inline BOOST_MP_CXX14_CONSTEXPR void eval_trunc(T& result, const T& a)
1469 {
1470 static_assert(number_category<T>::value == number_kind_floating_point, "The trunc function is only valid for floating point types.");
1471 switch (eval_fpclassify(a))
1472 {
1473 case FP_NAN:
1474 errno = EDOM;
1475 // fallthrough...
1476 case FP_ZERO:
1477 case FP_INFINITE:
1478 result = a;
1479 return;
1480 }
1481 if (eval_get_sign(a) < 0)
1482 eval_ceil(result, a);
1483 else
1484 eval_floor(result, a);
1485 }
1486
1487 template <class T>
1488 inline BOOST_MP_CXX14_CONSTEXPR void eval_modf(T& result, T const& arg, T* pipart)
1489 {
1490 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1491 int c = eval_fpclassify(arg);
1492 if (c == static_cast<int>(FP_NAN))
1493 {
1494 if (pipart)
1495 *pipart = arg;
1496 result = arg;
1497 return;
1498 }
1499 else if (c == static_cast<int>(FP_INFINITE))
1500 {
1501 if (pipart)
1502 *pipart = arg;
1503 result = ui_type(0u);
1504 return;
1505 }
1506 if (pipart)
1507 {
1508 eval_trunc(*pipart, arg);
1509 eval_subtract(result, arg, *pipart);
1510 }
1511 else
1512 {
1513 T ipart;
1514 eval_trunc(ipart, arg);
1515 eval_subtract(result, arg, ipart);
1516 }
1517 }
1518
1519 template <class T>
1520 inline BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a)
1521 {
1522 static_assert(number_category<T>::value == number_kind_floating_point, "The round function is only valid for floating point types.");
1523 using fp_type = typename boost::multiprecision::detail::canonical<float, T>::type;
1524 int c = eval_fpclassify(a);
1525 if (c == static_cast<int>(FP_NAN))
1526 {
1527 result = a;
1528 errno = EDOM;
1529 return;
1530 }
1531 if ((c == FP_ZERO) || (c == static_cast<int>(FP_INFINITE)))
1532 {
1533 result = a;
1534 }
1535 else if (eval_get_sign(a) < 0)
1536 {
1537 eval_subtract(result, a, fp_type(0.5f));
1538 eval_ceil(result, result);
1539 }
1540 else
1541 {
1542 eval_add(result, a, fp_type(0.5f));
1543 eval_floor(result, result);
1544 }
1545 }
1546
1547 template <class B>
1548 BOOST_MP_CXX14_CONSTEXPR void eval_lcm(B& result, const B& a, const B& b);
1549 template <class B>
1550 BOOST_MP_CXX14_CONSTEXPR void eval_gcd(B& result, const B& a, const B& b);
1551
1552 template <class T, class Arithmetic>
1553 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Arithmetic>::value >::type eval_gcd(T& result, const T& a, const Arithmetic& b)
1554 {
1555 using si_type = typename boost::multiprecision::detail::canonical<Arithmetic, T>::type;
1556 using default_ops::eval_gcd;
1557 T t;
1558 t = static_cast<si_type>(b);
1559 eval_gcd(result, a, t);
1560 }
1561 template <class T, class Arithmetic>
1562 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Arithmetic>::value >::type eval_gcd(T& result, const Arithmetic& a, const T& b)
1563 {
1564 eval_gcd(result, b, a);
1565 }
1566 template <class T, class Arithmetic>
1567 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Arithmetic>::value >::type eval_lcm(T& result, const T& a, const Arithmetic& b)
1568 {
1569 using si_type = typename boost::multiprecision::detail::canonical<Arithmetic, T>::type;
1570 using default_ops::eval_lcm;
1571 T t;
1572 t = static_cast<si_type>(b);
1573 eval_lcm(result, a, t);
1574 }
1575 template <class T, class Arithmetic>
1576 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Arithmetic>::value >::type eval_lcm(T& result, const Arithmetic& a, const T& b)
1577 {
1578 eval_lcm(result, b, a);
1579 }
1580
1581 template <class T>
1582 inline BOOST_MP_CXX14_CONSTEXPR std::size_t eval_lsb(const T& val)
1583 {
1584 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1585 int c = eval_get_sign(val);
1586 if (c == 0)
1587 {
1588 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1589 }
1590 if (c < 0)
1591 {
1592 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1593 }
1594 std::size_t result = 0;
1595 T mask, t;
1596 mask = ui_type(1);
1597 do
1598 {
1599 eval_bitwise_and(t, mask, val);
1600 ++result;
1601 eval_left_shift(mask, 1);
1602 } while (eval_is_zero(t));
1603
1604 return --result;
1605 }
1606
1607 template <class T>
1608 inline BOOST_MP_CXX14_CONSTEXPR std::ptrdiff_t eval_msb(const T& val)
1609 {
1610 int c = eval_get_sign(val);
1611 if (c == 0)
1612 {
1613 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1614 }
1615 if (c < 0)
1616 {
1617 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1618 }
1619 //
1620 // This implementation is really really rubbish - it does
1621 // a linear scan for the most-significant-bit. We should really
1622 // do a binary search, but as none of our backends actually needs
1623 // this implementation, we'll leave it for now. In fact for most
1624 // backends it's likely that there will always be a more efficient
1625 // native implementation possible.
1626 //
1627 std::size_t result = 0;
1628 T t(val);
1629 while (!eval_is_zero(t))
1630 {
1631 eval_right_shift(t, 1);
1632 ++result;
1633 }
1634 return --result;
1635 }
1636
1637 template <class T>
1638 inline BOOST_MP_CXX14_CONSTEXPR bool eval_bit_test(const T& val, std::size_t index)
1639 {
1640 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1641 T mask, t;
1642 mask = ui_type(1);
1643 eval_left_shift(mask, index);
1644 eval_bitwise_and(t, mask, val);
1645 return !eval_is_zero(t);
1646 }
1647
1648 template <class T>
1649 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_set(T& val, std::size_t index)
1650 {
1651 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1652 T mask;
1653 mask = ui_type(1);
1654 eval_left_shift(mask, index);
1655 eval_bitwise_or(val, mask);
1656 }
1657
1658 template <class T>
1659 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_flip(T& val, std::size_t index)
1660 {
1661 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1662 T mask;
1663 mask = ui_type(1);
1664 eval_left_shift(mask, index);
1665 eval_bitwise_xor(val, mask);
1666 }
1667
1668 template <class T>
1669 inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_unset(T& val, std::size_t index)
1670 {
1671 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1672 T mask, t;
1673 mask = ui_type(1);
1674 eval_left_shift(mask, index);
1675 eval_bitwise_and(t, mask, val);
1676 if (!eval_is_zero(t))
1677 eval_bitwise_xor(val, mask);
1678 }
1679
1680 template <class Backend>
1681 BOOST_MP_CXX14_CONSTEXPR void eval_qr(const Backend& x, const Backend& y, Backend& q, Backend& r);
1682
1683 template <class Backend>
1684 BOOST_MP_CXX14_CONSTEXPR void eval_karatsuba_sqrt(Backend& result, const Backend& x, Backend& r, Backend& t, size_t bits)
1685 {
1686 using default_ops::eval_is_zero;
1687 using default_ops::eval_subtract;
1688 using default_ops::eval_right_shift;
1689 using default_ops::eval_left_shift;
1690 using default_ops::eval_bit_set;
1691 using default_ops::eval_decrement;
1692 using default_ops::eval_bitwise_and;
1693 using default_ops::eval_add;
1694 using default_ops::eval_qr;
1695
1696 using small_uint = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
1697
1698 constexpr small_uint zero = 0u;
1699
1700 // we can calculate it faster with std::sqrt
1701 #ifdef BOOST_HAS_INT128
1702 if (bits <= 128)
1703 {
1704 uint128_type a{}, b{}, c{};
1705 eval_convert_to(&a, x);
1706 c = boost::multiprecision::detail::karatsuba_sqrt(a, b, bits);
1707 r = number<Backend>::canonical_value(b);
1708 result = number<Backend>::canonical_value(c);
1709 return;
1710 }
1711 #else
1712 if (bits <= std::numeric_limits<std::uintmax_t>::digits)
1713 {
1714 std::uintmax_t a{ 0 }, b{ 0 }, c{ 0 };
1715 eval_convert_to(&a, x);
1716 c = boost::multiprecision::detail::karatsuba_sqrt(a, b, bits);
1717 r = number<Backend>::canonical_value(b);
1718 result = number<Backend>::canonical_value(c);
1719 return;
1720 }
1721 #endif
1722 // https://hal.inria.fr/file/index/docid/72854/filename/RR-3805.pdf
1723 std::size_t b = bits / 4;
1724 Backend q(x);
1725 eval_right_shift(q, b * 2);
1726 Backend s;
1727 eval_karatsuba_sqrt(s, q, r, t, bits - b * 2);
1728 t = zero;
1729 eval_bit_set(t, static_cast<unsigned>(b * 2));
1730 eval_left_shift(r, b);
1731 eval_decrement(t);
1732 eval_bitwise_and(t, x);
1733 eval_right_shift(t, b);
1734 eval_add(t, r);
1735 eval_left_shift(s, 1u);
1736 eval_qr(t, s, q, r);
1737 eval_left_shift(r, b);
1738 t = zero;
1739 eval_bit_set(t, static_cast<unsigned>(b));
1740 eval_decrement(t);
1741 eval_bitwise_and(t, x);
1742 eval_add(r, t);
1743 eval_left_shift(s, b - 1);
1744 eval_add(s, q);
1745 eval_multiply(q, q);
1746 // we substract after, so it works for unsigned integers too
1747 if (r.compare(q) < 0)
1748 {
1749 t = s;
1750 eval_left_shift(t, 1u);
1751 eval_decrement(t);
1752 eval_add(r, t);
1753 eval_decrement(s);
1754 }
1755 eval_subtract(r, q);
1756 result = s;
1757 }
1758
1759 template <class B>
1760 void BOOST_MP_CXX14_CONSTEXPR eval_integer_sqrt_bitwise(B& s, B& r, const B& x)
1761 {
1762 //
1763 // This is slow bit-by-bit integer square root, see for example
1764 // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
1765 // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
1766 // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
1767 // at some point.
1768 //
1769 using ui_type = typename boost::multiprecision::detail::canonical<unsigned char, B>::type;
1770
1771 s = ui_type(0u);
1772 if (eval_get_sign(x) == 0)
1773 {
1774 r = ui_type(0u);
1775 return;
1776 }
1777 std::ptrdiff_t g = eval_msb(x);
1778 if (g <= 1)
1779 {
1780 s = ui_type(1);
1781 eval_subtract(r, x, s);
1782 return;
1783 }
1784
1785 B t;
1786 r = x;
1787 g /= 2;
1788 std::ptrdiff_t org_g = g;
1789 eval_bit_set(s, g);
1790 eval_bit_set(t, 2 * g);
1791 eval_subtract(r, x, t);
1792 --g;
1793 if (eval_get_sign(r) == 0)
1794 return;
1795 std::ptrdiff_t msbr = eval_msb(r);
1796 do
1797 {
1798 if (msbr >= org_g + g + 1)
1799 {
1800 t = s;
1801 eval_left_shift(t, g + 1);
1802 eval_bit_set(t, 2 * g);
1803 if (t.compare(r) <= 0)
1804 {
1805 BOOST_MP_ASSERT(g >= 0);
1806 eval_bit_set(s, g);
1807 eval_subtract(r, t);
1808 if (eval_get_sign(r) == 0)
1809 return;
1810 msbr = eval_msb(r);
1811 }
1812 }
1813 --g;
1814 } while (g >= 0);
1815 }
1816
1817 template <class Backend>
1818 BOOST_MP_CXX14_CONSTEXPR void eval_integer_sqrt(Backend& result, Backend& r, const Backend& x)
1819 {
1820 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
1821 // recursive Karatsuba sqrt can cause issues in constexpr context:
1822 if (BOOST_MP_IS_CONST_EVALUATED(result.size()))
1823 return eval_integer_sqrt_bitwise(result, r, x);
1824 #endif
1825 using small_uint = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
1826
1827 constexpr small_uint zero = 0u;
1828
1829 if (eval_is_zero(x))
1830 {
1831 r = zero;
1832 result = zero;
1833 return;
1834 }
1835 Backend t;
1836 eval_karatsuba_sqrt(result, x, r, t, eval_msb(x) + 1);
1837 }
1838
1839 template <class B>
1840 inline BOOST_MP_CXX14_CONSTEXPR void eval_conj(B& result, const B& val)
1841 {
1842 result = val; // assume non-complex result.
1843 }
1844 template <class B>
1845 inline BOOST_MP_CXX14_CONSTEXPR void eval_proj(B& result, const B& val)
1846 {
1847 result = val; // assume non-complex result.
1848 }
1849
1850 //
1851 // These have to implemented by the backend, declared here so that our macro generated code compiles OK.
1852 //
1853 template <class T>
1854 typename std::enable_if<sizeof(T) == 0>::type eval_floor();
1855 template <class T>
1856 typename std::enable_if<sizeof(T) == 0>::type eval_ceil();
1857 template <class T>
1858 typename std::enable_if<sizeof(T) == 0>::type eval_trunc();
1859 template <class T>
1860 typename std::enable_if<sizeof(T) == 0>::type eval_sqrt();
1861 template <class T>
1862 typename std::enable_if<sizeof(T) == 0>::type eval_ldexp();
1863 template <class T>
1864 typename std::enable_if<sizeof(T) == 0>::type eval_frexp();
1865 // TODO implement default versions of these:
1866 template <class T>
1867 typename std::enable_if<sizeof(T) == 0>::type eval_asinh();
1868 template <class T>
1869 typename std::enable_if<sizeof(T) == 0>::type eval_acosh();
1870 template <class T>
1871 typename std::enable_if<sizeof(T) == 0>::type eval_atanh();
1872
1873 //
1874 // eval_logb and eval_scalbn simply assume base 2 and forward to
1875 // eval_ldexp and eval_frexp:
1876 //
1877 template <class B>
1878 inline BOOST_MP_CXX14_CONSTEXPR typename B::exponent_type eval_ilogb(const B& val)
1879 {
1880 static_assert(!std::numeric_limits<number<B> >::is_specialized || (std::numeric_limits<number<B> >::radix == 2), "The default implementation of ilogb requires a base 2 number type");
1881 typename B::exponent_type e(0);
1882 switch (eval_fpclassify(val))
1883 {
1884 case FP_NAN:
1885 #ifdef FP_ILOGBNAN
1886 return FP_ILOGBNAN > 0 ? (std::numeric_limits<typename B::exponent_type>::max)() : (std::numeric_limits<typename B::exponent_type>::min)();
1887 #else
1888 return (std::numeric_limits<typename B::exponent_type>::max)();
1889 #endif
1890 case FP_INFINITE:
1891 return (std::numeric_limits<typename B::exponent_type>::max)();
1892 case FP_ZERO:
1893 return (std::numeric_limits<typename B::exponent_type>::min)();
1894 }
1895 B result;
1896 eval_frexp(result, val, &e);
1897 return e - 1;
1898 }
1899
1900 template <class B>
1901 inline BOOST_MP_CXX14_CONSTEXPR void eval_logb(B& result, const B& val)
1902 {
1903 switch (eval_fpclassify(val))
1904 {
1905 case FP_NAN:
1906 result = val;
1907 errno = EDOM;
1908 return;
1909 case FP_ZERO:
1910 result = std::numeric_limits<number<B> >::infinity().backend();
1911 result.negate();
1912 errno = ERANGE;
1913 return;
1914 case FP_INFINITE:
1915 result = val;
1916 if (eval_signbit(val))
1917 result.negate();
1918 return;
1919 }
1920 using max_t = typename std::conditional<std::is_same<std::intmax_t, long>::value, long long, std::intmax_t>::type;
1921 result = static_cast<max_t>(eval_ilogb(val));
1922 }
1923 template <class B, class A>
1924 inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbn(B& result, const B& val, A e)
1925 {
1926 static_assert(!std::numeric_limits<number<B> >::is_specialized || (std::numeric_limits<number<B> >::radix == 2), "The default implementation of scalbn requires a base 2 number type");
1927 eval_ldexp(result, val, static_cast<typename B::exponent_type>(e));
1928 }
1929 template <class B, class A>
1930 inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbln(B& result, const B& val, A e)
1931 {
1932 eval_scalbn(result, val, e);
1933 }
1934
1935 template <class T>
1936 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant<bool, true> const&, const std::integral_constant<bool, false>&)
1937 {
1938 return eval_fpclassify(val) == FP_NAN;
1939 }
1940 template <class T>
1941 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant<bool, false> const&, const std::integral_constant<bool, true>&)
1942 {
1943 return BOOST_MP_ISNAN(val);
1944 }
1945 template <class T>
1946 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T&, std::integral_constant<bool, false> const&, const std::integral_constant<bool, false>&)
1947 {
1948 return false;
1949 }
1950
1951 template <class T>
1952 inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val)
1953 {
1954 return is_arg_nan(val, std::integral_constant<bool, boost::multiprecision::detail::is_backend<T>::value>(), std::is_floating_point<T>());
1955 }
1956
1957 template <class T, class U, class V>
1958 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmax(T& result, const U& a, const V& b)
1959 {
1960 if (is_arg_nan(a))
1961 result = number<T>::canonical_value(b);
1962 else if (is_arg_nan(b))
1963 result = number<T>::canonical_value(a);
1964 else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
1965 result = number<T>::canonical_value(b);
1966 else
1967 result = number<T>::canonical_value(a);
1968 }
1969 template <class T, class U, class V>
1970 inline BOOST_MP_CXX14_CONSTEXPR void eval_fmin(T& result, const U& a, const V& b)
1971 {
1972 if (is_arg_nan(a))
1973 result = number<T>::canonical_value(b);
1974 else if (is_arg_nan(b))
1975 result = number<T>::canonical_value(a);
1976 else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
1977 result = number<T>::canonical_value(a);
1978 else
1979 result = number<T>::canonical_value(b);
1980 }
1981
1982 template <class R, class T, class U>
1983 inline BOOST_MP_CXX14_CONSTEXPR void eval_hypot(R& result, const T& a, const U& b)
1984 {
1985 //
1986 // Normalize x and y, so that both are positive and x >= y:
1987 //
1988 R x, y;
1989 x = number<R>::canonical_value(a);
1990 y = number<R>::canonical_value(b);
1991 if (eval_get_sign(x) < 0)
1992 x.negate();
1993 if (eval_get_sign(y) < 0)
1994 y.negate();
1995
1996 // Special case, see C99 Annex F.
1997 // The order of the if's is important: do not change!
1998 int c1 = eval_fpclassify(x);
1999 int c2 = eval_fpclassify(y);
2000
2001 if (c1 == FP_ZERO)
2002 {
2003 result = y;
2004 return;
2005 }
2006 if (c2 == FP_ZERO)
2007 {
2008 result = x;
2009 return;
2010 }
2011 if (c1 == FP_INFINITE)
2012 {
2013 result = x;
2014 return;
2015 }
2016 if ((c2 == FP_INFINITE) || (c2 == FP_NAN))
2017 {
2018 result = y;
2019 return;
2020 }
2021 if (c1 == FP_NAN)
2022 {
2023 result = x;
2024 return;
2025 }
2026
2027 if (eval_gt(y, x))
2028 x.swap(y);
2029
2030 eval_multiply(result, x, std::numeric_limits<number<R> >::epsilon().backend());
2031
2032 if (eval_gt(result, y))
2033 {
2034 result = x;
2035 return;
2036 }
2037
2038 R rat;
2039 eval_divide(rat, y, x);
2040 eval_multiply(result, rat, rat);
2041 eval_increment(result);
2042 eval_sqrt(rat, result);
2043 eval_multiply(result, rat, x);
2044 }
2045
2046 template <class R, class T>
2047 inline BOOST_MP_CXX14_CONSTEXPR void eval_nearbyint(R& result, const T& a)
2048 {
2049 eval_round(result, a);
2050 }
2051 template <class R, class T>
2052 inline BOOST_MP_CXX14_CONSTEXPR void eval_rint(R& result, const T& a)
2053 {
2054 eval_nearbyint(result, a);
2055 }
2056
2057 template <class T>
2058 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_backend<T>::value, int>::type eval_signbit(const T& val)
2059 {
2060 return eval_get_sign(val) < 0 ? 1 : 0;
2061 }
2062
2063 //
2064 // Real and imaginary parts:
2065 //
2066 template <class To, class From>
2067 inline BOOST_MP_CXX14_CONSTEXPR void eval_real(To& to, const From& from)
2068 {
2069 to = from;
2070 }
2071 template <class To, class From>
2072 inline BOOST_MP_CXX14_CONSTEXPR void eval_imag(To& to, const From&)
2073 {
2074 using ui_type = typename std::tuple_element<0, typename To::unsigned_types>::type;
2075 to = ui_type(0);
2076 }
2077
2078 } // namespace default_ops
2079 namespace default_ops_adl {
2080
2081 template <class To, class From>
2082 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real_imp(To& to, const From& from)
2083 {
2084 using to_component_type = typename component_type<number<To> >::type;
2085 typename to_component_type::backend_type to_component;
2086 to_component = from;
2087 eval_set_real(to, to_component);
2088 }
2089 template <class To, class From>
2090 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag_imp(To& to, const From& from)
2091 {
2092 using to_component_type = typename component_type<number<To> >::type;
2093 typename to_component_type::backend_type to_component;
2094 to_component = from;
2095 eval_set_imag(to, to_component);
2096 }
2097
2098 } // namespace default_ops_adl
2099 namespace default_ops {
2100
2101 template <class To, class From>
2102 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<To>::value == number_kind_complex>::type eval_set_real(To& to, const From& from)
2103 {
2104 default_ops_adl::eval_set_real_imp(to, from);
2105 }
2106 template <class To, class From>
2107 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<To>::value != number_kind_complex>::type eval_set_real(To& to, const From& from)
2108 {
2109 to = from;
2110 }
2111
2112 template <class To, class From>
2113 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag(To& to, const From& from)
2114 {
2115 default_ops_adl::eval_set_imag_imp(to, from);
2116 }
2117
2118 template <class T>
2119 inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real(T& to, const T& from)
2120 {
2121 to = from;
2122 }
2123 template <class T>
2124 void BOOST_MP_CXX14_CONSTEXPR eval_set_imag(T&, const T&)
2125 {
2126 static_assert(sizeof(T) == INT_MAX, "eval_set_imag needs to be specialised for each specific backend");
2127 }
2128
2129 //
2130 // These functions are implemented in separate files, but expanded inline here,
2131 // DO NOT CHANGE THE ORDER OF THESE INCLUDES:
2132 //
2133 #include <boost/multiprecision/detail/functions/constants.hpp>
2134 #include <boost/multiprecision/detail/functions/pow.hpp>
2135 #include <boost/multiprecision/detail/functions/trig.hpp>
2136
2137 } // namespace default_ops
2138
2139 //
2140 // Default versions of floating point classification routines:
2141 //
2142 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2143 inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2144 {
2145 using multiprecision::default_ops::eval_fpclassify;
2146 return eval_fpclassify(arg.backend());
2147 }
2148 template <class tag, class A1, class A2, class A3, class A4>
2149 inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2150 {
2151 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2152 return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2153 }
2154 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2155 inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2156 {
2157 int v = fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg);
2158 return (v != static_cast<int>(FP_INFINITE)) && (v != static_cast<int>(FP_NAN));
2159 }
2160 template <class tag, class A1, class A2, class A3, class A4>
2161 inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2162 {
2163 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2164 return isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2165 }
2166 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2167 inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2168 {
2169 return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_NAN);
2170 }
2171 template <class tag, class A1, class A2, class A3, class A4>
2172 inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2173 {
2174 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2175 return isnan BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2176 }
2177 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2178 inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2179 {
2180 return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_INFINITE);
2181 }
2182 template <class tag, class A1, class A2, class A3, class A4>
2183 inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2184 {
2185 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2186 return isinf BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2187 }
2188 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2189 inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2190 {
2191 return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_NORMAL);
2192 }
2193 template <class tag, class A1, class A2, class A3, class A4>
2194 inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2195 {
2196 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2197 return isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2198 }
2199
2200 // Default versions of sign manipulation functions, if individual backends can do better than this
2201 // (for example with signed zero), then they should overload these functions further:
2202
2203 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2204 inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2205 {
2206 return arg.sign();
2207 }
2208 template <class tag, class A1, class A2, class A3, class A4>
2209 inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2210 {
2211 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2212 return sign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2213 }
2214
2215 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2216 inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2217 {
2218 using default_ops::eval_signbit;
2219 return static_cast<bool>(eval_signbit(arg.backend()));
2220 }
2221 template <class tag, class A1, class A2, class A3, class A4>
2222 inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2223 {
2224 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2225 return static_cast<bool>(signbit BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)));
2226 }
2227 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2228 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2229 {
2230 return -arg;
2231 }
2232 template <class tag, class A1, class A2, class A3, class A4>
2233 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2234 {
2235 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2236 return changesign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2237 }
2238 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2239 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2240 {
2241 return (boost::multiprecision::signbit)(a) != (boost::multiprecision::signbit)(b) ? (boost::multiprecision::changesign)(a) : a;
2242 }
2243 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2244 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& b)
2245 {
2246 return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2247 }
2248 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2249 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2250 {
2251 return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2252 }
2253 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2254 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
2255 {
2256 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2257 return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2258 }
2259 //
2260 // real and imag:
2261 //
2262 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2263 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
2264 real(const multiprecision::number<Backend, ExpressionTemplates>& a)
2265 {
2266 using default_ops::eval_real;
2267 using result_type = typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type;
2268 boost::multiprecision::detail::scoped_default_precision<result_type> precision_guard(a);
2269 result_type result;
2270 eval_real(result.backend(), a.backend());
2271 return result;
2272 }
2273 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2274 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
2275 imag(const multiprecision::number<Backend, ExpressionTemplates>& a)
2276 {
2277 using default_ops::eval_imag;
2278 using result_type = typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type;
2279 boost::multiprecision::detail::scoped_default_precision<result_type> precision_guard(a);
2280 result_type result;
2281 eval_imag(result.backend(), a.backend());
2282 return result;
2283 }
2284
2285 template <class tag, class A1, class A2, class A3, class A4>
2286 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2287 real(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2288 {
2289 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2290 detail::scoped_default_precision<value_type> precision_guard(arg);
2291 return real(value_type(arg));
2292 }
2293
2294 template <class tag, class A1, class A2, class A3, class A4>
2295 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2296 imag(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2297 {
2298 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2299 detail::scoped_default_precision<value_type> precision_guard(arg);
2300 return imag(value_type(arg));
2301 }
2302
2303 //
2304 // Complex number functions, these are overloaded at the Backend level, we just provide the
2305 // expression template versions here, plus overloads for non-complex types:
2306 //
2307 #ifdef BOOST_MP_MATH_AVAILABLE
2308 template <class T, expression_template_option ExpressionTemplates>
2309 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates>>>::type::type
2310 abs(const number<T, ExpressionTemplates>& v)
2311 {
2312 return std::move(boost::math::hypot(real(v), imag(v)));
2313 }
2314 template <class tag, class A1, class A2, class A3, class A4>
2315 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_complex, component_type<typename detail::expression<tag, A1, A2, A3, A4>::result_type>>::type::type
2316 abs(const detail::expression<tag, A1, A2, A3, A4>& v)
2317 {
2318 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2319 return std::move(abs(static_cast<number_type>(v)));
2320 }
2321
2322 template <class T, expression_template_option ExpressionTemplates>
2323 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
2324 arg(const number<T, ExpressionTemplates>& v)
2325 {
2326 return std::move(atan2(imag(v), real(v)));
2327 }
2328 template <class T, expression_template_option ExpressionTemplates>
2329 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
2330 arg(const number<T, ExpressionTemplates>&)
2331 {
2332 return 0;
2333 }
2334 template <class tag, class A1, class A2, class A3, class A4>
2335 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_complex || number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename scalar_result_from_possible_complex<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
2336 arg(const detail::expression<tag, A1, A2, A3, A4>& v)
2337 {
2338 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2339 return std::move(arg(static_cast<number_type>(v)));
2340 }
2341 #endif // BOOST_MP_MATH_AVAILABLE
2342
2343 template <class T, expression_template_option ExpressionTemplates>
2344 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates>>>::type::type
2345 norm(const number<T, ExpressionTemplates>& v)
2346 {
2347 typename component_type<number<T, ExpressionTemplates> >::type a(real(v)), b(imag(v));
2348 return std::move(a * a + b * b);
2349 }
2350 template <class T, expression_template_option ExpressionTemplates>
2351 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value != number_kind_complex, typename scalar_result_from_possible_complex<number<T, ExpressionTemplates> >::type>::type
2352 norm(const number<T, ExpressionTemplates>& v)
2353 {
2354 return v * v;
2355 }
2356 template <class tag, class A1, class A2, class A3, class A4>
2357 inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2358 norm(const detail::expression<tag, A1, A2, A3, A4>& v)
2359 {
2360 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2361 return std::move(norm(static_cast<number_type>(v)));
2362 }
2363
2364 template <class Backend, expression_template_option ExpressionTemplates>
2365 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r, number<Backend, ExpressionTemplates> const& theta)
2366 {
2367 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2368 }
2369
2370 template <class tag, class A1, class A2, class A3, class A4, class Backend, expression_template_option ExpressionTemplates>
2371 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, ExpressionTemplates> >::value,
2372 typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2373 polar(detail::expression<tag, A1, A2, A3, A4> const& r, number<Backend, ExpressionTemplates> const& theta)
2374 {
2375 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2376 }
2377
2378 template <class Backend, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2379 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, ExpressionTemplates> >::value,
2380 typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2381 polar(number<Backend, ExpressionTemplates> const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2382 {
2383 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2384 }
2385
2386 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2387 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, typename detail::expression<tagb, A1b, A2b, A3b, A4b>::result_type>::value,
2388 typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
2389 polar(detail::expression<tag, A1, A2, A3, A4> const& r, detail::expression<tagb, A1b, A2b, A3b, A4b> const& theta)
2390 {
2391 using scalar_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2392 return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2393 }
2394 //
2395 // We also allow the first argument to polar to be an arithmetic type (probably a literal):
2396 //
2397 template <class Scalar, class Backend, expression_template_option ExpressionTemplates>
2398 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<Scalar>::value, typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2399 polar(Scalar const& r, number<Backend, ExpressionTemplates> const& theta)
2400 {
2401 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2402 }
2403
2404 template <class tag, class A1, class A2, class A3, class A4, class Scalar>
2405 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<Scalar>::value,
2406 typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
2407 polar(Scalar const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2408 {
2409 using scalar_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2410 return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2411 }
2412 //
2413 // Single argument overloads:
2414 //
2415 template <class Backend, expression_template_option ExpressionTemplates>
2416 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r)
2417 {
2418 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(r);
2419 }
2420
2421 template <class tag, class A1, class A2, class A3, class A4>
2422 BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2423 polar(detail::expression<tag, A1, A2, A3, A4> const& r)
2424 {
2425 return typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type(r);
2426 }
2427
2428 } // namespace multiprecision
2429
2430 namespace math {
2431
2432 //
2433 // Import Math functions here, so they can be found by Boost.Math:
2434 //
2435 using boost::multiprecision::changesign;
2436 using boost::multiprecision::copysign;
2437 using boost::multiprecision::fpclassify;
2438 using boost::multiprecision::isfinite;
2439 using boost::multiprecision::isinf;
2440 using boost::multiprecision::isnan;
2441 using boost::multiprecision::isnormal;
2442 using boost::multiprecision::sign;
2443 using boost::multiprecision::signbit;
2444
2445 #ifndef BOOST_MP_MATH_AVAILABLE
2446 namespace policies {
2447
2448 template <typename... Args>
2449 class policy {};
2450
2451 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2452 void raise_rounding_error(T1, T2, T3, T4, T5)
2453 {
2454 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Rounding error"));
2455 }
2456
2457 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2458 void raise_overflow_error(T1, T2, T3, T4, T5)
2459 {
2460 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Overflow error"));
2461 }
2462
2463 template <typename T1, typename T2, typename T3, typename T4, typename T5>
2464 void raise_evaluation_error(T1, T2, T3, T4, T5)
2465 {
2466 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Evaluation error"));
2467 }
2468
2469 template <typename T, typename... Args>
2470 struct is_policy
2471 {
2472 static constexpr bool value = false;
2473 };
2474
2475 template <typename... Args>
2476 struct is_policy<policy<Args...>>
2477 {
2478 static constexpr bool value = true;
2479 };
2480
2481 } // namespace policies
2482 #endif
2483
2484 } // namespace math
2485
2486 namespace multiprecision {
2487 #ifdef BOOST_MP_MATH_AVAILABLE
2488 using c99_error_policy = ::boost::math::policies::policy<
2489 ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>,
2490 ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>,
2491 ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>,
2492 ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>,
2493 ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error> >;
2494
2495 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2496 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2497 asinh
2498 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2499 {
2500 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2501 return boost::math::asinh(arg, c99_error_policy());
2502 }
2503 template <class tag, class A1, class A2, class A3, class A4>
2504 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex, typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2505 asinh
2506 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2507 {
2508 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2509 detail::scoped_default_precision<value_type> precision_guard(arg);
2510 return asinh(value_type(arg));
2511 }
2512 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2513 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2514 acosh
2515 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2516 {
2517 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2518 return boost::math::acosh(arg, c99_error_policy());
2519 }
2520 template <class tag, class A1, class A2, class A3, class A4>
2521 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex, typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2522 acosh
2523 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2524 {
2525 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2526 detail::scoped_default_precision<value_type> precision_guard(arg);
2527 return acosh(value_type(arg));
2528 }
2529 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2530 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2531 atanh
2532 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2533 {
2534 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2535 return boost::math::atanh(arg, c99_error_policy());
2536 }
2537 template <class tag, class A1, class A2, class A3, class A4>
2538 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex, typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2539 atanh
2540 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2541 {
2542 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2543 detail::scoped_default_precision<value_type> precision_guard(arg);
2544 return atanh(value_type(arg));
2545 }
2546 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2547 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2548 {
2549 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2550 return boost::math::cbrt(arg, c99_error_policy());
2551 }
2552 template <class tag, class A1, class A2, class A3, class A4>
2553 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2554 {
2555 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2556 detail::scoped_default_precision<value_type> precision_guard(arg);
2557 return cbrt(value_type(arg));
2558 }
2559 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2560 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2561 {
2562 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2563 return boost::math::erf(arg, c99_error_policy());
2564 }
2565 template <class tag, class A1, class A2, class A3, class A4>
2566 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2567 {
2568 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2569 detail::scoped_default_precision<value_type> precision_guard(arg);
2570 return erf(value_type(arg));
2571 }
2572 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2573 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2574 {
2575 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2576 return boost::math::erfc(arg, c99_error_policy());
2577 }
2578 template <class tag, class A1, class A2, class A3, class A4>
2579 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2580 {
2581 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2582 detail::scoped_default_precision<value_type> precision_guard(arg);
2583 return erfc(value_type(arg));
2584 }
2585 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2586 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2587 {
2588 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2589 return boost::math::expm1(arg, c99_error_policy());
2590 }
2591 template <class tag, class A1, class A2, class A3, class A4>
2592 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2593 {
2594 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2595 detail::scoped_default_precision<value_type> precision_guard(arg);
2596 return expm1(value_type(arg));
2597 }
2598 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2599 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2600 {
2601 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2602 multiprecision::number<Backend, ExpressionTemplates> result;
2603 result = boost::math::lgamma(arg, c99_error_policy());
2604 if ((boost::multiprecision::isnan)(result) && !(boost::multiprecision::isnan)(arg))
2605 {
2606 result = std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::infinity();
2607 errno = ERANGE;
2608 }
2609 return result;
2610 }
2611 template <class tag, class A1, class A2, class A3, class A4>
2612 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2613 {
2614 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2615 detail::scoped_default_precision<value_type> precision_guard(arg);
2616 return lgamma(value_type(arg));
2617 }
2618 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2619 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2620 {
2621 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2622 if ((arg == 0) && std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::has_infinity)
2623 {
2624 errno = ERANGE;
2625 return 1 / arg;
2626 }
2627 return boost::math::tgamma(arg, c99_error_policy());
2628 }
2629 template <class tag, class A1, class A2, class A3, class A4>
2630 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2631 {
2632 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2633 detail::scoped_default_precision<value_type> precision_guard(arg);
2634 return tgamma(value_type(arg));
2635 }
2636
2637 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2638 inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2639 {
2640 return lround(arg);
2641 }
2642 template <class tag, class A1, class A2, class A3, class A4>
2643 inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2644 {
2645 return lround(arg);
2646 }
2647 #ifndef BOOST_NO_LONG_LONG
2648 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2649 inline BOOST_MP_CXX14_CONSTEXPR long long llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2650 {
2651 return llround(arg);
2652 }
2653 template <class tag, class A1, class A2, class A3, class A4>
2654 inline BOOST_MP_CXX14_CONSTEXPR long long llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2655 {
2656 return llround(arg);
2657 }
2658 #endif
2659 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2660 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2661 {
2662 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2663 return boost::math::log1p(arg, c99_error_policy());
2664 }
2665 template <class tag, class A1, class A2, class A3, class A4>
2666 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2667 {
2668 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2669 detail::scoped_default_precision<value_type> precision_guard(arg);
2670 return log1p(value_type(arg));
2671 }
2672
2673 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2674 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2675 {
2676 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2677 return boost::math::nextafter(a, b, c99_error_policy());
2678 }
2679 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2680 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& b)
2681 {
2682 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2683 return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2684 }
2685 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2686 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2687 {
2688 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2689 return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2690 }
2691 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2692 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
2693 {
2694 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2695 detail::scoped_default_precision<value_type> precision_guard(a, b);
2696 return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2697 }
2698 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2699 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2700 {
2701 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2702 return boost::math::nextafter(a, b, c99_error_policy());
2703 }
2704 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2705 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& a, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& b)
2706 {
2707 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2708 return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2709 }
2710 template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2711 inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::number<Backend, ExpressionTemplates>& b)
2712 {
2713 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2714 return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2715 }
2716 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2717 inline BOOST_MP_CXX14_CONSTEXPR typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& a, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
2718 {
2719 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2720 detail::scoped_default_precision<value_type> precision_guard(a, b);
2721 return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2722 }
2723 #endif // BOOST_MP_MATH_AVAILABLE
2724
2725 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2726 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& add(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2727 {
2728 static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2729 static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2730 using default_ops::eval_add;
2731 eval_add(result.backend(), a.backend(), b.backend());
2732 return result;
2733 }
2734
2735 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2736 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& subtract(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2737 {
2738 static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2739 static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2740 using default_ops::eval_subtract;
2741 eval_subtract(result.backend(), a.backend(), b.backend());
2742 return result;
2743 }
2744
2745 template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2746 inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& multiply(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2747 {
2748 static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2749 static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2750 using default_ops::eval_multiply;
2751 eval_multiply(result.backend(), a.backend(), b.backend());
2752 return result;
2753 }
2754
2755 template <class B, expression_template_option ET, class I>
2756 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2757 add(number<B, ET>& result, const I& a, const I& b)
2758 {
2759 using default_ops::eval_add;
2760 using canonical_type = typename detail::canonical<I, B>::type;
2761 eval_add(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2762 return result;
2763 }
2764
2765 template <class B, expression_template_option ET, class I>
2766 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2767 subtract(number<B, ET>& result, const I& a, const I& b)
2768 {
2769 using default_ops::eval_subtract;
2770 using canonical_type = typename detail::canonical<I, B>::type;
2771 eval_subtract(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2772 return result;
2773 }
2774
2775 template <class B, expression_template_option ET, class I>
2776 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2777 multiply(number<B, ET>& result, const I& a, const I& b)
2778 {
2779 using default_ops::eval_multiply;
2780 using canonical_type = typename detail::canonical<I, B>::type;
2781 eval_multiply(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2782 return result;
2783 }
2784
2785 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2786 inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression<tag, A1, A2, A3, A4>::result_type trunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2787 {
2788 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2789 return std::move(trunc(number_type(v), pol));
2790 }
2791
2792 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2793 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates> trunc(const number<Backend, ExpressionTemplates>& v, const Policy&)
2794 {
2795 using default_ops::eval_trunc;
2796 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(v);
2797 number<Backend, ExpressionTemplates> result;
2798 eval_trunc(result.backend(), v.backend());
2799 return result;
2800 }
2801
2802 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2803 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2804 {
2805 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2806 number_type r(trunc(v, pol));
2807 if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2808 return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, number_type(v), 0, pol);
2809 return r.template convert_to<int>();
2810 }
2811 template <class tag, class A1, class A2, class A3, class A4>
2812 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2813 {
2814 return itrunc(v, boost::math::policies::policy<>());
2815 }
2816 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2817 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v, const Policy& pol)
2818 {
2819 number<Backend, ExpressionTemplates> r(trunc(v, pol));
2820 if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2821 return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, v, 0, pol);
2822 return r.template convert_to<int>();
2823 }
2824 template <class Backend, expression_template_option ExpressionTemplates>
2825 inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v)
2826 {
2827 return itrunc(v, boost::math::policies::policy<>());
2828 }
2829 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2830 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2831 {
2832 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2833 number_type r(trunc(v, pol));
2834 if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2835 return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, number_type(v), 0L, pol);
2836 return r.template convert_to<long>();
2837 }
2838 template <class tag, class A1, class A2, class A3, class A4>
2839 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2840 {
2841 return ltrunc(v, boost::math::policies::policy<>());
2842 }
2843 template <class T, expression_template_option ExpressionTemplates, class Policy>
2844 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2845 {
2846 number<T, ExpressionTemplates> r(trunc(v, pol));
2847 if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2848 return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, v, 0L, pol);
2849 return r.template convert_to<long>();
2850 }
2851 template <class T, expression_template_option ExpressionTemplates>
2852 inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v)
2853 {
2854 return ltrunc(v, boost::math::policies::policy<>());
2855 }
2856 #ifndef BOOST_NO_LONG_LONG
2857 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2858 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2859 {
2860 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2861 number_type r(trunc(v, pol));
2862 if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2863 return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, number_type(v), 0LL, pol);
2864 return r.template convert_to<long long>();
2865 }
2866 template <class tag, class A1, class A2, class A3, class A4>
2867 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2868 {
2869 return lltrunc(v, boost::math::policies::policy<>());
2870 }
2871 template <class T, expression_template_option ExpressionTemplates, class Policy>
2872 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2873 {
2874 number<T, ExpressionTemplates> r(trunc(v, pol));
2875 if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2876 return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, v, 0LL, pol);
2877 return r.template convert_to<long long>();
2878 }
2879 template <class T, expression_template_option ExpressionTemplates>
2880 inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const number<T, ExpressionTemplates>& v)
2881 {
2882 return lltrunc(v, boost::math::policies::policy<>());
2883 }
2884 #endif
2885 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2886 inline BOOST_MP_CXX14_CONSTEXPR typename detail::expression<tag, A1, A2, A3, A4>::result_type round(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2887 {
2888 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2889 return std::move(round(static_cast<number_type>(v), pol));
2890 }
2891 template <class T, expression_template_option ExpressionTemplates, class Policy>
2892 inline BOOST_MP_CXX14_CONSTEXPR number<T, ExpressionTemplates> round(const number<T, ExpressionTemplates>& v, const Policy&)
2893 {
2894 using default_ops::eval_round;
2895 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2896 number<T, ExpressionTemplates> result;
2897 eval_round(result.backend(), v.backend());
2898 return result;
2899 }
2900
2901 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2902 inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2903 {
2904 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2905 number_type r(round(v, pol));
2906 if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2907 return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0, pol);
2908 return r.template convert_to<int>();
2909 }
2910 template <class tag, class A1, class A2, class A3, class A4>
2911 inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v)
2912 {
2913 return iround(v, boost::math::policies::policy<>());
2914 }
2915 template <class T, expression_template_option ExpressionTemplates, class Policy>
2916 inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2917 {
2918 number<T, ExpressionTemplates> r(round(v, pol));
2919 if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2920 return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0, pol);
2921 return r.template convert_to<int>();
2922 }
2923 template <class T, expression_template_option ExpressionTemplates>
2924 inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v)
2925 {
2926 return iround(v, boost::math::policies::policy<>());
2927 }
2928 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2929 inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2930 {
2931 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2932 number_type r(round(v, pol));
2933 if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2934 return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, number_type(v), 0L, pol);
2935 return r.template convert_to<long>();
2936 }
2937 template <class tag, class A1, class A2, class A3, class A4>
2938 inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v)
2939 {
2940 return lround(v, boost::math::policies::policy<>());
2941 }
2942 template <class T, expression_template_option ExpressionTemplates, class Policy>
2943 inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2944 {
2945 number<T, ExpressionTemplates> r(round(v, pol));
2946 if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2947 return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, v, 0L, pol);
2948 return r.template convert_to<long>();
2949 }
2950 template <class T, expression_template_option ExpressionTemplates>
2951 inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v)
2952 {
2953 return lround(v, boost::math::policies::policy<>());
2954 }
2955 #ifndef BOOST_NO_LONG_LONG
2956 template <class tag, class A1, class A2, class A3, class A4, class Policy>
2957 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2958 {
2959 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2960 number_type r(round(v, pol));
2961 if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2962 return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0LL, pol);
2963 return r.template convert_to<long long>();
2964 }
2965 template <class tag, class A1, class A2, class A3, class A4>
2966 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const detail::expression<tag, A1, A2, A3, A4>& v)
2967 {
2968 return llround(v, boost::math::policies::policy<>());
2969 }
2970 template <class T, expression_template_option ExpressionTemplates, class Policy>
2971 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2972 {
2973 number<T, ExpressionTemplates> r(round(v, pol));
2974 if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2975 return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0LL, pol);
2976 return r.template convert_to<long long>();
2977 }
2978 template <class T, expression_template_option ExpressionTemplates>
2979 inline BOOST_MP_CXX14_CONSTEXPR long long llround(const number<T, ExpressionTemplates>& v)
2980 {
2981 return llround(v, boost::math::policies::policy<>());
2982 }
2983 #endif
2984 //
2985 // frexp does not return an expression template since we require the
2986 // integer argument to be evaluated even if the returned value is
2987 // not assigned to anything...
2988 //
2989 template <class T, expression_template_option ExpressionTemplates>
2990 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, short* pint)
2991 {
2992 using default_ops::eval_frexp;
2993 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2994 number<T, ExpressionTemplates> result;
2995 eval_frexp(result.backend(), v.backend(), pint);
2996 return result;
2997 }
2998 template <class tag, class A1, class A2, class A3, class A4>
2999 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
3000 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, short* pint)
3001 {
3002 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3003 return std::move(frexp(static_cast<number_type>(v), pint));
3004 }
3005 template <class T, expression_template_option ExpressionTemplates>
3006 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, int* pint)
3007 {
3008 using default_ops::eval_frexp;
3009 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3010 number<T, ExpressionTemplates> result;
3011 eval_frexp(result.backend(), v.backend(), pint);
3012 return result;
3013 }
3014 template <class tag, class A1, class A2, class A3, class A4>
3015 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
3016 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, int* pint)
3017 {
3018 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3019 return std::move(frexp(static_cast<number_type>(v), pint));
3020 }
3021 template <class T, expression_template_option ExpressionTemplates>
3022 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, long* pint)
3023 {
3024 using default_ops::eval_frexp;
3025 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3026 number<T, ExpressionTemplates> result;
3027 eval_frexp(result.backend(), v.backend(), pint);
3028 return result;
3029 }
3030 template <class tag, class A1, class A2, class A3, class A4>
3031 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
3032 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long* pint)
3033 {
3034 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3035 return std::move(frexp(static_cast<number_type>(v), pint));
3036 }
3037 template <class T, expression_template_option ExpressionTemplates>
3038 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type frexp(const number<T, ExpressionTemplates>& v, long long* pint)
3039 {
3040 using default_ops::eval_frexp;
3041 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3042 number<T, ExpressionTemplates> result;
3043 eval_frexp(result.backend(), v.backend(), pint);
3044 return result;
3045 }
3046 template <class tag, class A1, class A2, class A3, class A4>
3047 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_floating_point, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
3048 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long long* pint)
3049 {
3050 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3051 return std::move(frexp(static_cast<number_type>(v), pint));
3052 }
3053 //
3054 // modf does not return an expression template since we require the
3055 // second argument to be evaluated even if the returned value is
3056 // not assigned to anything...
3057 //
3058 template <class T, expression_template_option ExpressionTemplates>
3059 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type modf(const number<T, ExpressionTemplates>& v, number<T, ExpressionTemplates>* pipart)
3060 {
3061 using default_ops::eval_modf;
3062 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3063 number<T, ExpressionTemplates> result;
3064 eval_modf(result.backend(), v.backend(), pipart ? &pipart->backend() : 0);
3065 return result;
3066 }
3067 template <class T, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
3068 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_floating_point, number<T, ExpressionTemplates> >::type modf(const detail::expression<tag, A1, A2, A3, A4>& v, number<T, ExpressionTemplates>* pipart)
3069 {
3070 using default_ops::eval_modf;
3071 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3072 number<T, ExpressionTemplates> result, arg(v);
3073 eval_modf(result.backend(), arg.backend(), pipart ? &pipart->backend() : 0);
3074 return result;
3075 }
3076
3077 //
3078 // Integer square root:
3079 //
3080 template <class B, expression_template_option ExpressionTemplates>
3081 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3082 sqrt(const number<B, ExpressionTemplates>& x)
3083 {
3084 using default_ops::eval_integer_sqrt;
3085 number<B, ExpressionTemplates> s, r;
3086 eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3087 return s;
3088 }
3089 template <class tag, class A1, class A2, class A3, class A4>
3090 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
3091 sqrt(const detail::expression<tag, A1, A2, A3, A4>& arg)
3092 {
3093 using default_ops::eval_integer_sqrt;
3094 using result_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3095 detail::scoped_default_precision<result_type> precision_guard(arg);
3096 result_type result, v(arg), r;
3097 eval_integer_sqrt(result.backend(), r.backend(), v.backend());
3098 return result;
3099 }
3100
3101 //
3102 // fma:
3103 //
3104
3105 namespace default_ops {
3106
3107 struct fma_func
3108 {
3109 template <class B, class T, class U, class V>
3110 BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, const V& c) const
3111 {
3112 eval_multiply_add(result, a, b, c);
3113 }
3114 };
3115
3116 } // namespace default_ops
3117
3118 template <class Backend, class U, class V>
3119 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3120 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3121 (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3122 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3123 detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V> >::type
3124 fma(const number<Backend, et_on>& a, const U& b, const V& c)
3125 {
3126 return detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V>(
3127 default_ops::fma_func(), a, b, c);
3128 }
3129
3130 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U, class V>
3131 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3132 (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3133 (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3134 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3135 detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V> >::type
3136 fma(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, const V& c)
3137 {
3138 return detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V>(
3139 default_ops::fma_func(), a, b, c);
3140 }
3141
3142 template <class Backend, class U, class V>
3143 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3144 (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3145 (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3146 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3147 number<Backend, et_off> >::type
3148 fma(const number<Backend, et_off>& a, const U& b, const V& c)
3149 {
3150 using default_ops::eval_multiply_add;
3151 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3152 number<Backend, et_off> result;
3153 eval_multiply_add(result.backend(), number<Backend, et_off>::canonical_value(a), number<Backend, et_off>::canonical_value(b), number<Backend, et_off>::canonical_value(c));
3154 return result;
3155 }
3156
3157 template <class U, class Backend, class V>
3158 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3159 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3160 boost::multiprecision::detail::is_arithmetic<U>::value &&
3161 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3162 detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V> >::type
3163 fma(const U& a, const number<Backend, et_on>& b, const V& c)
3164 {
3165 return detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V>(
3166 default_ops::fma_func(), a, b, c);
3167 }
3168
3169 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
3170 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3171 (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3172 boost::multiprecision::detail::is_arithmetic<U>::value &&
3173 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3174 detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V> >::type
3175 fma(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, const V& c)
3176 {
3177 return detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V>(
3178 default_ops::fma_func(), a, b, c);
3179 }
3180
3181 template <class U, class Backend, class V>
3182 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3183 (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3184 boost::multiprecision::detail::is_arithmetic<U>::value &&
3185 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3186 number<Backend, et_off> >::type
3187 fma(const U& a, const number<Backend, et_off>& b, const V& c)
3188 {
3189 using default_ops::eval_multiply_add;
3190 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3191 number<Backend, et_off> result;
3192 eval_multiply_add(result.backend(), number<Backend, et_off>::canonical_value(a), number<Backend, et_off>::canonical_value(b), number<Backend, et_off>::canonical_value(c));
3193 return result;
3194 }
3195
3196 template <class U, class V, class Backend>
3197 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3198 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3199 boost::multiprecision::detail::is_arithmetic<U>::value &&
3200 boost::multiprecision::detail::is_arithmetic<V>::value,
3201 detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> > >::type
3202 fma(const U& a, const V& b, const number<Backend, et_on>& c)
3203 {
3204 return detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> >(
3205 default_ops::fma_func(), a, b, c);
3206 }
3207
3208 template <class U, class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3209 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3210 (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3211 boost::multiprecision::detail::is_arithmetic<U>::value &&
3212 boost::multiprecision::detail::is_arithmetic<V>::value,
3213 detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
3214 fma(const U& a, const V& b, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& c)
3215 {
3216 return detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(
3217 default_ops::fma_func(), a, b, c);
3218 }
3219
3220 template <class U, class V, class Backend>
3221 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3222 (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3223 boost::multiprecision::detail::is_arithmetic<U>::value &&
3224 boost::multiprecision::detail::is_arithmetic<V>::value,
3225 number<Backend, et_off> >::type
3226 fma(const U& a, const V& b, const number<Backend, et_off>& c)
3227 {
3228 using default_ops::eval_multiply_add;
3229 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3230 number<Backend, et_off> result;
3231 eval_multiply_add(result.backend(), number<Backend, et_off>::canonical_value(a), number<Backend, et_off>::canonical_value(b), number<Backend, et_off>::canonical_value(c));
3232 return result;
3233 }
3234
3235 namespace default_ops {
3236
3237 struct remquo_func
3238 {
3239 template <class B, class T, class U>
3240 BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, int* pi) const
3241 {
3242 eval_remquo(result, a, b, pi);
3243 }
3244 };
3245
3246 } // namespace default_ops
3247
3248 template <class Backend, class U>
3249 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3250 number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3251 detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*> >::type
3252 remquo(const number<Backend, et_on>& a, const U& b, int* pi)
3253 {
3254 return detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*>(
3255 default_ops::remquo_func(), a, b, pi);
3256 }
3257
3258 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U>
3259 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3260 number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point,
3261 detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*> >::type
3262 remquo(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, int* pi)
3263 {
3264 return detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*>(
3265 default_ops::remquo_func(), a, b, pi);
3266 }
3267
3268 template <class U, class Backend>
3269 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3270 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3271 detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*> >::type
3272 remquo(const U& a, const number<Backend, et_on>& b, int* pi)
3273 {
3274 return detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*>(
3275 default_ops::remquo_func(), a, b, pi);
3276 }
3277
3278 template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3279 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3280 (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3281 detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*> >::type
3282 remquo(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, int* pi)
3283 {
3284 return detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*>(
3285 default_ops::remquo_func(), a, b, pi);
3286 }
3287
3288 template <class Backend, class U>
3289 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3290 number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3291 number<Backend, et_off> >::type
3292 remquo(const number<Backend, et_off>& a, const U& b, int* pi)
3293 {
3294 using default_ops::eval_remquo;
3295 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3296 number<Backend, et_off> result;
3297 eval_remquo(result.backend(), a.backend(), number<Backend, et_off>::canonical_value(b), pi);
3298 return result;
3299 }
3300 template <class U, class Backend>
3301 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3302 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3303 number<Backend, et_off> >::type
3304 remquo(const U& a, const number<Backend, et_off>& b, int* pi)
3305 {
3306 using default_ops::eval_remquo;
3307 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3308 number<Backend, et_off> result;
3309 eval_remquo(result.backend(), number<Backend, et_off>::canonical_value(a), b.backend(), pi);
3310 return result;
3311 }
3312
3313 template <class B, expression_template_option ExpressionTemplates>
3314 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3315 sqrt(const number<B, ExpressionTemplates>& x, number<B, ExpressionTemplates>& r)
3316 {
3317 using default_ops::eval_integer_sqrt;
3318 detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(x, r);
3319 number<B, ExpressionTemplates> s;
3320 eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3321 return s;
3322 }
3323 template <class B, expression_template_option ExpressionTemplates, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3324 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3325 sqrt(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& arg, number<B, ExpressionTemplates>& r)
3326 {
3327 using default_ops::eval_integer_sqrt;
3328 detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(r);
3329 number<B, ExpressionTemplates> s;
3330 number<B, ExpressionTemplates> x(arg);
3331 eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3332 return s;
3333 }
3334
3335 // clang-format off
3336 //
3337 // Regrettably, when the argument to a function is an rvalue we must return by value, and not return an
3338 // expression template, otherwise we can end up with dangling references.
3339 // See https://github.com/boostorg/multiprecision/issues/175.
3340 //
3341 #define UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3342 template <class Backend> \
3343 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> > ::type \
3344 func(number<Backend, et_on>&& arg) \
3345 { \
3346 detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg); \
3347 number<Backend, et_on> result; \
3348 using default_ops::BOOST_JOIN(eval_, func); \
3349 BOOST_JOIN(eval_, func)(result.backend(), arg.backend()); \
3350 return result; \
3351 } \
3352
3353 #define BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3354 template <class Backend> \
3355 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> >::type func(number<Backend, et_on>&& arg, const number<Backend, et_on>& a) \
3356 { \
3357 detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a); \
3358 number<Backend, et_on> result; \
3359 using default_ops::BOOST_JOIN(eval_, func); \
3360 BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \
3361 return result; \
3362 } \
3363 template <class Backend> \
3364 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> >::type func(const number<Backend, et_on>& arg, number<Backend, et_on>&& a) \
3365 { \
3366 detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a); \
3367 number<Backend, et_on> result; \
3368 using default_ops::BOOST_JOIN(eval_, func); \
3369 BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \
3370 return result; \
3371 } \
3372 template <class Backend> \
3373 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> >::type func(number<Backend, et_on>&& arg, number<Backend, et_on>&& a) \
3374 { \
3375 detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a); \
3376 number<Backend, et_on> result; \
3377 using default_ops::BOOST_JOIN(eval_, func); \
3378 BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \
3379 return result; \
3380 } \
3381 template <class Backend, class tag, class A1, class A2, class A3, class A4> \
3382 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category) && (std::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value), \
3383 number<Backend, et_on> > ::type \
3384 func(number<Backend, et_on>&& arg, const detail::expression<tag, A1, A2, A3, A4>& a) \
3385 { \
3386 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3387 number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3388 } \
3389 template <class tag, class A1, class A2, class A3, class A4, class Backend> \
3390 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category) && (std::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value), \
3391 number<Backend, et_on> > ::type \
3392 func(const detail::expression<tag, A1, A2, A3, A4>& arg, number<Backend, et_on>&& a) \
3393 { \
3394 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3395 detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3396 } \
3397 template <class Backend, class Arithmetic> \
3398 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3399 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category), \
3400 number<Backend, et_on> >::type \
3401 func(number<Backend, et_on>&& arg, const Arithmetic& a) \
3402 { \
3403 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, \
3404 number<Backend, et_on>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3405 } \
3406 template <class Backend, class Arithmetic> \
3407 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3408 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category), \
3409 number<Backend, et_on> > ::type \
3410 func(const Arithmetic& arg, number<Backend, et_on>&& a) \
3411 { \
3412 return detail::expression< \
3413 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3414 Arithmetic, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a); \
3415 } \
3416
3417
3418 #define UNARY_OP_FUNCTOR(func, category) \
3419 namespace detail { \
3420 template <class Backend> \
3421 struct BOOST_JOIN(category, BOOST_JOIN(func, _funct)) \
3422 { \
3423 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const \
3424 { \
3425 using default_ops::BOOST_JOIN(eval_, func); \
3426 BOOST_JOIN(eval_, func) \
3427 (result, arg); \
3428 } \
3429 template <class U> \
3430 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg) const \
3431 { \
3432 using default_ops::BOOST_JOIN(eval_, func); \
3433 Backend temp; \
3434 BOOST_JOIN(eval_, func) \
3435 (temp, arg); \
3436 result = std::move(temp); \
3437 } \
3438 }; \
3439 } \
3440 \
3441 template <class tag, class A1, class A2, class A3, class A4> \
3442 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category, \
3443 detail::expression<detail::function, \
3444 detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3445 detail::expression<tag, A1, A2, A3, A4> > > ::type \
3446 func(const detail::expression<tag, A1, A2, A3, A4>& arg) \
3447 { \
3448 return detail::expression< \
3449 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3450 detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type > (), arg); \
3451 } \
3452 template <class Backend> \
3453 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, \
3454 detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, number<Backend, et_on> > > ::type \
3455 func(const number<Backend, et_on>& arg) \
3456 { \
3457 return detail::expression< \
3458 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3459 number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg); \
3460 } \
3461 template <class Backend> \
3462 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3463 boost::multiprecision::number_category<Backend>::value == category, \
3464 number<Backend, et_off> >::type \
3465 func(const number<Backend, et_off>& arg) \
3466 { \
3467 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg); \
3468 number<Backend, et_off> result; \
3469 using default_ops::BOOST_JOIN(eval_, func); \
3470 BOOST_JOIN(eval_, func)(result.backend(), arg.backend()); \
3471 return result; \
3472 }\
3473 UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3474
3475 #define BINARY_OP_FUNCTOR(func, category) \
3476 namespace detail { \
3477 template <class Backend> \
3478 struct BOOST_JOIN(category, BOOST_JOIN(func, _funct)) \
3479 { \
3480 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Backend& a) const \
3481 { \
3482 using default_ops::BOOST_JOIN(eval_, func); \
3483 BOOST_JOIN(eval_, func) \
3484 (result, arg, a); \
3485 } \
3486 template <class Arithmetic> \
3487 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Arithmetic& a) const \
3488 { \
3489 using default_ops::BOOST_JOIN(eval_, func); \
3490 BOOST_JOIN(eval_, func) \
3491 (result, arg, number<Backend>::canonical_value(a)); \
3492 } \
3493 template <class Arithmetic> \
3494 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Arithmetic& arg, const Backend& a) const \
3495 { \
3496 using default_ops::BOOST_JOIN(eval_, func); \
3497 BOOST_JOIN(eval_, func) \
3498 (result, number<Backend>::canonical_value(arg), a); \
3499 } \
3500 template <class U> \
3501 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Backend& a) const \
3502 { \
3503 using default_ops::BOOST_JOIN(eval_, func); \
3504 Backend r; \
3505 BOOST_JOIN(eval_, func) \
3506 (r, arg, a); \
3507 result = std::move(r); \
3508 } \
3509 template <class U, class Arithmetic> \
3510 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Arithmetic& a) const \
3511 { \
3512 using default_ops::BOOST_JOIN(eval_, func); \
3513 Backend r; \
3514 BOOST_JOIN(eval_, func) \
3515 (r, arg, number<Backend>::canonical_value(a)); \
3516 result = std::move(r); \
3517 } \
3518 template <class U, class Arithmetic> \
3519 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Arithmetic& arg, const Backend& a) const \
3520 { \
3521 using default_ops::BOOST_JOIN(eval_, func); \
3522 Backend r; \
3523 BOOST_JOIN(eval_, func) \
3524 (r, number<Backend>::canonical_value(arg), a); \
3525 result = std::move(r); \
3526 } \
3527 }; \
3528 } \
3529 template <class Backend> \
3530 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, detail::expression<detail::function, \
3531 detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, number<Backend, et_on>, number<Backend, et_on> > > ::type \
3532 func(const number<Backend, et_on>& arg, const number<Backend, et_on>& a) \
3533 { \
3534 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3535 number<Backend, et_on>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3536 } \
3537 template <class Backend, class tag, class A1, class A2, class A3, class A4> \
3538 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category) && (std::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value), \
3539 detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > > ::type \
3540 func(const number<Backend, et_on>& arg, const detail::expression<tag, A1, A2, A3, A4>& a) \
3541 { \
3542 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3543 number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3544 } \
3545 template <class tag, class A1, class A2, class A3, class A4, class Backend> \
3546 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category) && (std::is_convertible<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, et_on> >::value), \
3547 detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > > ::type \
3548 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const number<Backend, et_on>& a) \
3549 { \
3550 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3551 detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3552 } \
3553 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b> \
3554 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category) && (number_category<detail::expression<tagb, A1b, A2b, A3b, A4b> >::value == category), \
3555 detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3556 detail::expression<tag, A1, A2, A3, A4>, detail::expression<tagb, A1b, A2b, A3b, A4b> > > ::type \
3557 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const detail::expression<tagb, A1b, A2b, A3b, A4b>& a) \
3558 { \
3559 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3560 detail::expression<tag, A1, A2, A3, A4>, detail::expression<tagb, A1b, A2b, A3b, A4b> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg, a); \
3561 } \
3562 template <class Backend, class Arithmetic> \
3563 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3564 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category), \
3565 detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3566 number<Backend, et_on>, Arithmetic> > ::type \
3567 func(const number<Backend, et_on>& arg, const Arithmetic& a) \
3568 { \
3569 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, \
3570 number<Backend, et_on>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3571 } \
3572 template <class tag, class A1, class A2, class A3, class A4, class Arithmetic> \
3573 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3574 is_compatible_arithmetic_type<Arithmetic, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value && (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category), \
3575 detail::expression< \
3576 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3577 detail::expression<tag, A1, A2, A3, A4>, Arithmetic> > ::type \
3578 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const Arithmetic& a) \
3579 { \
3580 return detail::expression< \
3581 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3582 detail::expression<tag, A1, A2, A3, A4>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type > (), arg, a); \
3583 } \
3584 template <class Backend, class Arithmetic> \
3585 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3586 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category), \
3587 detail::expression< \
3588 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3589 Arithmetic, number<Backend, et_on> > > ::type \
3590 func(const Arithmetic& arg, const number<Backend, et_on>& a) \
3591 { \
3592 return detail::expression< \
3593 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3594 Arithmetic, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a); \
3595 } \
3596 template <class tag, class A1, class A2, class A3, class A4, class Arithmetic> \
3597 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3598 is_compatible_arithmetic_type<Arithmetic, typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value && (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category), \
3599 detail::expression< \
3600 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3601 Arithmetic, detail::expression<tag, A1, A2, A3, A4> > > ::type \
3602 func(const Arithmetic& arg, const detail::expression<tag, A1, A2, A3, A4>& a) \
3603 { \
3604 return detail::expression< \
3605 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3606 Arithmetic, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type > (), arg, a); \
3607 } \
3608 template <class Backend> \
3609 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category), number<Backend, et_off> >::type \
3610 func(const number<Backend, et_off>& arg, const number<Backend, et_off>& a) \
3611 { \
3612 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a); \
3613 number<Backend, et_off> result; \
3614 using default_ops::BOOST_JOIN(eval_, func); \
3615 BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \
3616 return result; \
3617 } \
3618 template <class Backend, class Arithmetic> \
3619 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3620 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category), \
3621 number<Backend, et_off> >::type \
3622 func(const number<Backend, et_off>& arg, const Arithmetic& a) \
3623 { \
3624 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg); \
3625 number<Backend, et_off> result; \
3626 using default_ops::BOOST_JOIN(eval_, func); \
3627 BOOST_JOIN(eval_, func) \
3628 (result.backend(), arg.backend(), number<Backend, et_off>::canonical_value(a)); \
3629 return result; \
3630 } \
3631 template <class Backend, class Arithmetic> \
3632 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3633 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category), \
3634 number<Backend, et_off> >::type \
3635 func(const Arithmetic& a, const number<Backend, et_off>& arg) \
3636 { \
3637 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg); \
3638 number<Backend, et_off> result; \
3639 using default_ops::BOOST_JOIN(eval_, func); \
3640 BOOST_JOIN(eval_, func) \
3641 (result.backend(), number<Backend, et_off>::canonical_value(a), arg.backend()); \
3642 return result; \
3643 }\
3644 BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category)
3645
3646 #define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category) \
3647 template <class tag, class A1, class A2, class A3, class A4> \
3648 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3649 (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category), \
3650 detail::expression< \
3651 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3652 detail::expression<tag, A1, A2, A3, A4>, Arg2> > ::type \
3653 func(const detail::expression<tag, A1, A2, A3, A4>& arg, Arg2 const& a) \
3654 { \
3655 return detail::expression< \
3656 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3657 detail::expression<tag, A1, A2, A3, A4>, Arg2 > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type > (), arg, a); \
3658 } \
3659 template <class Backend> \
3660 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3661 (number_category<Backend>::value == category), \
3662 detail::expression< \
3663 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3664 number<Backend, et_on>, Arg2> > ::type \
3665 func(const number<Backend, et_on>& arg, Arg2 const& a) \
3666 { \
3667 return detail::expression< \
3668 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3669 number<Backend, et_on>, Arg2 > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a); \
3670 } \
3671 template <class Backend> \
3672 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3673 (number_category<Backend>::value == category), \
3674 number<Backend, et_off> >::type \
3675 func(const number<Backend, et_off>& arg, Arg2 const& a) \
3676 { \
3677 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a); \
3678 number<Backend, et_off> result; \
3679 using default_ops::BOOST_JOIN(eval_, func); \
3680 BOOST_JOIN(eval_, func) \
3681 (result.backend(), arg.backend(), a); \
3682 return result; \
3683 }
3684
3685 #define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category) \
3686 namespace detail { \
3687 template <class Backend> \
3688 struct BOOST_JOIN(category, BOOST_JOIN(func, _funct)) \
3689 { \
3690 template <class Arg> \
3691 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, Backend const& arg, Arg a) const \
3692 { \
3693 using default_ops::BOOST_JOIN(eval_, func); \
3694 BOOST_JOIN(eval_, func) \
3695 (result, arg, a); \
3696 } \
3697 template <class U, class Arg> \
3698 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, Backend const& arg, Arg a) const \
3699 { \
3700 using default_ops::BOOST_JOIN(eval_, func); \
3701 Backend temp; \
3702 BOOST_JOIN(eval_, func) \
3703 (temp, arg, a); \
3704 result = std::move(temp); \
3705 } \
3706 }; \
3707 } \
3708 \
3709 HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)
3710
3711 // clang-format on
3712
3713 namespace detail {
3714 template <class Backend>
3715 struct abs_funct
3716 {
3717 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3718 {
3719 using default_ops::eval_abs;
3720 eval_abs(result, arg);
3721 }
3722 };
3723 template <class Backend>
3724 struct conj_funct
3725 {
3726 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3727 {
3728 using default_ops::eval_conj;
3729 eval_conj(result, arg);
3730 }
3731 };
3732 template <class Backend>
3733 struct proj_funct
3734 {
3735 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3736 {
3737 using default_ops::eval_proj;
3738 eval_proj(result, arg);
3739 }
3740 };
3741
3742 } // namespace detail
3743
3744 template <class tag, class A1, class A2, class A3, class A4>
3745 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex,
3746 detail::expression<
3747 detail::function, detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> > >::type
3748 abs(const detail::expression<tag, A1, A2, A3, A4>& arg)
3749 {
3750 return detail::expression<
3751 detail::function, detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3752 detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3753 }
3754 template <class Backend>
3755 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex,
3756 detail::expression<
3757 detail::function, detail::abs_funct<Backend>, number<Backend, et_on> > >::type
3758 abs(const number<Backend, et_on>& arg)
3759 {
3760 return detail::expression<
3761 detail::function, detail::abs_funct<Backend>, number<Backend, et_on> >(
3762 detail::abs_funct<Backend>(), arg);
3763 }
3764 template <class Backend>
3765 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, number<Backend, et_off> >::type
3766 abs(const number<Backend, et_off>& arg)
3767 {
3768 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3769 number<Backend, et_off> result;
3770 using default_ops::eval_abs;
3771 eval_abs(result.backend(), arg.backend());
3772 return result;
3773 }
3774
3775 template <class tag, class A1, class A2, class A3, class A4>
3776 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3777 detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3778 conj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3779 {
3780 return detail::expression<
3781 detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3782 detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3783 }
3784 template <class Backend>
3785 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3786 detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >
3787 conj(const number<Backend, et_on>& arg)
3788 {
3789 return detail::expression<
3790 detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >(
3791 detail::conj_funct<Backend>(), arg);
3792 }
3793 template <class Backend>
3794 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3795 conj(const number<Backend, et_off>& arg)
3796 {
3797 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3798 number<Backend, et_off> result;
3799 using default_ops::eval_conj;
3800 eval_conj(result.backend(), arg.backend());
3801 return result;
3802 }
3803
3804 template <class tag, class A1, class A2, class A3, class A4>
3805 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3806 detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3807 proj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3808 {
3809 return detail::expression<
3810 detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3811 detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3812 }
3813 template <class Backend>
3814 inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3815 detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >
3816 proj(const number<Backend, et_on>& arg)
3817 {
3818 return detail::expression<
3819 detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >(
3820 detail::proj_funct<Backend>(), arg);
3821 }
3822 template <class Backend>
3823 inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3824 proj(const number<Backend, et_off>& arg)
3825 {
3826 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3827 number<Backend, et_off> result;
3828 using default_ops::eval_proj;
3829 eval_proj(result.backend(), arg.backend());
3830 return result;
3831 }
3832
3833 UNARY_OP_FUNCTOR(fabs, number_kind_floating_point)
3834 UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point)
3835 UNARY_OP_FUNCTOR(floor, number_kind_floating_point)
3836 UNARY_OP_FUNCTOR(ceil, number_kind_floating_point)
3837 UNARY_OP_FUNCTOR(trunc, number_kind_floating_point)
3838 UNARY_OP_FUNCTOR(round, number_kind_floating_point)
3839 UNARY_OP_FUNCTOR(exp, number_kind_floating_point)
3840 UNARY_OP_FUNCTOR(exp2, number_kind_floating_point)
3841 UNARY_OP_FUNCTOR(log, number_kind_floating_point)
3842 UNARY_OP_FUNCTOR(log10, number_kind_floating_point)
3843 UNARY_OP_FUNCTOR(cos, number_kind_floating_point)
3844 UNARY_OP_FUNCTOR(sin, number_kind_floating_point)
3845 UNARY_OP_FUNCTOR(tan, number_kind_floating_point)
3846 UNARY_OP_FUNCTOR(asin, number_kind_floating_point)
3847 UNARY_OP_FUNCTOR(acos, number_kind_floating_point)
3848 UNARY_OP_FUNCTOR(atan, number_kind_floating_point)
3849 UNARY_OP_FUNCTOR(cosh, number_kind_floating_point)
3850 UNARY_OP_FUNCTOR(sinh, number_kind_floating_point)
3851 UNARY_OP_FUNCTOR(tanh, number_kind_floating_point)
3852 UNARY_OP_FUNCTOR(log2, number_kind_floating_point)
3853 UNARY_OP_FUNCTOR(nearbyint, number_kind_floating_point)
3854 UNARY_OP_FUNCTOR(rint, number_kind_floating_point)
3855
3856 HETERO_BINARY_OP_FUNCTOR(ldexp, short, number_kind_floating_point)
3857 //HETERO_BINARY_OP_FUNCTOR(frexp, short*, number_kind_floating_point)
3858 HETERO_BINARY_OP_FUNCTOR_B(ldexp, int, number_kind_floating_point)
3859 //HETERO_BINARY_OP_FUNCTOR_B(frexp, int*, number_kind_floating_point)
3860 HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point)
3861 //HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point)
3862 HETERO_BINARY_OP_FUNCTOR_B(ldexp, long long, number_kind_floating_point)
3863 //HETERO_BINARY_OP_FUNCTOR_B(frexp, long long*, number_kind_floating_point)
3864 BINARY_OP_FUNCTOR(pow, number_kind_floating_point)
3865 BINARY_OP_FUNCTOR(fmod, number_kind_floating_point)
3866 BINARY_OP_FUNCTOR(fmax, number_kind_floating_point)
3867 BINARY_OP_FUNCTOR(fmin, number_kind_floating_point)
3868 BINARY_OP_FUNCTOR(atan2, number_kind_floating_point)
3869 BINARY_OP_FUNCTOR(fdim, number_kind_floating_point)
3870 BINARY_OP_FUNCTOR(hypot, number_kind_floating_point)
3871 BINARY_OP_FUNCTOR(remainder, number_kind_floating_point)
3872
3873 UNARY_OP_FUNCTOR(logb, number_kind_floating_point)
3874 HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point)
3875 HETERO_BINARY_OP_FUNCTOR(scalbln, short, number_kind_floating_point)
3876 HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point)
3877 HETERO_BINARY_OP_FUNCTOR_B(scalbln, int, number_kind_floating_point)
3878 HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point)
3879 HETERO_BINARY_OP_FUNCTOR_B(scalbln, long, number_kind_floating_point)
3880 HETERO_BINARY_OP_FUNCTOR_B(scalbn, long long, number_kind_floating_point)
3881 HETERO_BINARY_OP_FUNCTOR_B(scalbln, long long, number_kind_floating_point)
3882
3883 //
3884 // Complex functions:
3885 //
3886 UNARY_OP_FUNCTOR(exp, number_kind_complex)
3887 UNARY_OP_FUNCTOR(log, number_kind_complex)
3888 UNARY_OP_FUNCTOR(log10, number_kind_complex)
3889 BINARY_OP_FUNCTOR(pow, number_kind_complex)
3890 UNARY_OP_FUNCTOR(sqrt, number_kind_complex)
3891 UNARY_OP_FUNCTOR(sin, number_kind_complex)
3892 UNARY_OP_FUNCTOR(cos, number_kind_complex)
3893 UNARY_OP_FUNCTOR(tan, number_kind_complex)
3894 UNARY_OP_FUNCTOR(asin, number_kind_complex)
3895 UNARY_OP_FUNCTOR(acos, number_kind_complex)
3896 UNARY_OP_FUNCTOR(atan, number_kind_complex)
3897 UNARY_OP_FUNCTOR(sinh, number_kind_complex)
3898 UNARY_OP_FUNCTOR(cosh, number_kind_complex)
3899 UNARY_OP_FUNCTOR(tanh, number_kind_complex)
3900 UNARY_OP_FUNCTOR(asinh, number_kind_complex)
3901 UNARY_OP_FUNCTOR(acosh, number_kind_complex)
3902 UNARY_OP_FUNCTOR(atanh, number_kind_complex)
3903
3904 //
3905 // Integer functions:
3906 //
3907 BINARY_OP_FUNCTOR(gcd, number_kind_integer)
3908 BINARY_OP_FUNCTOR(lcm, number_kind_integer)
3909 HETERO_BINARY_OP_FUNCTOR(pow, unsigned, number_kind_integer)
3910
3911 #undef BINARY_OP_FUNCTOR
3912 #undef UNARY_OP_FUNCTOR
3913
3914 //
3915 // ilogb:
3916 //
3917 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3918 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == number_kind_floating_point, typename Backend::exponent_type>::type
3919 ilogb(const multiprecision::number<Backend, ExpressionTemplates>& val)
3920 {
3921 using default_ops::eval_ilogb;
3922 return eval_ilogb(val.backend());
3923 }
3924
3925 template <class tag, class A1, class A2, class A3, class A4>
3926 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<detail::expression<tag, A1, A2, A3, A4> >::value == number_kind_floating_point, typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type::backend_type::exponent_type>::type
3927 ilogb(const detail::expression<tag, A1, A2, A3, A4>& val)
3928 {
3929 using default_ops::eval_ilogb;
3930 typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type arg(val);
3931 return eval_ilogb(arg.backend());
3932 }
3933
3934 } //namespace multiprecision
3935
3936 namespace math {
3937 //
3938 // Overload of Boost.Math functions that find the wrong overload when used with number:
3939 //
3940 namespace detail {
3941 template <class T>
3942 T sinc_pi_imp(T);
3943 template <class T>
3944 T sinhc_pi_imp(T);
3945 } // namespace detail
3946 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3947 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
3948 {
3949 boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3950 return std::move(detail::sinc_pi_imp(x));
3951 }
3952
3953 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
3954 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
3955 {
3956 boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3957 return std::move(detail::sinc_pi_imp(x));
3958 }
3959
3960 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3961 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
3962 {
3963 boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3964 return std::move(detail::sinhc_pi_imp(x));
3965 }
3966
3967 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
3968 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
3969 {
3970 boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3971 return std::move(boost::math::sinhc_pi(x));
3972 }
3973
3974 using boost::multiprecision::gcd;
3975 using boost::multiprecision::lcm;
3976
3977 #ifdef BOOST_MSVC
3978 #pragma warning(pop)
3979 #endif
3980 } // namespace math
3981
3982 namespace integer {
3983
3984 using boost::multiprecision::gcd;
3985 using boost::multiprecision::lcm;
3986
3987 } // namespace integer
3988
3989 } // namespace boost
3990
3991 //
3992 // This has to come last of all:
3993 //
3994 #include <boost/multiprecision/detail/no_et_ops.hpp>
3995 #include <boost/multiprecision/detail/et_ops.hpp>
3996 //
3997 // min/max overloads:
3998 //
3999 #include <boost/multiprecision/detail/min_max.hpp>
4000
4001 #endif