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_MP_DEFAULT_OPS
8#define BOOST_MP_DEFAULT_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
38namespace boost {
39namespace multiprecision {
40
41namespace detail {
42
43template <class To, class From>
44void 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*/);
45template <class To, class From>
46void 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*/);
47template <class To, class From>
48void 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*/);
49template <class To, class From>
50void 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*/);
51template <class To, class From>
52void 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
54template <class Integer>
55BOOST_MP_CXX14_CONSTEXPR Integer karatsuba_sqrt(const Integer& x, Integer& r, size_t bits);
56
57} // namespace detail
58
59namespace default_ops {
60
61template <class T>
62BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_backend<T>::value, int>::type eval_signbit(const T& val);
63
64template <class T>
65inline 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
67inline int eval_signbit(float val) { return (std::signbit)(x: val); }
68inline int eval_signbit(double val) { return (std::signbit)(x: val); }
69inline int eval_signbit(long double val) { return (std::signbit)(x: val); }
70#ifdef BOOST_HAS_FLOAT128
71extern "C" int signbitq(float128_type) throw();
72inline int eval_signbit(float128_type val) { return signbitq(val); }
73#endif
74
75template <class T>
76BOOST_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//
95template <class T, class V>
96inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<V, T>::value>::type
97eval_add(T& result, V const& v)
98{
99 T t;
100 t = v;
101 eval_add(result, t);
102}
103template <class T, class V>
104inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, T>::value>::type
105eval_add(T& result, V const& v)
106{
107 T t(v);
108 eval_add(result, t);
109}
110template <class T, class V>
111inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<V, T>::value>::type
112eval_subtract(T& result, V const& v)
113{
114 T t;
115 t = v;
116 eval_subtract(result, t);
117}
118template <class T, class V>
119inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, T>::value>::type
120eval_subtract(T& result, V const& v)
121{
122 T t(v);
123 eval_subtract(result, t);
124}
125template <class T, class V>
126inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< !std::is_convertible<V, T>::value>::type
127eval_multiply(T& result, V const& v)
128{
129 T t;
130 t = v;
131 eval_multiply(result, t);
132}
133template <class T, class V>
134inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, T>::value>::type
135eval_multiply(T& result, V const& v)
136{
137 T t(v);
138 eval_multiply(result, t);
139}
140
141template <class T, class U, class V>
142BOOST_MP_CXX14_CONSTEXPR void eval_multiply(T& t, const U& u, const V& v);
143
144template <class T, class U, class V>
145inline 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}
151template <class T, class U, class V>
152inline 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}
156template <class T, class U, class V>
157inline 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}
163template <class T, class U, class V>
164inline 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}
168template <class T, class V>
169inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
170eval_divide(T& result, V const& v)
171{
172 T t;
173 t = v;
174 eval_divide(result, t);
175}
176template <class T, class V>
177inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
178eval_divide(T& result, V const& v)
179{
180 T t(v);
181 eval_divide(result, t);
182}
183template <class T, class V>
184inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
185eval_modulus(T& result, V const& v)
186{
187 T t;
188 t = v;
189 eval_modulus(result, t);
190}
191template <class T, class V>
192inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
193eval_modulus(T& result, V const& v)
194{
195 T t(v);
196 eval_modulus(result, t);
197}
198template <class T, class V>
199inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
200eval_bitwise_and(T& result, V const& v)
201{
202 T t;
203 t = v;
204 eval_bitwise_and(result, t);
205}
206template <class T, class V>
207inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
208eval_bitwise_and(T& result, V const& v)
209{
210 T t(v);
211 eval_bitwise_and(result, t);
212}
213template <class T, class V>
214inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
215eval_bitwise_or(T& result, V const& v)
216{
217 T t;
218 t = v;
219 eval_bitwise_or(result, t);
220}
221template <class T, class V>
222inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
223eval_bitwise_or(T& result, V const& v)
224{
225 T t(v);
226 eval_bitwise_or(result, t);
227}
228template <class T, class V>
229inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
230eval_bitwise_xor(T& result, V const& v)
231{
232 T t;
233 t = v;
234 eval_bitwise_xor(result, t);
235}
236template <class T, class V>
237inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
238eval_bitwise_xor(T& result, V const& v)
239{
240 T t(v);
241 eval_bitwise_xor(result, t);
242}
243
244template <class T, class V>
245inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && !std::is_convertible<V, T>::value>::type
246eval_complement(T& result, V const& v)
247{
248 T t;
249 t = v;
250 eval_complement(result, t);
251}
252template <class T, class V>
253inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, number<T, et_on> >::value && std::is_convertible<V, T>::value>::type
254eval_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//
263template <class T, class U, class V>
264BOOST_MP_CXX14_CONSTEXPR void eval_add(T& t, const U& u, const V& v);
265
266template <class T>
267inline 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}
283template <class T, class U>
284inline 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}
290template <class T, class U>
291inline 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}
296template <class T, class U>
297inline 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}
301template <class T, class U, class V>
302inline 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}
322template <class T, class U, class V>
323inline 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
328template <class T, class U, class V>
329void BOOST_MP_CXX14_CONSTEXPR eval_subtract(T& t, const U& u, const V& v);
330
331template <class T>
332inline 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}
349template <class T, class U>
350inline 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}
356template <class T, class U>
357inline 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}
362template <class T, class U>
363inline 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}
369template <class T, class U>
370inline 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}
375template <class T, class U>
376inline 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}
382template <class T, class U>
383inline 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}
388template <class T, class U, class V>
389inline 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}
410template <class T, class U, class V>
411inline 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
416template <class T>
417inline 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)
434template <class T, class U>
435inline 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}
441template <class T, class U>
442inline 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}
447template <class T, class U>
448inline 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
453template <class T, class U, class V>
454inline 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}
474template <class T, class U, class V>
475inline 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
480template <class T>
481inline 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
496template <class T, class U>
497inline 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}
503template <class T>
504inline BOOST_MP_CXX14_CONSTEXPR const T& make_T(const T& t)
505{
506 return t;
507}
508
509template <class T, class U, class V, class X>
510inline 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}
514template <class T, class U, class V, class X>
515inline 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}
519template <class T, class U, class V, class X>
520inline 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}
534template <class T, class U, class V, class X>
535inline 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
540template <class T, class U, class V>
541BOOST_MP_CXX14_CONSTEXPR void eval_divide(T& t, const U& u, const V& v);
542
543template <class T>
544inline 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)
561template <class T, class U>
562inline 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}
568template <class T, class U>
569inline 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}
574template <class T, class U>
575inline 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}
581template <class T, class U>
582inline 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
588template <class T, class U, class V>
589inline 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}
612template <class T, class U, class V>
613inline 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
618template <class T, class U, class V>
619BOOST_MP_CXX14_CONSTEXPR void eval_modulus(T& t, const U& u, const V& v);
620
621template <class T>
622inline 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}
638template <class T, class U>
639inline 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}
645template <class T, class U>
646inline 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}
651template <class T, class U>
652inline 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}
658template <class T, class U>
659inline 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}
664template <class T, class U, class V>
665inline 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}
687template <class T, class U, class V>
688inline 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
693template <class T, class U, class V>
694BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and(T& t, const U& u, const V& v);
695
696template <class T>
697inline 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}
713template <class T, class U>
714inline 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}
720template <class T, class U>
721inline 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}
726template <class T, class U>
727inline 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}
731template <class T, class U, class V>
732inline 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}
737template <class T, class U, class V>
738inline 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
743template <class T, class U, class V>
744BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or(T& t, const U& u, const V& v);
745
746template <class T>
747inline 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}
763template <class T, class U>
764inline 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}
770template <class T, class U>
771inline 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}
776template <class T, class U>
777inline 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}
781template <class T, class U, class V>
782inline 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}
802template <class T, class U, class V>
803inline 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
808template <class T, class U, class V>
809BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor(T& t, const U& u, const V& v);
810
811template <class T>
812inline 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}
828template <class T, class U>
829inline 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}
835template <class T, class U>
836inline 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}
841template <class T, class U>
842inline 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}
846template <class T, class U, class V>
847inline 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}
867template <class T, class U, class V>
868inline 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
873template <class T>
874inline 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}
879template <class T>
880inline 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
886template <class T, class U, class V>
887inline 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
893template <class T, class U, class V>
894inline 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
900template <class T>
901inline 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}
906template <class T>
907inline 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
913template <class T, class V, class U>
914inline 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}
924template <class T, class V, class U>
925inline 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}
931template <class T, class V, class U>
932inline 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}
940template <class T, class V, class U>
941inline 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
949template <class T, class V, class U>
950inline 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
958template <class T, class V, class U, int N>
959inline 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
964template <class T, class V, class U>
965inline 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
970template <class Result, class Traits>
971inline 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}
978template <class Result, class Traits>
979inline 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
987template <class R, int b>
988struct 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
995template <class R>
996struct 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
1009template <class Tuple, int i, class T, bool = (i == std::tuple_size<Tuple>::value)>
1010struct 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};
1017template <class Tuple, int i, class T>
1018struct find_index_of_type<Tuple, i, T, true>
1019{
1020 static constexpr int value = -1;
1021};
1022
1023
1024template <class R, class B>
1025struct 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
1040template <class R, class T>
1041inline 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
1050template <class R, class B>
1051inline 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 > static_cast<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 < static_cast<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
1075template <class R, class B>
1076inline 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
1094template <class R, class B>
1095inline 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
1103template <class R, class B>
1104inline 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
1133template <class R, class B>
1134inline 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
1158template <class R, class B>
1159inline 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
1164template <class R, class B>
1165inline void last_chance_eval_convert_to(terminal<R>* result, const B& backend, const std::integral_constant<bool, true>&)
1166{
1167 static_cast<void>(result);
1168 static_cast<void>(backend);
1169
1170 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/");
1171}
1172#endif
1173
1174template <class R, class B>
1175inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(terminal<R>* result, const B& backend)
1176{
1177 using tag_type = std::integral_constant<bool, boost::multiprecision::detail::is_unsigned<R>::value && number_category<B>::value == number_kind_integer>;
1178 last_chance_eval_convert_to(result, backend, tag_type());
1179}
1180
1181template <class B1, class B2, expression_template_option et>
1182inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(terminal<number<B1, et> >* result, const B2& backend)
1183{
1184 //
1185 // We ran out of types to try for the conversion, try
1186 // a generic conversion and hope for the best:
1187 //
1188 boost::multiprecision::detail::generic_interconvert(result->value.backend(), backend, number_category<B1>(), number_category<B2>());
1189}
1190
1191template <class B>
1192inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::string* result, const B& backend)
1193{
1194 *result = backend.str(0, std::ios_base::fmtflags(0));
1195}
1196
1197template <class B>
1198inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex<float>* result, const B& backend)
1199{
1200 using scalar_type = typename scalar_result_from_possible_complex<multiprecision::number<B> >::type;
1201 scalar_type re, im;
1202 eval_real(re.backend(), backend);
1203 eval_imag(im.backend(), backend);
1204
1205 *result = std::complex<float>(re.template convert_to<float>(), im.template convert_to<float>());
1206}
1207
1208template <class B>
1209inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex<double>* result, const B& backend)
1210{
1211 using scalar_type = typename scalar_result_from_possible_complex<multiprecision::number<B> >::type;
1212 scalar_type re, im;
1213 eval_real(re.backend(), backend);
1214 eval_imag(im.backend(), backend);
1215
1216 *result = std::complex<double>(re.template convert_to<double>(), im.template convert_to<double>());
1217}
1218
1219template <class B>
1220inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(std::complex<long double>* result, const B& backend)
1221{
1222 using scalar_type = typename scalar_result_from_possible_complex<multiprecision::number<B> >::type;
1223 scalar_type re, im;
1224 eval_real(re.backend(), backend);
1225 eval_imag(im.backend(), backend);
1226
1227 *result = std::complex<long double>(re.template convert_to<long double>(), im.template convert_to<long double>());
1228}
1229
1230//
1231// Functions:
1232//
1233template <class T, class U>
1234inline BOOST_MP_CXX14_CONSTEXPR void eval_abs(T& result, const U& arg)
1235{
1236 using type_list = typename U::signed_types ;
1237 using front = typename std::tuple_element<0, type_list>::type;
1238 result = arg;
1239 if (arg.compare(front(0)) < 0)
1240 result.negate();
1241}
1242template <class T, class U>
1243inline BOOST_MP_CXX14_CONSTEXPR void eval_fabs(T& result, const U& arg)
1244{
1245 static_assert(number_category<T>::value == number_kind_floating_point, "The fabs function is only valid for floating point types.");
1246 using type_list = typename U::signed_types ;
1247 using front = typename std::tuple_element<0, type_list>::type;
1248 result = arg;
1249 if (arg.compare(front(0)) < 0)
1250 result.negate();
1251}
1252
1253template <class Backend>
1254inline BOOST_MP_CXX14_CONSTEXPR int eval_fpclassify(const Backend& arg)
1255{
1256 static_assert(number_category<Backend>::value == number_kind_floating_point, "The fpclassify function is only valid for floating point types.");
1257 return eval_is_zero(arg) ? FP_ZERO : FP_NORMAL;
1258}
1259
1260template <class T>
1261inline BOOST_MP_CXX14_CONSTEXPR void eval_fmod(T& result, const T& a, const T& b)
1262{
1263 static_assert(number_category<T>::value == number_kind_floating_point, "The fmod function is only valid for floating point types.");
1264 if ((&result == &a) || (&result == &b))
1265 {
1266 T temp;
1267 eval_fmod(temp, a, b);
1268 result = temp;
1269 return;
1270 }
1271 switch (eval_fpclassify(a))
1272 {
1273 case FP_ZERO:
1274 result = a;
1275 return;
1276 case FP_INFINITE:
1277 case FP_NAN:
1278 result = std::numeric_limits<number<T> >::quiet_NaN().backend();
1279 errno = EDOM;
1280 return;
1281 }
1282 switch (eval_fpclassify(b))
1283 {
1284 case FP_ZERO:
1285 case FP_NAN:
1286 result = std::numeric_limits<number<T> >::quiet_NaN().backend();
1287 errno = EDOM;
1288 return;
1289 }
1290 T n;
1291 eval_divide(result, a, b);
1292 if (eval_get_sign(result) < 0)
1293 eval_ceil(n, result);
1294 else
1295 eval_floor(n, result);
1296 eval_multiply(n, b);
1297 eval_subtract(result, a, n);
1298 if (eval_get_sign(result) != 0)
1299 {
1300 //
1301 // Sanity check, that due to rounding errors in division,
1302 // we haven't accidently calculated the wrong value:
1303 // See https://github.com/boostorg/multiprecision/issues/604 for an example.
1304 //
1305 if (eval_get_sign(result) == eval_get_sign(b))
1306 {
1307 if (result.compare(b) >= 0)
1308 {
1309 eval_subtract(result, b);
1310 }
1311 }
1312 else
1313 {
1314 n = b;
1315 n.negate();
1316 if (result.compare(n) >= 0)
1317 {
1318 eval_subtract(result, n);
1319 }
1320 }
1321 }
1322}
1323template <class T, class A>
1324inline 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)
1325{
1326 using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1327 using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1328 cast_type c;
1329 c = a;
1330 eval_fmod(result, x, c);
1331}
1332
1333template <class T, class A>
1334inline 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)
1335{
1336 using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1337 using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1338 cast_type c;
1339 c = x;
1340 eval_fmod(result, c, a);
1341}
1342
1343template <class T>
1344BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a);
1345
1346template <class T>
1347inline BOOST_MP_CXX14_CONSTEXPR void eval_remquo(T& result, const T& a, const T& b, int* pi)
1348{
1349 static_assert(number_category<T>::value == number_kind_floating_point, "The remquo function is only valid for floating point types.");
1350 if ((&result == &a) || (&result == &b))
1351 {
1352 T temp;
1353 eval_remquo(temp, a, b, pi);
1354 result = temp;
1355 return;
1356 }
1357 T n;
1358 eval_divide(result, a, b);
1359 eval_round(n, result);
1360 eval_convert_to(pi, n);
1361 eval_multiply(n, b);
1362 eval_subtract(result, a, n);
1363 if (eval_is_zero(result))
1364 {
1365 if (eval_signbit(a))
1366 result.negate();
1367 }
1368}
1369template <class T, class A>
1370inline 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)
1371{
1372 using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1373 using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1374 cast_type c = cast_type();
1375 c = a;
1376 eval_remquo(result, x, c, pi);
1377}
1378template <class T, class A>
1379inline 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)
1380{
1381 using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1382 using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
1383 cast_type c = cast_type();
1384 c = x;
1385 eval_remquo(result, c, a, pi);
1386}
1387template <class T, class U, class V>
1388inline BOOST_MP_CXX14_CONSTEXPR void eval_remainder(T& result, const U& a, const V& b)
1389{
1390 int i(0);
1391 eval_remquo(result, a, b, &i);
1392}
1393
1394template <class B>
1395BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const B& a, const B& b);
1396template <class T, class U>
1397BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const T& a, const U& b);
1398template <class B>
1399BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const B& a, const B& b);
1400template <class T, class U>
1401BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const T& a, const U& b);
1402
1403template <class T>
1404inline BOOST_MP_CXX14_CONSTEXPR void eval_fdim(T& result, const T& a, const T& b)
1405{
1406 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1407 const ui_type zero = 0u;
1408 switch (eval_fpclassify(b))
1409 {
1410 case FP_NAN:
1411 case FP_INFINITE:
1412 result = zero;
1413 return;
1414 }
1415 switch (eval_fpclassify(a))
1416 {
1417 case FP_NAN:
1418 result = zero;
1419 return;
1420 case FP_INFINITE:
1421 result = a;
1422 return;
1423 }
1424 if (eval_gt(a, b))
1425 {
1426 eval_subtract(result, a, b);
1427 }
1428 else
1429 result = zero;
1430}
1431
1432template <class T, class A>
1433inline 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)
1434{
1435 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1436 using arithmetic_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1437 const ui_type zero = 0u;
1438 arithmetic_type canonical_b = b;
1439 switch (BOOST_MP_FPCLASSIFY(b))
1440 {
1441 case FP_NAN:
1442 case FP_INFINITE:
1443 result = zero;
1444 return;
1445 }
1446 switch (eval_fpclassify(a))
1447 {
1448 case FP_NAN:
1449 result = zero;
1450 return;
1451 case FP_INFINITE:
1452 result = a;
1453 return;
1454 }
1455 if (eval_gt(a, canonical_b))
1456 {
1457 eval_subtract(result, a, canonical_b);
1458 }
1459 else
1460 result = zero;
1461}
1462
1463template <class T, class A>
1464inline 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)
1465{
1466 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1467 using arithmetic_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
1468 const ui_type zero = 0u;
1469 arithmetic_type canonical_a = a;
1470 switch (eval_fpclassify(b))
1471 {
1472 case FP_NAN:
1473 case FP_INFINITE:
1474 result = zero;
1475 return;
1476 }
1477 switch (BOOST_MP_FPCLASSIFY(a))
1478 {
1479 case FP_NAN:
1480 result = zero;
1481 return;
1482 case FP_INFINITE:
1483 result = std::numeric_limits<number<T> >::infinity().backend();
1484 return;
1485 }
1486 if (eval_gt(canonical_a, b))
1487 {
1488 eval_subtract(result, canonical_a, b);
1489 }
1490 else
1491 result = zero;
1492}
1493
1494template <class T>
1495inline BOOST_MP_CXX14_CONSTEXPR void eval_trunc(T& result, const T& a)
1496{
1497 static_assert(number_category<T>::value == number_kind_floating_point, "The trunc function is only valid for floating point types.");
1498 switch (eval_fpclassify(a))
1499 {
1500 case FP_NAN:
1501 errno = EDOM;
1502 // fallthrough...
1503 case FP_ZERO:
1504 case FP_INFINITE:
1505 result = a;
1506 return;
1507 }
1508 if (eval_get_sign(a) < 0)
1509 eval_ceil(result, a);
1510 else
1511 eval_floor(result, a);
1512}
1513
1514template <class T>
1515inline BOOST_MP_CXX14_CONSTEXPR void eval_modf(T& result, T const& arg, T* pipart)
1516{
1517 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1518 int c = eval_fpclassify(arg);
1519 if (c == static_cast<int>(FP_NAN))
1520 {
1521 if (pipart)
1522 *pipart = arg;
1523 result = arg;
1524 return;
1525 }
1526 else if (c == static_cast<int>(FP_INFINITE))
1527 {
1528 if (pipart)
1529 *pipart = arg;
1530 result = ui_type(0u);
1531 return;
1532 }
1533 if (pipart)
1534 {
1535 eval_trunc(*pipart, arg);
1536 eval_subtract(result, arg, *pipart);
1537 }
1538 else
1539 {
1540 T ipart;
1541 eval_trunc(ipart, arg);
1542 eval_subtract(result, arg, ipart);
1543 }
1544}
1545
1546template <class T>
1547inline BOOST_MP_CXX14_CONSTEXPR void eval_round(T& result, const T& a)
1548{
1549 static_assert(number_category<T>::value == number_kind_floating_point, "The round function is only valid for floating point types.");
1550 using fp_type = typename boost::multiprecision::detail::canonical<float, T>::type;
1551 int c = eval_fpclassify(a);
1552 if (c == static_cast<int>(FP_NAN))
1553 {
1554 result = a;
1555 errno = EDOM;
1556 return;
1557 }
1558 if ((c == FP_ZERO) || (c == static_cast<int>(FP_INFINITE)))
1559 {
1560 result = a;
1561 }
1562 else if (eval_get_sign(a) < 0)
1563 {
1564 eval_subtract(result, a, fp_type(0.5f));
1565 eval_ceil(result, result);
1566 }
1567 else
1568 {
1569 eval_add(result, a, fp_type(0.5f));
1570 eval_floor(result, result);
1571 }
1572}
1573
1574template <class B>
1575BOOST_MP_CXX14_CONSTEXPR void eval_lcm(B& result, const B& a, const B& b);
1576template <class B>
1577BOOST_MP_CXX14_CONSTEXPR void eval_gcd(B& result, const B& a, const B& b);
1578
1579template <class T, class Arithmetic>
1580inline 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)
1581{
1582 using si_type = typename boost::multiprecision::detail::canonical<Arithmetic, T>::type;
1583 using default_ops::eval_gcd;
1584 T t;
1585 t = static_cast<si_type>(b);
1586 eval_gcd(result, a, t);
1587}
1588template <class T, class Arithmetic>
1589inline 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)
1590{
1591 eval_gcd(result, b, a);
1592}
1593template <class T, class Arithmetic>
1594inline 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)
1595{
1596 using si_type = typename boost::multiprecision::detail::canonical<Arithmetic, T>::type;
1597 using default_ops::eval_lcm;
1598 T t;
1599 t = static_cast<si_type>(b);
1600 eval_lcm(result, a, t);
1601}
1602template <class T, class Arithmetic>
1603inline 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)
1604{
1605 eval_lcm(result, b, a);
1606}
1607
1608template <class T>
1609inline BOOST_MP_CXX14_CONSTEXPR std::size_t eval_lsb(const T& val)
1610{
1611 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1612 int c = eval_get_sign(val);
1613 if (c == 0)
1614 {
1615 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1616 }
1617 if (c < 0)
1618 {
1619 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1620 }
1621 std::size_t result = 0;
1622 T mask, t;
1623 mask = ui_type(1);
1624 do
1625 {
1626 eval_bitwise_and(t, mask, val);
1627 ++result;
1628 eval_left_shift(mask, 1);
1629 } while (eval_is_zero(t));
1630
1631 return --result;
1632}
1633
1634template <class T>
1635inline BOOST_MP_CXX14_CONSTEXPR std::ptrdiff_t eval_msb(const T& val)
1636{
1637 int c = eval_get_sign(val);
1638 if (c == 0)
1639 {
1640 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1641 }
1642 if (c < 0)
1643 {
1644 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1645 }
1646 //
1647 // This implementation is really really rubbish - it does
1648 // a linear scan for the most-significant-bit. We should really
1649 // do a binary search, but as none of our backends actually needs
1650 // this implementation, we'll leave it for now. In fact for most
1651 // backends it's likely that there will always be a more efficient
1652 // native implementation possible.
1653 //
1654 std::size_t result = 0;
1655 T t(val);
1656 while (!eval_is_zero(t))
1657 {
1658 eval_right_shift(t, 1);
1659 ++result;
1660 }
1661 --result;
1662
1663 return static_cast<std::ptrdiff_t>(result);
1664}
1665
1666template <class T>
1667inline BOOST_MP_CXX14_CONSTEXPR bool eval_bit_test(const T& val, std::size_t index)
1668{
1669 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1670 T mask, t;
1671 mask = ui_type(1);
1672 eval_left_shift(mask, index);
1673 eval_bitwise_and(t, mask, val);
1674 return !eval_is_zero(t);
1675}
1676
1677template <class T>
1678inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_set(T& val, std::size_t index)
1679{
1680 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1681 T mask;
1682 mask = ui_type(1);
1683 eval_left_shift(mask, index);
1684 eval_bitwise_or(val, mask);
1685}
1686
1687template <class T>
1688inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_flip(T& val, std::size_t index)
1689{
1690 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1691 T mask;
1692 mask = ui_type(1);
1693 eval_left_shift(mask, index);
1694 eval_bitwise_xor(val, mask);
1695}
1696
1697template <class T>
1698inline BOOST_MP_CXX14_CONSTEXPR void eval_bit_unset(T& val, std::size_t index)
1699{
1700 using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
1701 T mask, t;
1702 mask = ui_type(1);
1703 eval_left_shift(mask, index);
1704 eval_bitwise_and(t, mask, val);
1705 if (!eval_is_zero(t))
1706 eval_bitwise_xor(val, mask);
1707}
1708
1709template <class Backend>
1710BOOST_MP_CXX14_CONSTEXPR void eval_qr(const Backend& x, const Backend& y, Backend& q, Backend& r);
1711
1712template <class Backend>
1713BOOST_MP_CXX14_CONSTEXPR void eval_karatsuba_sqrt(Backend& result, const Backend& x, Backend& r, Backend& t, size_t bits)
1714{
1715 using default_ops::eval_is_zero;
1716 using default_ops::eval_subtract;
1717 using default_ops::eval_right_shift;
1718 using default_ops::eval_left_shift;
1719 using default_ops::eval_bit_set;
1720 using default_ops::eval_decrement;
1721 using default_ops::eval_bitwise_and;
1722 using default_ops::eval_add;
1723 using default_ops::eval_qr;
1724
1725 using small_uint = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
1726
1727 constexpr small_uint zero = 0u;
1728
1729 // we can calculate it faster with std::sqrt
1730#ifdef BOOST_HAS_INT128
1731 if (bits <= 128)
1732 {
1733 uint128_type a{}, b{}, c{};
1734 eval_convert_to(&a, x);
1735 c = boost::multiprecision::detail::karatsuba_sqrt(x: a, r&: b, bits);
1736 r = number<Backend>::canonical_value(b);
1737 result = number<Backend>::canonical_value(c);
1738 return;
1739 }
1740#else
1741 if (bits <= std::numeric_limits<std::uintmax_t>::digits)
1742 {
1743 std::uintmax_t a{ 0 }, b{ 0 }, c{ 0 };
1744 eval_convert_to(&a, x);
1745 c = boost::multiprecision::detail::karatsuba_sqrt(a, b, bits);
1746 r = number<Backend>::canonical_value(b);
1747 result = number<Backend>::canonical_value(c);
1748 return;
1749 }
1750#endif
1751 // https://hal.inria.fr/file/index/docid/72854/filename/RR-3805.pdf
1752 std::size_t b = bits / 4;
1753 Backend q(x);
1754 eval_right_shift(q, b * 2);
1755 Backend s;
1756 eval_karatsuba_sqrt(s, q, r, t, bits - b * 2);
1757 t = zero;
1758 eval_bit_set(t, static_cast<unsigned>(b * 2));
1759 eval_left_shift(r, b);
1760 eval_decrement(t);
1761 eval_bitwise_and(t, x);
1762 eval_right_shift(t, b);
1763 eval_add(t, r);
1764 eval_left_shift(s, 1u);
1765 eval_qr(t, s, q, r);
1766 eval_left_shift(r, b);
1767 t = zero;
1768 eval_bit_set(t, static_cast<unsigned>(b));
1769 eval_decrement(t);
1770 eval_bitwise_and(t, x);
1771 eval_add(r, t);
1772 eval_left_shift(s, b - 1);
1773 eval_add(s, q);
1774 eval_multiply(q, q);
1775 // we substract after, so it works for unsigned integers too
1776 if (r.compare(q) < 0)
1777 {
1778 t = s;
1779 eval_left_shift(t, 1u);
1780 eval_decrement(t);
1781 eval_add(r, t);
1782 eval_decrement(s);
1783 }
1784 eval_subtract(r, q);
1785 result = s;
1786}
1787
1788template <class B>
1789void BOOST_MP_CXX14_CONSTEXPR eval_integer_sqrt_bitwise(B& s, B& r, const B& x)
1790{
1791 //
1792 // This is slow bit-by-bit integer square root, see for example
1793 // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
1794 // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
1795 // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
1796 // at some point.
1797 //
1798 using ui_type = typename boost::multiprecision::detail::canonical<unsigned char, B>::type;
1799
1800 s = ui_type(0u);
1801 if (eval_get_sign(x) == 0)
1802 {
1803 r = ui_type(0u);
1804 return;
1805 }
1806 std::ptrdiff_t g = static_cast<std::ptrdiff_t>(eval_msb(x));
1807 if (g <= 1)
1808 {
1809 s = ui_type(1);
1810 eval_subtract(r, x, s);
1811 return;
1812 }
1813
1814 B t;
1815 r = x;
1816 g /= 2;
1817 std::ptrdiff_t org_g = g;
1818 eval_bit_set(s, static_cast<std::size_t>(g));
1819 eval_bit_set(t, static_cast<std::size_t>(2 * g));
1820 eval_subtract(r, x, t);
1821 --g;
1822 if (eval_get_sign(r) == 0)
1823 return;
1824 std::ptrdiff_t msbr = static_cast<std::ptrdiff_t>(eval_msb(r));
1825 do
1826 {
1827 if (msbr >= org_g + g + 1)
1828 {
1829 t = s;
1830 eval_left_shift(t, static_cast<std::size_t>(g + 1));
1831 eval_bit_set(t, static_cast<std::size_t>(2 * g));
1832 if (t.compare(r) <= 0)
1833 {
1834 BOOST_MP_ASSERT(g >= 0);
1835 eval_bit_set(s, static_cast<std::size_t>(g));
1836 eval_subtract(r, t);
1837 if (eval_get_sign(r) == 0)
1838 return;
1839 msbr = static_cast<std::ptrdiff_t>(eval_msb(r));
1840 }
1841 }
1842 --g;
1843 } while (g >= 0);
1844}
1845
1846template <class Backend>
1847BOOST_MP_CXX14_CONSTEXPR void eval_integer_sqrt(Backend& result, Backend& r, const Backend& x)
1848{
1849#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
1850 // recursive Karatsuba sqrt can cause issues in constexpr context:
1851 if (BOOST_MP_IS_CONST_EVALUATED(result.size()))
1852 return eval_integer_sqrt_bitwise(result, r, x);
1853#endif
1854 using small_uint = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
1855
1856 constexpr small_uint zero = 0u;
1857
1858 if (eval_is_zero(x))
1859 {
1860 r = zero;
1861 result = zero;
1862 return;
1863 }
1864 Backend t;
1865 eval_karatsuba_sqrt(result, x, r, t, eval_msb(x) + 1);
1866}
1867
1868template <class B>
1869inline BOOST_MP_CXX14_CONSTEXPR void eval_conj(B& result, const B& val)
1870{
1871 result = val; // assume non-complex result.
1872}
1873template <class B>
1874inline BOOST_MP_CXX14_CONSTEXPR void eval_proj(B& result, const B& val)
1875{
1876 result = val; // assume non-complex result.
1877}
1878
1879//
1880// These have to implemented by the backend, declared here so that our macro generated code compiles OK.
1881//
1882template <class T>
1883typename std::enable_if<sizeof(T) == 0>::type eval_floor();
1884template <class T>
1885typename std::enable_if<sizeof(T) == 0>::type eval_ceil();
1886template <class T>
1887typename std::enable_if<sizeof(T) == 0>::type eval_trunc();
1888template <class T>
1889typename std::enable_if<sizeof(T) == 0>::type eval_sqrt();
1890template <class T>
1891typename std::enable_if<sizeof(T) == 0>::type eval_ldexp();
1892template <class T>
1893typename std::enable_if<sizeof(T) == 0>::type eval_frexp();
1894// TODO implement default versions of these:
1895template <class T>
1896typename std::enable_if<sizeof(T) == 0>::type eval_asinh();
1897template <class T>
1898typename std::enable_if<sizeof(T) == 0>::type eval_acosh();
1899template <class T>
1900typename std::enable_if<sizeof(T) == 0>::type eval_atanh();
1901
1902//
1903// eval_logb and eval_scalbn simply assume base 2 and forward to
1904// eval_ldexp and eval_frexp:
1905//
1906template <class B>
1907inline BOOST_MP_CXX14_CONSTEXPR typename B::exponent_type eval_ilogb(const B& val)
1908{
1909 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");
1910 typename B::exponent_type e(0);
1911 switch (eval_fpclassify(val))
1912 {
1913 case FP_NAN:
1914#ifdef FP_ILOGBNAN
1915 return FP_ILOGBNAN > 0 ? (std::numeric_limits<typename B::exponent_type>::max)() : (std::numeric_limits<typename B::exponent_type>::min)();
1916#else
1917 return (std::numeric_limits<typename B::exponent_type>::max)();
1918#endif
1919 case FP_INFINITE:
1920 return (std::numeric_limits<typename B::exponent_type>::max)();
1921 case FP_ZERO:
1922 return (std::numeric_limits<typename B::exponent_type>::min)();
1923 }
1924 B result;
1925 eval_frexp(result, val, &e);
1926 return e - 1;
1927}
1928
1929template <class B>
1930inline BOOST_MP_CXX14_CONSTEXPR void eval_logb(B& result, const B& val)
1931{
1932 switch (eval_fpclassify(val))
1933 {
1934 case FP_NAN:
1935 result = val;
1936 errno = EDOM;
1937 return;
1938 case FP_ZERO:
1939 result = std::numeric_limits<number<B> >::infinity().backend();
1940 result.negate();
1941 errno = ERANGE;
1942 return;
1943 case FP_INFINITE:
1944 result = val;
1945 if (eval_signbit(val))
1946 result.negate();
1947 return;
1948 }
1949 using max_t = typename std::conditional<std::is_same<std::intmax_t, long>::value, long long, std::intmax_t>::type;
1950 result = static_cast<max_t>(eval_ilogb(val));
1951}
1952template <class B, class A>
1953inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbn(B& result, const B& val, A e)
1954{
1955 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");
1956 eval_ldexp(result, val, static_cast<typename B::exponent_type>(e));
1957}
1958template <class B, class A>
1959inline BOOST_MP_CXX14_CONSTEXPR void eval_scalbln(B& result, const B& val, A e)
1960{
1961 eval_scalbn(result, val, e);
1962}
1963
1964template <class T>
1965inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant<bool, true> const&, const std::integral_constant<bool, false>&)
1966{
1967 return eval_fpclassify(val) == FP_NAN;
1968}
1969template <class T>
1970inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val, std::integral_constant<bool, false> const&, const std::integral_constant<bool, true>&)
1971{
1972 return BOOST_MP_ISNAN(val);
1973}
1974template <class T>
1975inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T&, std::integral_constant<bool, false> const&, const std::integral_constant<bool, false>&)
1976{
1977 return false;
1978}
1979
1980template <class T>
1981inline BOOST_MP_CXX14_CONSTEXPR bool is_arg_nan(const T& val)
1982{
1983 return is_arg_nan(val, std::integral_constant<bool, boost::multiprecision::detail::is_backend<T>::value>(), std::is_floating_point<T>());
1984}
1985
1986template <class T, class U, class V>
1987inline BOOST_MP_CXX14_CONSTEXPR void eval_fmax(T& result, const U& a, const V& b)
1988{
1989 if (is_arg_nan(a))
1990 result = number<T>::canonical_value(b);
1991 else if (is_arg_nan(b))
1992 result = number<T>::canonical_value(a);
1993 else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
1994 result = number<T>::canonical_value(b);
1995 else
1996 result = number<T>::canonical_value(a);
1997}
1998template <class T, class U, class V>
1999inline BOOST_MP_CXX14_CONSTEXPR void eval_fmin(T& result, const U& a, const V& b)
2000{
2001 if (is_arg_nan(a))
2002 result = number<T>::canonical_value(b);
2003 else if (is_arg_nan(b))
2004 result = number<T>::canonical_value(a);
2005 else if (eval_lt(number<T>::canonical_value(a), number<T>::canonical_value(b)))
2006 result = number<T>::canonical_value(a);
2007 else
2008 result = number<T>::canonical_value(b);
2009}
2010
2011template <class R, class T, class U>
2012inline BOOST_MP_CXX14_CONSTEXPR void eval_hypot(R& result, const T& a, const U& b)
2013{
2014 //
2015 // Normalize x and y, so that both are positive and x >= y:
2016 //
2017 R x, y;
2018 x = number<R>::canonical_value(a);
2019 y = number<R>::canonical_value(b);
2020 if (eval_get_sign(x) < 0)
2021 x.negate();
2022 if (eval_get_sign(y) < 0)
2023 y.negate();
2024
2025 // Special case, see C99 Annex F.
2026 // The order of the if's is important: do not change!
2027 int c1 = eval_fpclassify(x);
2028 int c2 = eval_fpclassify(y);
2029
2030 if (c1 == FP_ZERO)
2031 {
2032 result = y;
2033 return;
2034 }
2035 if (c2 == FP_ZERO)
2036 {
2037 result = x;
2038 return;
2039 }
2040 if (c1 == FP_INFINITE)
2041 {
2042 result = x;
2043 return;
2044 }
2045 if ((c2 == FP_INFINITE) || (c2 == FP_NAN))
2046 {
2047 result = y;
2048 return;
2049 }
2050 if (c1 == FP_NAN)
2051 {
2052 result = x;
2053 return;
2054 }
2055
2056 if (eval_gt(y, x))
2057 x.swap(y);
2058
2059 eval_multiply(result, x, std::numeric_limits<number<R> >::epsilon().backend());
2060
2061 if (eval_gt(result, y))
2062 {
2063 result = x;
2064 return;
2065 }
2066
2067 R rat;
2068 eval_divide(rat, y, x);
2069 eval_multiply(result, rat, rat);
2070 eval_increment(result);
2071 eval_sqrt(rat, result);
2072 eval_multiply(result, rat, x);
2073}
2074
2075template <class R, class T>
2076inline BOOST_MP_CXX14_CONSTEXPR void eval_nearbyint(R& result, const T& a)
2077{
2078 eval_round(result, a);
2079}
2080template <class R, class T>
2081inline BOOST_MP_CXX14_CONSTEXPR void eval_rint(R& result, const T& a)
2082{
2083 eval_nearbyint(result, a);
2084}
2085
2086template <class T>
2087inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_backend<T>::value, int>::type eval_signbit(const T& val)
2088{
2089 return eval_get_sign(val) < 0 ? 1 : 0;
2090}
2091
2092//
2093// Real and imaginary parts:
2094//
2095template <class To, class From>
2096inline BOOST_MP_CXX14_CONSTEXPR void eval_real(To& to, const From& from)
2097{
2098 to = from;
2099}
2100template <class To, class From>
2101inline BOOST_MP_CXX14_CONSTEXPR void eval_imag(To& to, const From&)
2102{
2103 using ui_type = typename std::tuple_element<0, typename To::unsigned_types>::type;
2104 to = ui_type(0);
2105}
2106
2107} // namespace default_ops
2108namespace default_ops_adl {
2109
2110template <class To, class From>
2111inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real_imp(To& to, const From& from)
2112{
2113 using to_component_type = typename component_type<number<To> >::type;
2114 typename to_component_type::backend_type to_component;
2115 to_component = from;
2116 eval_set_real(to, to_component);
2117}
2118template <class To, class From>
2119inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag_imp(To& to, const From& from)
2120{
2121 using to_component_type = typename component_type<number<To> >::type;
2122 typename to_component_type::backend_type to_component;
2123 to_component = from;
2124 eval_set_imag(to, to_component);
2125}
2126
2127} // namespace default_ops_adl
2128namespace default_ops {
2129
2130template <class To, class From>
2131inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<To>::value == number_kind_complex>::type eval_set_real(To& to, const From& from)
2132{
2133 default_ops_adl::eval_set_real_imp(to, from);
2134}
2135template <class To, class From>
2136inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<To>::value != number_kind_complex>::type eval_set_real(To& to, const From& from)
2137{
2138 to = from;
2139}
2140
2141template <class To, class From>
2142inline BOOST_MP_CXX14_CONSTEXPR void eval_set_imag(To& to, const From& from)
2143{
2144 default_ops_adl::eval_set_imag_imp(to, from);
2145}
2146
2147template <class T>
2148inline BOOST_MP_CXX14_CONSTEXPR void eval_set_real(T& to, const T& from)
2149{
2150 to = from;
2151}
2152template <class T>
2153void BOOST_MP_CXX14_CONSTEXPR eval_set_imag(T&, const T&)
2154{
2155 static_assert(sizeof(T) == INT_MAX, "eval_set_imag needs to be specialised for each specific backend");
2156}
2157
2158//
2159// These functions are implemented in separate files, but expanded inline here,
2160// DO NOT CHANGE THE ORDER OF THESE INCLUDES:
2161//
2162#include <boost/multiprecision/detail/functions/constants.hpp>
2163#include <boost/multiprecision/detail/functions/pow.hpp>
2164#include <boost/multiprecision/detail/functions/trig.hpp>
2165
2166} // namespace default_ops
2167
2168//
2169// Default versions of floating point classification routines:
2170//
2171template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2172inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2173{
2174 using multiprecision::default_ops::eval_fpclassify;
2175 return eval_fpclassify(arg.backend());
2176}
2177template <class tag, class A1, class A2, class A3, class A4>
2178inline BOOST_MP_CXX14_CONSTEXPR int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2179{
2180 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2181 return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2182}
2183template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2184inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2185{
2186 int v = fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg);
2187 return (v != static_cast<int>(FP_INFINITE)) && (v != static_cast<int>(FP_NAN));
2188}
2189template <class tag, class A1, class A2, class A3, class A4>
2190inline BOOST_MP_CXX14_CONSTEXPR bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2191{
2192 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2193 return isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2194}
2195template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2196inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2197{
2198 return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_NAN);
2199}
2200template <class tag, class A1, class A2, class A3, class A4>
2201inline BOOST_MP_CXX14_CONSTEXPR bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2202{
2203 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2204 return isnan BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2205}
2206template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2207inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2208{
2209 return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_INFINITE);
2210}
2211template <class tag, class A1, class A2, class A3, class A4>
2212inline BOOST_MP_CXX14_CONSTEXPR bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2213{
2214 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2215 return isinf BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2216}
2217template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2218inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2219{
2220 return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(arg) == static_cast<int>(FP_NORMAL);
2221}
2222template <class tag, class A1, class A2, class A3, class A4>
2223inline BOOST_MP_CXX14_CONSTEXPR bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2224{
2225 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2226 return isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2227}
2228
2229// Default versions of sign manipulation functions, if individual backends can do better than this
2230// (for example with signed zero), then they should overload these functions further:
2231
2232template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2233inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2234{
2235 return arg.sign();
2236}
2237template <class tag, class A1, class A2, class A3, class A4>
2238inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2239{
2240 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2241 return sign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2242}
2243
2244template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2245inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2246{
2247 using default_ops::eval_signbit;
2248 return static_cast<bool>(eval_signbit(arg.backend()));
2249}
2250template <class tag, class A1, class A2, class A3, class A4>
2251inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2252{
2253 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2254 return static_cast<bool>(signbit BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)));
2255}
2256template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2257inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2258{
2259 return -arg;
2260}
2261template <class tag, class A1, class A2, class A3, class A4>
2262inline 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)
2263{
2264 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2265 return changesign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
2266}
2267template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2268inline 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)
2269{
2270 return (boost::multiprecision::signbit)(a) != (boost::multiprecision::signbit)(b) ? (boost::multiprecision::changesign)(a) : a;
2271}
2272template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2273inline 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)
2274{
2275 return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2276}
2277template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2278inline 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)
2279{
2280 return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2281}
2282template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2283inline 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)
2284{
2285 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2286 return copysign BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2287}
2288//
2289// real and imag:
2290//
2291template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2292inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
2293real(const multiprecision::number<Backend, ExpressionTemplates>& a)
2294{
2295 using default_ops::eval_real;
2296 using result_type = typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type;
2297 boost::multiprecision::detail::scoped_default_precision<result_type> precision_guard(a);
2298 result_type result;
2299 eval_real(result.backend(), a.backend());
2300 return result;
2301}
2302template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2303inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type
2304imag(const multiprecision::number<Backend, ExpressionTemplates>& a)
2305{
2306 using default_ops::eval_imag;
2307 using result_type = typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type;
2308 boost::multiprecision::detail::scoped_default_precision<result_type> precision_guard(a);
2309 result_type result;
2310 eval_imag(result.backend(), a.backend());
2311 return result;
2312}
2313
2314template <class tag, class A1, class A2, class A3, class A4>
2315inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2316real(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2317{
2318 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2319 detail::scoped_default_precision<value_type> precision_guard(arg);
2320 return real(value_type(arg));
2321}
2322
2323template <class tag, class A1, class A2, class A3, class A4>
2324inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2325imag(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2326{
2327 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2328 detail::scoped_default_precision<value_type> precision_guard(arg);
2329 return imag(value_type(arg));
2330}
2331
2332//
2333// Complex number functions, these are overloaded at the Backend level, we just provide the
2334// expression template versions here, plus overloads for non-complex types:
2335//
2336#ifdef BOOST_MP_MATH_AVAILABLE
2337template <class T, expression_template_option ExpressionTemplates>
2338inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates>>>::type::type
2339abs(const number<T, ExpressionTemplates>& v)
2340{
2341 return std::move(boost::math::hypot(real(v), imag(v)));
2342}
2343template <class tag, class A1, class A2, class A3, class A4>
2344inline 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
2345abs(const detail::expression<tag, A1, A2, A3, A4>& v)
2346{
2347 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2348 return std::move(abs(static_cast<number_type>(v)));
2349}
2350
2351template <class T, expression_template_option ExpressionTemplates>
2352inline 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
2353arg(const number<T, ExpressionTemplates>& v)
2354{
2355 return std::move(atan2(imag(v), real(v)));
2356}
2357template <class T, expression_template_option ExpressionTemplates>
2358inline 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
2359arg(const number<T, ExpressionTemplates>&)
2360{
2361 return 0;
2362}
2363template <class tag, class A1, class A2, class A3, class A4>
2364inline 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
2365arg(const detail::expression<tag, A1, A2, A3, A4>& v)
2366{
2367 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2368 return std::move(arg(static_cast<number_type>(v)));
2369}
2370#endif // BOOST_MP_MATH_AVAILABLE
2371
2372template <class T, expression_template_option ExpressionTemplates>
2373inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<T>::value == number_kind_complex, component_type<number<T, ExpressionTemplates>>>::type::type
2374norm(const number<T, ExpressionTemplates>& v)
2375{
2376 typename component_type<number<T, ExpressionTemplates> >::type a(real(v)), b(imag(v));
2377 return std::move(a * a + b * b);
2378}
2379template <class T, expression_template_option ExpressionTemplates>
2380inline 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
2381norm(const number<T, ExpressionTemplates>& v)
2382{
2383 return v * v;
2384}
2385template <class tag, class A1, class A2, class A3, class A4>
2386inline BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2387norm(const detail::expression<tag, A1, A2, A3, A4>& v)
2388{
2389 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2390 return std::move(norm(static_cast<number_type>(v)));
2391}
2392
2393template <class Backend, expression_template_option ExpressionTemplates>
2394BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r, number<Backend, ExpressionTemplates> const& theta)
2395{
2396 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2397}
2398
2399template <class tag, class A1, class A2, class A3, class A4, class Backend, expression_template_option ExpressionTemplates>
2400BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, ExpressionTemplates> >::value,
2401 typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2402polar(detail::expression<tag, A1, A2, A3, A4> const& r, number<Backend, ExpressionTemplates> const& theta)
2403{
2404 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2405}
2406
2407template <class Backend, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2408BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_same<typename detail::expression<tag, A1, A2, A3, A4>::result_type, number<Backend, ExpressionTemplates> >::value,
2409 typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2410polar(number<Backend, ExpressionTemplates> const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2411{
2412 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2413}
2414
2415template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2416BOOST_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,
2417 typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
2418polar(detail::expression<tag, A1, A2, A3, A4> const& r, detail::expression<tagb, A1b, A2b, A3b, A4b> const& theta)
2419{
2420 using scalar_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2421 return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2422}
2423//
2424// We also allow the first argument to polar to be an arithmetic type (probably a literal):
2425//
2426template <class Scalar, class Backend, expression_template_option ExpressionTemplates>
2427BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<Scalar>::value, typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type>::type
2428polar(Scalar const& r, number<Backend, ExpressionTemplates> const& theta)
2429{
2430 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(number<Backend, ExpressionTemplates>(r * cos(theta)), number<Backend, ExpressionTemplates>(r * sin(theta)));
2431}
2432
2433template <class tag, class A1, class A2, class A3, class A4, class Scalar>
2434BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<Scalar>::value,
2435 typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type>::type
2436polar(Scalar const& r, detail::expression<tag, A1, A2, A3, A4> const& theta)
2437{
2438 using scalar_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2439 return typename complex_result_from_scalar<scalar_type>::type(scalar_type(r * cos(theta)), scalar_type(r * sin(theta)));
2440}
2441//
2442// Single argument overloads:
2443//
2444template <class Backend, expression_template_option ExpressionTemplates>
2445BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type polar(number<Backend, ExpressionTemplates> const& r)
2446{
2447 return typename complex_result_from_scalar<number<Backend, ExpressionTemplates> >::type(r);
2448}
2449
2450template <class tag, class A1, class A2, class A3, class A4>
2451BOOST_MP_CXX14_CONSTEXPR typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type
2452polar(detail::expression<tag, A1, A2, A3, A4> const& r)
2453{
2454 return typename complex_result_from_scalar<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::type(r);
2455}
2456
2457} // namespace multiprecision
2458
2459namespace math {
2460
2461//
2462// Import Math functions here, so they can be found by Boost.Math:
2463//
2464using boost::multiprecision::changesign;
2465using boost::multiprecision::copysign;
2466using boost::multiprecision::fpclassify;
2467using boost::multiprecision::isfinite;
2468using boost::multiprecision::isinf;
2469using boost::multiprecision::isnan;
2470using boost::multiprecision::isnormal;
2471using boost::multiprecision::sign;
2472using boost::multiprecision::signbit;
2473
2474#ifndef BOOST_MP_MATH_AVAILABLE
2475namespace policies {
2476
2477template <typename... Args>
2478class policy {};
2479
2480template <typename T1, typename T2, typename T3, typename T4, typename T5>
2481void raise_rounding_error(T1, T2, T3, T4, T5)
2482{
2483 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Rounding error"));
2484}
2485
2486template <typename T1, typename T2, typename T3, typename T4, typename T5>
2487void raise_overflow_error(T1, T2, T3, T4, T5)
2488{
2489 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Overflow error"));
2490}
2491
2492template <typename T1, typename T2, typename T3, typename T4, typename T5>
2493void raise_evaluation_error(T1, T2, T3, T4, T5)
2494{
2495 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Evaluation error"));
2496}
2497
2498template <typename T1, typename T2, typename T3, typename T4, typename T5>
2499void raise_domain_error(T1, T2, T3, T4, T5)
2500{
2501 BOOST_MP_THROW_EXCEPTION(std::domain_error("Domain error"));
2502}
2503
2504template <typename T, typename... Args>
2505struct is_policy
2506{
2507 static constexpr bool value = false;
2508};
2509
2510template <typename... Args>
2511struct is_policy<policy<Args...>>
2512{
2513 static constexpr bool value = true;
2514};
2515
2516} // namespace policies
2517#endif
2518
2519} // namespace math
2520
2521namespace multiprecision {
2522#ifdef BOOST_MP_MATH_AVAILABLE
2523using c99_error_policy = ::boost::math::policies::policy<
2524 ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>,
2525 ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>,
2526 ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>,
2527 ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>,
2528 ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error> >;
2529
2530template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2531inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2532 asinh
2533 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2534{
2535 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2536 return boost::math::asinh(arg, c99_error_policy());
2537}
2538template <class tag, class A1, class A2, class A3, class A4>
2539inline 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
2540 asinh
2541 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2542{
2543 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2544 detail::scoped_default_precision<value_type> precision_guard(arg);
2545 return asinh(value_type(arg));
2546}
2547template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2548inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2549 acosh
2550 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2551{
2552 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2553 return boost::math::acosh(arg, c99_error_policy());
2554}
2555template <class tag, class A1, class A2, class A3, class A4>
2556inline 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
2557 acosh
2558 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2559{
2560 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2561 detail::scoped_default_precision<value_type> precision_guard(arg);
2562 return acosh(value_type(arg));
2563}
2564template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2565inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, multiprecision::number<Backend, ExpressionTemplates> >::type
2566 atanh
2567 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2568{
2569 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2570 return boost::math::atanh(arg, c99_error_policy());
2571}
2572template <class tag, class A1, class A2, class A3, class A4>
2573inline 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
2574 atanh
2575 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2576{
2577 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2578 detail::scoped_default_precision<value_type> precision_guard(arg);
2579 return atanh(value_type(arg));
2580}
2581template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2582inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2583{
2584 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2585 return boost::math::cbrt(arg, c99_error_policy());
2586}
2587template <class tag, class A1, class A2, class A3, class A4>
2588inline 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)
2589{
2590 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2591 detail::scoped_default_precision<value_type> precision_guard(arg);
2592 return cbrt(value_type(arg));
2593}
2594template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2595inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2596{
2597 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2598 return boost::math::erf(arg, c99_error_policy());
2599}
2600template <class tag, class A1, class A2, class A3, class A4>
2601inline 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)
2602{
2603 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2604 detail::scoped_default_precision<value_type> precision_guard(arg);
2605 return erf(value_type(arg));
2606}
2607template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2608inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2609{
2610 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2611 return boost::math::erfc(arg, c99_error_policy());
2612}
2613template <class tag, class A1, class A2, class A3, class A4>
2614inline 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)
2615{
2616 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2617 detail::scoped_default_precision<value_type> precision_guard(arg);
2618 return erfc(value_type(arg));
2619}
2620template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2621inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2622{
2623 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2624 return boost::math::expm1(arg, c99_error_policy());
2625}
2626template <class tag, class A1, class A2, class A3, class A4>
2627inline 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)
2628{
2629 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2630 detail::scoped_default_precision<value_type> precision_guard(arg);
2631 return expm1(value_type(arg));
2632}
2633template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2634inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2635{
2636 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2637 multiprecision::number<Backend, ExpressionTemplates> result;
2638 result = boost::math::lgamma(arg, c99_error_policy());
2639 if ((boost::multiprecision::isnan)(result) && !(boost::multiprecision::isnan)(arg))
2640 {
2641 result = std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::infinity();
2642 errno = ERANGE;
2643 }
2644 return result;
2645}
2646template <class tag, class A1, class A2, class A3, class A4>
2647inline 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)
2648{
2649 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2650 detail::scoped_default_precision<value_type> precision_guard(arg);
2651 return lgamma(value_type(arg));
2652}
2653template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2654inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2655{
2656 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2657 if ((arg == 0) && std::numeric_limits<multiprecision::number<Backend, ExpressionTemplates> >::has_infinity)
2658 {
2659 errno = ERANGE;
2660 return 1 / arg;
2661 }
2662 return boost::math::tgamma(arg, c99_error_policy());
2663}
2664template <class tag, class A1, class A2, class A3, class A4>
2665inline 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)
2666{
2667 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2668 detail::scoped_default_precision<value_type> precision_guard(arg);
2669 return tgamma(value_type(arg));
2670}
2671
2672template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2673inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2674{
2675 return lround(arg);
2676}
2677template <class tag, class A1, class A2, class A3, class A4>
2678inline BOOST_MP_CXX14_CONSTEXPR long lrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2679{
2680 return lround(arg);
2681}
2682#ifndef BOOST_NO_LONG_LONG
2683template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2684inline BOOST_MP_CXX14_CONSTEXPR long long llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2685{
2686 return llround(arg);
2687}
2688template <class tag, class A1, class A2, class A3, class A4>
2689inline BOOST_MP_CXX14_CONSTEXPR long long llrint BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
2690{
2691 return llround(arg);
2692}
2693#endif
2694template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2695inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
2696{
2697 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(arg);
2698 return boost::math::log1p(arg, c99_error_policy());
2699}
2700template <class tag, class A1, class A2, class A3, class A4>
2701inline 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)
2702{
2703 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2704 detail::scoped_default_precision<value_type> precision_guard(arg);
2705 return log1p(value_type(arg));
2706}
2707
2708template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2709inline 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)
2710{
2711 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2712 return boost::math::nextafter(a, b, c99_error_policy());
2713}
2714template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2715inline 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)
2716{
2717 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2718 return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2719}
2720template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2721inline 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)
2722{
2723 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2724 return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2725}
2726template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2727inline 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)
2728{
2729 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2730 detail::scoped_default_precision<value_type> precision_guard(a, b);
2731 return nextafter BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2732}
2733template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2734inline 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)
2735{
2736 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2737 return boost::math::nextafter(a, b, c99_error_policy());
2738}
2739template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
2740inline 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)
2741{
2742 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2743 return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(a, multiprecision::number<Backend, ExpressionTemplates>(b));
2744}
2745template <class tag, class A1, class A2, class A3, class A4, class Backend, multiprecision::expression_template_option ExpressionTemplates>
2746inline 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)
2747{
2748 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(a, b);
2749 return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(multiprecision::number<Backend, ExpressionTemplates>(a), b);
2750}
2751template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
2752inline 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)
2753{
2754 using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
2755 detail::scoped_default_precision<value_type> precision_guard(a, b);
2756 return nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(a), value_type(b));
2757}
2758#endif // BOOST_MP_MATH_AVAILABLE
2759
2760template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2761inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& add(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2762{
2763 static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2764 static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2765 using default_ops::eval_add;
2766 eval_add(result.backend(), a.backend(), b.backend());
2767 return result;
2768}
2769
2770template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2771inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& subtract(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2772{
2773 static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2774 static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2775 using default_ops::eval_subtract;
2776 eval_subtract(result.backend(), a.backend(), b.backend());
2777 return result;
2778}
2779
2780template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
2781inline BOOST_MP_CXX14_CONSTEXPR number<B1, ET1>& multiply(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
2782{
2783 static_assert((std::is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
2784 static_assert((std::is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
2785 using default_ops::eval_multiply;
2786 eval_multiply(result.backend(), a.backend(), b.backend());
2787 return result;
2788}
2789
2790template <class B, expression_template_option ET, class I>
2791inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2792add(number<B, ET>& result, const I& a, const I& b)
2793{
2794 using default_ops::eval_add;
2795 using canonical_type = typename detail::canonical<I, B>::type;
2796 eval_add(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2797 return result;
2798}
2799
2800template <class B, expression_template_option ET, class I>
2801inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2802subtract(number<B, ET>& result, const I& a, const I& b)
2803{
2804 using default_ops::eval_subtract;
2805 using canonical_type = typename detail::canonical<I, B>::type;
2806 eval_subtract(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2807 return result;
2808}
2809
2810template <class B, expression_template_option ET, class I>
2811inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, number<B, ET>&>::type
2812multiply(number<B, ET>& result, const I& a, const I& b)
2813{
2814 using default_ops::eval_multiply;
2815 using canonical_type = typename detail::canonical<I, B>::type;
2816 eval_multiply(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
2817 return result;
2818}
2819
2820template <class tag, class A1, class A2, class A3, class A4, class Policy>
2821inline 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)
2822{
2823 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2824 return std::move(trunc(number_type(v), pol));
2825}
2826
2827template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2828inline BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates> trunc(const number<Backend, ExpressionTemplates>& v, const Policy&)
2829{
2830 using default_ops::eval_trunc;
2831 detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(v);
2832 number<Backend, ExpressionTemplates> result;
2833 eval_trunc(result.backend(), v.backend());
2834 return result;
2835}
2836
2837template <class tag, class A1, class A2, class A3, class A4, class Policy>
2838inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2839{
2840 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2841 number_type r(trunc(v, pol));
2842 if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2843 return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", nullptr, number_type(v), 0, pol);
2844 return r.template convert_to<int>();
2845}
2846template <class tag, class A1, class A2, class A3, class A4>
2847inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2848{
2849 return itrunc(v, boost::math::policies::policy<>());
2850}
2851template <class Backend, expression_template_option ExpressionTemplates, class Policy>
2852inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v, const Policy& pol)
2853{
2854 number<Backend, ExpressionTemplates> r(trunc(v, pol));
2855 if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2856 return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", nullptr, v, 0, pol);
2857 return r.template convert_to<int>();
2858}
2859template <class Backend, expression_template_option ExpressionTemplates>
2860inline BOOST_MP_CXX14_CONSTEXPR int itrunc(const number<Backend, ExpressionTemplates>& v)
2861{
2862 return itrunc(v, boost::math::policies::policy<>());
2863}
2864template <class tag, class A1, class A2, class A3, class A4, class Policy>
2865inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2866{
2867 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2868 number_type r(trunc(v, pol));
2869 if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2870 return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", nullptr, number_type(v), 0L, pol);
2871 return r.template convert_to<long>();
2872}
2873template <class tag, class A1, class A2, class A3, class A4>
2874inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2875{
2876 return ltrunc(v, boost::math::policies::policy<>());
2877}
2878template <class T, expression_template_option ExpressionTemplates, class Policy>
2879inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2880{
2881 number<T, ExpressionTemplates> r(trunc(v, pol));
2882 if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2883 return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", nullptr, v, 0L, pol);
2884 return r.template convert_to<long>();
2885}
2886template <class T, expression_template_option ExpressionTemplates>
2887inline BOOST_MP_CXX14_CONSTEXPR long ltrunc(const number<T, ExpressionTemplates>& v)
2888{
2889 return ltrunc(v, boost::math::policies::policy<>());
2890}
2891#ifndef BOOST_NO_LONG_LONG
2892template <class tag, class A1, class A2, class A3, class A4, class Policy>
2893inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2894{
2895 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2896 number_type r(trunc(v, pol));
2897 if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2898 return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", nullptr, number_type(v), 0LL, pol);
2899 return r.template convert_to<long long>();
2900}
2901template <class tag, class A1, class A2, class A3, class A4>
2902inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
2903{
2904 return lltrunc(v, boost::math::policies::policy<>());
2905}
2906template <class T, expression_template_option ExpressionTemplates, class Policy>
2907inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
2908{
2909 number<T, ExpressionTemplates> r(trunc(v, pol));
2910 if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2911 return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", nullptr, v, 0LL, pol);
2912 return r.template convert_to<long long>();
2913}
2914template <class T, expression_template_option ExpressionTemplates>
2915inline BOOST_MP_CXX14_CONSTEXPR long long lltrunc(const number<T, ExpressionTemplates>& v)
2916{
2917 return lltrunc(v, boost::math::policies::policy<>());
2918}
2919#endif
2920template <class tag, class A1, class A2, class A3, class A4, class Policy>
2921inline 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)
2922{
2923 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2924 return std::move(round(static_cast<number_type>(v), pol));
2925}
2926template <class T, expression_template_option ExpressionTemplates, class Policy>
2927inline BOOST_MP_CXX14_CONSTEXPR number<T, ExpressionTemplates> round(const number<T, ExpressionTemplates>& v, const Policy&)
2928{
2929 using default_ops::eval_round;
2930 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
2931 number<T, ExpressionTemplates> result;
2932 eval_round(result.backend(), v.backend());
2933 return result;
2934}
2935
2936template <class tag, class A1, class A2, class A3, class A4, class Policy>
2937inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2938{
2939 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2940 number_type r(round(v, pol));
2941 if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2942 return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, number_type(v), 0, pol);
2943 return r.template convert_to<int>();
2944}
2945template <class tag, class A1, class A2, class A3, class A4>
2946inline BOOST_MP_CXX14_CONSTEXPR int iround(const detail::expression<tag, A1, A2, A3, A4>& v)
2947{
2948 return iround(v, boost::math::policies::policy<>());
2949}
2950template <class T, expression_template_option ExpressionTemplates, class Policy>
2951inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2952{
2953 number<T, ExpressionTemplates> r(round(v, pol));
2954 if ((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !BOOST_MP_ISFINITE(v))
2955 return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, v, 0, pol);
2956 return r.template convert_to<int>();
2957}
2958template <class T, expression_template_option ExpressionTemplates>
2959inline BOOST_MP_CXX14_CONSTEXPR int iround(const number<T, ExpressionTemplates>& v)
2960{
2961 return iround(v, boost::math::policies::policy<>());
2962}
2963template <class tag, class A1, class A2, class A3, class A4, class Policy>
2964inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2965{
2966 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2967 number_type r(round(v, pol));
2968 if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2969 return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", nullptr, number_type(v), 0L, pol);
2970 return r.template convert_to<long>();
2971}
2972template <class tag, class A1, class A2, class A3, class A4>
2973inline BOOST_MP_CXX14_CONSTEXPR long lround(const detail::expression<tag, A1, A2, A3, A4>& v)
2974{
2975 return lround(v, boost::math::policies::policy<>());
2976}
2977template <class T, expression_template_option ExpressionTemplates, class Policy>
2978inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v, const Policy& pol)
2979{
2980 number<T, ExpressionTemplates> r(round(v, pol));
2981 if ((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !BOOST_MP_ISFINITE(v))
2982 return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", nullptr, v, 0L, pol);
2983 return r.template convert_to<long>();
2984}
2985template <class T, expression_template_option ExpressionTemplates>
2986inline BOOST_MP_CXX14_CONSTEXPR long lround(const number<T, ExpressionTemplates>& v)
2987{
2988 return lround(v, boost::math::policies::policy<>());
2989}
2990#ifndef BOOST_NO_LONG_LONG
2991template <class tag, class A1, class A2, class A3, class A4, class Policy>
2992inline BOOST_MP_CXX14_CONSTEXPR long long llround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
2993{
2994 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
2995 number_type r(round(v, pol));
2996 if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
2997 return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, number_type(v), 0LL, pol);
2998 return r.template convert_to<long long>();
2999}
3000template <class tag, class A1, class A2, class A3, class A4>
3001inline BOOST_MP_CXX14_CONSTEXPR long long llround(const detail::expression<tag, A1, A2, A3, A4>& v)
3002{
3003 return llround(v, boost::math::policies::policy<>());
3004}
3005template <class T, expression_template_option ExpressionTemplates, class Policy>
3006inline BOOST_MP_CXX14_CONSTEXPR long long llround(const number<T, ExpressionTemplates>& v, const Policy& pol)
3007{
3008 number<T, ExpressionTemplates> r(round(v, pol));
3009 if ((r > (std::numeric_limits<long long>::max)()) || r < (std::numeric_limits<long long>::min)() || !BOOST_MP_ISFINITE(v))
3010 return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", nullptr, v, 0LL, pol);
3011 return r.template convert_to<long long>();
3012}
3013template <class T, expression_template_option ExpressionTemplates>
3014inline BOOST_MP_CXX14_CONSTEXPR long long llround(const number<T, ExpressionTemplates>& v)
3015{
3016 return llround(v, boost::math::policies::policy<>());
3017}
3018#endif
3019//
3020// frexp does not return an expression template since we require the
3021// integer argument to be evaluated even if the returned value is
3022// not assigned to anything...
3023//
3024template <class T, expression_template_option ExpressionTemplates>
3025inline 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)
3026{
3027 using default_ops::eval_frexp;
3028 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3029 number<T, ExpressionTemplates> result;
3030 eval_frexp(result.backend(), v.backend(), pint);
3031 return result;
3032}
3033template <class tag, class A1, class A2, class A3, class A4>
3034inline 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
3035frexp(const detail::expression<tag, A1, A2, A3, A4>& v, short* pint)
3036{
3037 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3038 return std::move(frexp(static_cast<number_type>(v), pint));
3039}
3040template <class T, expression_template_option ExpressionTemplates>
3041inline 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)
3042{
3043 using default_ops::eval_frexp;
3044 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3045 number<T, ExpressionTemplates> result;
3046 eval_frexp(result.backend(), v.backend(), pint);
3047 return result;
3048}
3049template <class tag, class A1, class A2, class A3, class A4>
3050inline 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
3051frexp(const detail::expression<tag, A1, A2, A3, A4>& v, int* pint)
3052{
3053 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3054 return std::move(frexp(static_cast<number_type>(v), pint));
3055}
3056template <class T, expression_template_option ExpressionTemplates>
3057inline 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)
3058{
3059 using default_ops::eval_frexp;
3060 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3061 number<T, ExpressionTemplates> result;
3062 eval_frexp(result.backend(), v.backend(), pint);
3063 return result;
3064}
3065template <class tag, class A1, class A2, class A3, class A4>
3066inline 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
3067frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long* pint)
3068{
3069 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3070 return std::move(frexp(static_cast<number_type>(v), pint));
3071}
3072template <class T, expression_template_option ExpressionTemplates>
3073inline 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)
3074{
3075 using default_ops::eval_frexp;
3076 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3077 number<T, ExpressionTemplates> result;
3078 eval_frexp(result.backend(), v.backend(), pint);
3079 return result;
3080}
3081template <class tag, class A1, class A2, class A3, class A4>
3082inline 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
3083frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long long* pint)
3084{
3085 using number_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3086 return std::move(frexp(static_cast<number_type>(v), pint));
3087}
3088//
3089// modf does not return an expression template since we require the
3090// second argument to be evaluated even if the returned value is
3091// not assigned to anything...
3092//
3093template <class T, expression_template_option ExpressionTemplates>
3094inline 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)
3095{
3096 using default_ops::eval_modf;
3097 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3098 number<T, ExpressionTemplates> result;
3099 eval_modf(result.backend(), v.backend(), pipart ? &pipart->backend() : nullptr);
3100 return result;
3101}
3102template <class T, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
3103inline 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)
3104{
3105 using default_ops::eval_modf;
3106 detail::scoped_default_precision<multiprecision::number<T, ExpressionTemplates> > precision_guard(v);
3107 number<T, ExpressionTemplates> result, arg(v);
3108 eval_modf(result.backend(), arg.backend(), pipart ? &pipart->backend() : nullptr);
3109 return result;
3110}
3111
3112//
3113// Integer square root:
3114//
3115template <class B, expression_template_option ExpressionTemplates>
3116inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3117sqrt(const number<B, ExpressionTemplates>& x)
3118{
3119 using default_ops::eval_integer_sqrt;
3120 number<B, ExpressionTemplates> s, r;
3121 eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3122 return s;
3123}
3124template <class tag, class A1, class A2, class A3, class A4>
3125inline 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
3126 sqrt(const detail::expression<tag, A1, A2, A3, A4>& arg)
3127{
3128 using default_ops::eval_integer_sqrt;
3129 using result_type = typename detail::expression<tag, A1, A2, A3, A4>::result_type;
3130 detail::scoped_default_precision<result_type> precision_guard(arg);
3131 result_type result, v(arg), r;
3132 eval_integer_sqrt(result.backend(), r.backend(), v.backend());
3133 return result;
3134}
3135
3136//
3137// fma:
3138//
3139
3140namespace default_ops {
3141
3142struct fma_func
3143{
3144 template <class B, class T, class U, class V>
3145 BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, const V& c) const
3146 {
3147 eval_multiply_add(result, a, b, c);
3148 }
3149};
3150
3151} // namespace default_ops
3152
3153template <class Backend, class U, class V>
3154inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3155 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3156 (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3157 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3158 detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V> >::type
3159fma(const number<Backend, et_on>& a, const U& b, const V& c)
3160{
3161 return detail::expression<detail::function, default_ops::fma_func, number<Backend, et_on>, U, V>(
3162 default_ops::fma_func(), a, b, c);
3163}
3164
3165template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U, class V>
3166inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3167 (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3168 (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3169 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3170 detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V> >::type
3171fma(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, const V& c)
3172{
3173 return detail::expression<detail::function, default_ops::fma_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, V>(
3174 default_ops::fma_func(), a, b, c);
3175}
3176
3177template <class Backend, class U, class V>
3178inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3179 (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3180 (is_number<U>::value || is_number_expression<U>::value || boost::multiprecision::detail::is_arithmetic<U>::value) &&
3181 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3182 number<Backend, et_off> >::type
3183fma(const number<Backend, et_off>& a, const U& b, const V& c)
3184{
3185 using default_ops::eval_multiply_add;
3186 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3187 number<Backend, et_off> result;
3188 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));
3189 return result;
3190}
3191
3192template <class U, class Backend, class V>
3193inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3194 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3195 boost::multiprecision::detail::is_arithmetic<U>::value &&
3196 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3197 detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V> >::type
3198fma(const U& a, const number<Backend, et_on>& b, const V& c)
3199{
3200 return detail::expression<detail::function, default_ops::fma_func, U, number<Backend, et_on>, V>(
3201 default_ops::fma_func(), a, b, c);
3202}
3203
3204template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
3205inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3206 (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3207 boost::multiprecision::detail::is_arithmetic<U>::value &&
3208 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3209 detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V> >::type
3210fma(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, const V& c)
3211{
3212 return detail::expression<detail::function, default_ops::fma_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V>(
3213 default_ops::fma_func(), a, b, c);
3214}
3215
3216template <class U, class Backend, class V>
3217inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3218 (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3219 boost::multiprecision::detail::is_arithmetic<U>::value &&
3220 (is_number<V>::value || is_number_expression<V>::value || boost::multiprecision::detail::is_arithmetic<V>::value),
3221 number<Backend, et_off> >::type
3222fma(const U& a, const number<Backend, et_off>& b, const V& c)
3223{
3224 using default_ops::eval_multiply_add;
3225 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3226 number<Backend, et_off> result;
3227 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));
3228 return result;
3229}
3230
3231template <class U, class V, class Backend>
3232inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3233 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) &&
3234 boost::multiprecision::detail::is_arithmetic<U>::value &&
3235 boost::multiprecision::detail::is_arithmetic<V>::value,
3236 detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> > >::type
3237fma(const U& a, const V& b, const number<Backend, et_on>& c)
3238{
3239 return detail::expression<detail::function, default_ops::fma_func, U, V, number<Backend, et_on> >(
3240 default_ops::fma_func(), a, b, c);
3241}
3242
3243template <class U, class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3244inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3245 (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point) &&
3246 boost::multiprecision::detail::is_arithmetic<U>::value &&
3247 boost::multiprecision::detail::is_arithmetic<V>::value,
3248 detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
3249fma(const U& a, const V& b, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& c)
3250{
3251 return detail::expression<detail::function, default_ops::fma_func, U, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(
3252 default_ops::fma_func(), a, b, c);
3253}
3254
3255template <class U, class V, class Backend>
3256inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3257 (number_category<number<Backend, et_off> >::value == number_kind_floating_point) &&
3258 boost::multiprecision::detail::is_arithmetic<U>::value &&
3259 boost::multiprecision::detail::is_arithmetic<V>::value,
3260 number<Backend, et_off> >::type
3261fma(const U& a, const V& b, const number<Backend, et_off>& c)
3262{
3263 using default_ops::eval_multiply_add;
3264 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b, c);
3265 number<Backend, et_off> result;
3266 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));
3267 return result;
3268}
3269
3270namespace default_ops {
3271
3272struct remquo_func
3273{
3274 template <class B, class T, class U>
3275 BOOST_MP_CXX14_CONSTEXPR void operator()(B& result, const T& a, const U& b, int* pi) const
3276 {
3277 eval_remquo(result, a, b, pi);
3278 }
3279};
3280
3281} // namespace default_ops
3282
3283template <class Backend, class U>
3284inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3285 number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3286 detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*> >::type
3287remquo(const number<Backend, et_on>& a, const U& b, int* pi)
3288{
3289 return detail::expression<detail::function, default_ops::remquo_func, number<Backend, et_on>, U, int*>(
3290 default_ops::remquo_func(), a, b, pi);
3291}
3292
3293template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class U>
3294inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3295 number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_floating_point,
3296 detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*> >::type
3297remquo(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const U& b, int* pi)
3298{
3299 return detail::expression<detail::function, default_ops::remquo_func, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, U, int*>(
3300 default_ops::remquo_func(), a, b, pi);
3301}
3302
3303template <class U, class Backend>
3304inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3305 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3306 detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*> >::type
3307remquo(const U& a, const number<Backend, et_on>& b, int* pi)
3308{
3309 return detail::expression<detail::function, default_ops::remquo_func, U, number<Backend, et_on>, int*>(
3310 default_ops::remquo_func(), a, b, pi);
3311}
3312
3313template <class U, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3314inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3315 (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,
3316 detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*> >::type
3317remquo(const U& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b, int* pi)
3318{
3319 return detail::expression<detail::function, default_ops::remquo_func, U, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, int*>(
3320 default_ops::remquo_func(), a, b, pi);
3321}
3322
3323template <class Backend, class U>
3324inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3325 number_category<number<Backend, et_on> >::value == number_kind_floating_point,
3326 number<Backend, et_off> >::type
3327remquo(const number<Backend, et_off>& a, const U& b, int* pi)
3328{
3329 using default_ops::eval_remquo;
3330 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3331 number<Backend, et_off> result;
3332 eval_remquo(result.backend(), a.backend(), number<Backend, et_off>::canonical_value(b), pi);
3333 return result;
3334}
3335template <class U, class Backend>
3336inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
3337 (number_category<number<Backend, et_on> >::value == number_kind_floating_point) && !is_number<U>::value && !is_number_expression<U>::value,
3338 number<Backend, et_off> >::type
3339remquo(const U& a, const number<Backend, et_off>& b, int* pi)
3340{
3341 using default_ops::eval_remquo;
3342 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(a, b);
3343 number<Backend, et_off> result;
3344 eval_remquo(result.backend(), number<Backend, et_off>::canonical_value(a), b.backend(), pi);
3345 return result;
3346}
3347
3348template <class B, expression_template_option ExpressionTemplates>
3349inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3350sqrt(const number<B, ExpressionTemplates>& x, number<B, ExpressionTemplates>& r)
3351{
3352 using default_ops::eval_integer_sqrt;
3353 detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(x, r);
3354 number<B, ExpressionTemplates> s;
3355 eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3356 return s;
3357}
3358template <class B, expression_template_option ExpressionTemplates, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
3359inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
3360sqrt(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& arg, number<B, ExpressionTemplates>& r)
3361{
3362 using default_ops::eval_integer_sqrt;
3363 detail::scoped_default_precision<multiprecision::number<B, ExpressionTemplates> > precision_guard(r);
3364 number<B, ExpressionTemplates> s;
3365 number<B, ExpressionTemplates> x(arg);
3366 eval_integer_sqrt(s.backend(), r.backend(), x.backend());
3367 return s;
3368}
3369
3370// clang-format off
3371//
3372// Regrettably, when the argument to a function is an rvalue we must return by value, and not return an
3373// expression template, otherwise we can end up with dangling references.
3374// See https://github.com/boostorg/multiprecision/issues/175.
3375//
3376#define UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3377 template <class Backend> \
3378 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, number<Backend, et_on> > ::type \
3379 func(number<Backend, et_on>&& arg) \
3380 { \
3381 detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg); \
3382 number<Backend, et_on> result; \
3383 using default_ops::BOOST_JOIN(eval_, func); \
3384 BOOST_JOIN(eval_, func)(result.backend(), arg.backend()); \
3385 return result; \
3386 } \
3387
3388#define BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3389 template <class Backend> \
3390 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) \
3391 { \
3392 detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a); \
3393 number<Backend, et_on> result; \
3394 using default_ops::BOOST_JOIN(eval_, func); \
3395 BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \
3396 return result; \
3397 } \
3398 template <class Backend> \
3399 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) \
3400 { \
3401 detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a); \
3402 number<Backend, et_on> result; \
3403 using default_ops::BOOST_JOIN(eval_, func); \
3404 BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \
3405 return result; \
3406 } \
3407 template <class Backend> \
3408 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) \
3409 { \
3410 detail::scoped_default_precision<multiprecision::number<Backend, et_on> > precision_guard(arg, a); \
3411 number<Backend, et_on> result; \
3412 using default_ops::BOOST_JOIN(eval_, func); \
3413 BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \
3414 return result; \
3415 } \
3416 template <class Backend, class tag, class A1, class A2, class A3, class A4> \
3417 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), \
3418 number<Backend, et_on> > ::type \
3419 func(number<Backend, et_on>&& arg, const detail::expression<tag, A1, A2, A3, A4>& a) \
3420 { \
3421 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3422 number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3423 } \
3424 template <class tag, class A1, class A2, class A3, class A4, class Backend> \
3425 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), \
3426 number<Backend, et_on> > ::type \
3427 func(const detail::expression<tag, A1, A2, A3, A4>& arg, number<Backend, et_on>&& a) \
3428 { \
3429 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3430 detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3431 } \
3432 template <class Backend, class Arithmetic> \
3433 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3434 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category), \
3435 number<Backend, et_on> >::type \
3436 func(number<Backend, et_on>&& arg, const Arithmetic& a) \
3437 { \
3438 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, \
3439 number<Backend, et_on>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3440 } \
3441 template <class Backend, class Arithmetic> \
3442 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3443 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category), \
3444 number<Backend, et_on> > ::type \
3445 func(const Arithmetic& arg, number<Backend, et_on>&& a) \
3446 { \
3447 return detail::expression< \
3448 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3449 Arithmetic, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a); \
3450 } \
3451
3452
3453#define UNARY_OP_FUNCTOR(func, category) \
3454 namespace detail { \
3455 template <class Backend> \
3456 struct BOOST_JOIN(category, BOOST_JOIN(func, _funct)) \
3457 { \
3458 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const \
3459 { \
3460 using default_ops::BOOST_JOIN(eval_, func); \
3461 BOOST_JOIN(eval_, func) \
3462 (result, arg); \
3463 } \
3464 template <class U> \
3465 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg) const \
3466 { \
3467 using default_ops::BOOST_JOIN(eval_, func); \
3468 Backend temp; \
3469 BOOST_JOIN(eval_, func) \
3470 (temp, arg); \
3471 result = std::move(temp); \
3472 } \
3473 }; \
3474 } \
3475 \
3476 template <class tag, class A1, class A2, class A3, class A4> \
3477 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category, \
3478 detail::expression<detail::function, \
3479 detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3480 detail::expression<tag, A1, A2, A3, A4> > > ::type \
3481 func(const detail::expression<tag, A1, A2, A3, A4>& arg) \
3482 { \
3483 return detail::expression< \
3484 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3485 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); \
3486 } \
3487 template <class Backend> \
3488 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, \
3489 detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, number<Backend, et_on> > > ::type \
3490 func(const number<Backend, et_on>& arg) \
3491 { \
3492 return detail::expression< \
3493 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3494 number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg); \
3495 } \
3496 template <class Backend> \
3497 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3498 boost::multiprecision::number_category<Backend>::value == category, \
3499 number<Backend, et_off> >::type \
3500 func(const number<Backend, et_off>& arg) \
3501 { \
3502 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg); \
3503 number<Backend, et_off> result; \
3504 using default_ops::BOOST_JOIN(eval_, func); \
3505 BOOST_JOIN(eval_, func)(result.backend(), arg.backend()); \
3506 return result; \
3507 }\
3508 UNARY_OP_FUNCTOR_CXX11_RVALUE(func, category)\
3509
3510#define BINARY_OP_FUNCTOR(func, category) \
3511 namespace detail { \
3512 template <class Backend> \
3513 struct BOOST_JOIN(category, BOOST_JOIN(func, _funct)) \
3514 { \
3515 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Backend& a) const \
3516 { \
3517 using default_ops::BOOST_JOIN(eval_, func); \
3518 BOOST_JOIN(eval_, func) \
3519 (result, arg, a); \
3520 } \
3521 template <class Arithmetic> \
3522 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg, const Arithmetic& a) const \
3523 { \
3524 using default_ops::BOOST_JOIN(eval_, func); \
3525 BOOST_JOIN(eval_, func) \
3526 (result, arg, number<Backend>::canonical_value(a)); \
3527 } \
3528 template <class Arithmetic> \
3529 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Arithmetic& arg, const Backend& a) const \
3530 { \
3531 using default_ops::BOOST_JOIN(eval_, func); \
3532 BOOST_JOIN(eval_, func) \
3533 (result, number<Backend>::canonical_value(arg), a); \
3534 } \
3535 template <class U> \
3536 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Backend& a) const \
3537 { \
3538 using default_ops::BOOST_JOIN(eval_, func); \
3539 Backend r; \
3540 BOOST_JOIN(eval_, func) \
3541 (r, arg, a); \
3542 result = std::move(r); \
3543 } \
3544 template <class U, class Arithmetic> \
3545 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Backend& arg, const Arithmetic& a) const \
3546 { \
3547 using default_ops::BOOST_JOIN(eval_, func); \
3548 Backend r; \
3549 BOOST_JOIN(eval_, func) \
3550 (r, arg, number<Backend>::canonical_value(a)); \
3551 result = std::move(r); \
3552 } \
3553 template <class U, class Arithmetic> \
3554 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, const Arithmetic& arg, const Backend& a) const \
3555 { \
3556 using default_ops::BOOST_JOIN(eval_, func); \
3557 Backend r; \
3558 BOOST_JOIN(eval_, func) \
3559 (r, number<Backend>::canonical_value(arg), a); \
3560 result = std::move(r); \
3561 } \
3562 }; \
3563 } \
3564 template <class Backend> \
3565 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == category, detail::expression<detail::function, \
3566 detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, number<Backend, et_on>, number<Backend, et_on> > > ::type \
3567 func(const number<Backend, et_on>& arg, const number<Backend, et_on>& a) \
3568 { \
3569 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3570 number<Backend, et_on>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3571 } \
3572 template <class Backend, class tag, class A1, class A2, class A3, class A4> \
3573 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), \
3574 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 \
3575 func(const number<Backend, et_on>& arg, const detail::expression<tag, A1, A2, A3, A4>& a) \
3576 { \
3577 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3578 number<Backend, et_on>, detail::expression<tag, A1, A2, A3, A4> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3579 } \
3580 template <class tag, class A1, class A2, class A3, class A4, class Backend> \
3581 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), \
3582 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 \
3583 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const number<Backend, et_on>& a) \
3584 { \
3585 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3586 detail::expression<tag, A1, A2, A3, A4>, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3587 } \
3588 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b> \
3589 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), \
3590 detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3591 detail::expression<tag, A1, A2, A3, A4>, detail::expression<tagb, A1b, A2b, A3b, A4b> > > ::type \
3592 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const detail::expression<tagb, A1b, A2b, A3b, A4b>& a) \
3593 { \
3594 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>, \
3595 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); \
3596 } \
3597 template <class Backend, class Arithmetic> \
3598 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3599 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category), \
3600 detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3601 number<Backend, et_on>, Arithmetic> > ::type \
3602 func(const number<Backend, et_on>& arg, const Arithmetic& a) \
3603 { \
3604 return detail::expression<detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>, \
3605 number<Backend, et_on>, Arithmetic > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct))<Backend>(), arg, a); \
3606 } \
3607 template <class tag, class A1, class A2, class A3, class A4, class Arithmetic> \
3608 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3609 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), \
3610 detail::expression< \
3611 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3612 detail::expression<tag, A1, A2, A3, A4>, Arithmetic> > ::type \
3613 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const Arithmetic& a) \
3614 { \
3615 return detail::expression< \
3616 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3617 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); \
3618 } \
3619 template <class Backend, class Arithmetic> \
3620 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3621 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_on> >::value && (number_category<Backend>::value == category), \
3622 detail::expression< \
3623 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3624 Arithmetic, number<Backend, et_on> > > ::type \
3625 func(const Arithmetic& arg, const number<Backend, et_on>& a) \
3626 { \
3627 return detail::expression< \
3628 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3629 Arithmetic, number<Backend, et_on> > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a); \
3630 } \
3631 template <class tag, class A1, class A2, class A3, class A4, class Arithmetic> \
3632 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3633 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), \
3634 detail::expression< \
3635 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3636 Arithmetic, detail::expression<tag, A1, A2, A3, A4> > > ::type \
3637 func(const Arithmetic& arg, const detail::expression<tag, A1, A2, A3, A4>& a) \
3638 { \
3639 return detail::expression< \
3640 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3641 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); \
3642 } \
3643 template <class Backend> \
3644 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(number_category<Backend>::value == category), number<Backend, et_off> >::type \
3645 func(const number<Backend, et_off>& arg, const number<Backend, et_off>& a) \
3646 { \
3647 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a); \
3648 number<Backend, et_off> result; \
3649 using default_ops::BOOST_JOIN(eval_, func); \
3650 BOOST_JOIN(eval_, func)(result.backend(), arg.backend(), a.backend()); \
3651 return result; \
3652 } \
3653 template <class Backend, class Arithmetic> \
3654 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3655 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category), \
3656 number<Backend, et_off> >::type \
3657 func(const number<Backend, et_off>& arg, const Arithmetic& a) \
3658 { \
3659 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg); \
3660 number<Backend, et_off> result; \
3661 using default_ops::BOOST_JOIN(eval_, func); \
3662 BOOST_JOIN(eval_, func) \
3663 (result.backend(), arg.backend(), number<Backend, et_off>::canonical_value(a)); \
3664 return result; \
3665 } \
3666 template <class Backend, class Arithmetic> \
3667 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3668 is_compatible_arithmetic_type<Arithmetic, number<Backend, et_off> >::value && (number_category<Backend>::value == category), \
3669 number<Backend, et_off> >::type \
3670 func(const Arithmetic& a, const number<Backend, et_off>& arg) \
3671 { \
3672 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg); \
3673 number<Backend, et_off> result; \
3674 using default_ops::BOOST_JOIN(eval_, func); \
3675 BOOST_JOIN(eval_, func) \
3676 (result.backend(), number<Backend, et_off>::canonical_value(a), arg.backend()); \
3677 return result; \
3678 }\
3679 BINARY_OP_FUNCTOR_CXX11_RVALUE(func, category)
3680
3681#define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category) \
3682 template <class tag, class A1, class A2, class A3, class A4> \
3683 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3684 (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category), \
3685 detail::expression< \
3686 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3687 detail::expression<tag, A1, A2, A3, A4>, Arg2> > ::type \
3688 func(const detail::expression<tag, A1, A2, A3, A4>& arg, Arg2 const& a) \
3689 { \
3690 return detail::expression< \
3691 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, \
3692 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); \
3693 } \
3694 template <class Backend> \
3695 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3696 (number_category<Backend>::value == category), \
3697 detail::expression< \
3698 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3699 number<Backend, et_on>, Arg2> > ::type \
3700 func(const number<Backend, et_on>& arg, Arg2 const& a) \
3701 { \
3702 return detail::expression< \
3703 detail::function, detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend>, \
3704 number<Backend, et_on>, Arg2 > (detail::BOOST_JOIN(category, BOOST_JOIN(func, _funct)) < Backend > (), arg, a); \
3705 } \
3706 template <class Backend> \
3707 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< \
3708 (number_category<Backend>::value == category), \
3709 number<Backend, et_off> >::type \
3710 func(const number<Backend, et_off>& arg, Arg2 const& a) \
3711 { \
3712 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg, a); \
3713 number<Backend, et_off> result; \
3714 using default_ops::BOOST_JOIN(eval_, func); \
3715 BOOST_JOIN(eval_, func) \
3716 (result.backend(), arg.backend(), a); \
3717 return result; \
3718 }
3719
3720#define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category) \
3721 namespace detail { \
3722 template <class Backend> \
3723 struct BOOST_JOIN(category, BOOST_JOIN(func, _funct)) \
3724 { \
3725 template <class Arg> \
3726 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, Backend const& arg, Arg a) const \
3727 { \
3728 using default_ops::BOOST_JOIN(eval_, func); \
3729 BOOST_JOIN(eval_, func) \
3730 (result, arg, a); \
3731 } \
3732 template <class U, class Arg> \
3733 BOOST_MP_CXX14_CONSTEXPR void operator()(U& result, Backend const& arg, Arg a) const \
3734 { \
3735 using default_ops::BOOST_JOIN(eval_, func); \
3736 Backend temp; \
3737 BOOST_JOIN(eval_, func) \
3738 (temp, arg, a); \
3739 result = std::move(temp); \
3740 } \
3741 }; \
3742 } \
3743 \
3744 HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)
3745
3746// clang-format on
3747
3748namespace detail {
3749template <class Backend>
3750struct abs_funct
3751{
3752 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3753 {
3754 using default_ops::eval_abs;
3755 eval_abs(result, arg);
3756 }
3757};
3758template <class Backend>
3759struct conj_funct
3760{
3761 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3762 {
3763 using default_ops::eval_conj;
3764 eval_conj(result, arg);
3765 }
3766 //
3767 // To allow for mixed complex/scalar arithmetic where conj is called on the scalar type (as in Eigen)
3768 // we provide an overload that will promote the arg to the distination type:
3769 //
3770 template <class Other>
3771 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_constructible<Other, Backend>::value>::type operator()(Other& result, const Backend& arg) const
3772 {
3773 using default_ops::eval_conj;
3774 Other t(arg);
3775 eval_conj(result, t);
3776 }
3777};
3778template <class Backend>
3779struct proj_funct
3780{
3781 BOOST_MP_CXX14_CONSTEXPR void operator()(Backend& result, const Backend& arg) const
3782 {
3783 using default_ops::eval_proj;
3784 eval_proj(result, arg);
3785 }
3786};
3787
3788} // namespace detail
3789
3790template <class tag, class A1, class A2, class A3, class A4>
3791inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex,
3792 detail::expression<
3793 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
3794abs(const detail::expression<tag, A1, A2, A3, A4>& arg)
3795{
3796 return detail::expression<
3797 detail::function, detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3798 detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3799}
3800template <class Backend>
3801inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex,
3802 detail::expression<
3803 detail::function, detail::abs_funct<Backend>, number<Backend, et_on> > >::type
3804abs(const number<Backend, et_on>& arg)
3805{
3806 return detail::expression<
3807 detail::function, detail::abs_funct<Backend>, number<Backend, et_on> >(
3808 detail::abs_funct<Backend>(), arg);
3809}
3810template <class Backend>
3811inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value != number_kind_complex, number<Backend, et_off> >::type
3812abs(const number<Backend, et_off>& arg)
3813{
3814 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3815 number<Backend, et_off> result;
3816 using default_ops::eval_abs;
3817 eval_abs(result.backend(), arg.backend());
3818 return result;
3819}
3820
3821template <class tag, class A1, class A2, class A3, class A4>
3822inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3823 detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3824conj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3825{
3826 return detail::expression<
3827 detail::function, detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3828 detail::conj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3829}
3830template <class Backend>
3831inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3832 detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >
3833conj(const number<Backend, et_on>& arg)
3834{
3835 return detail::expression<
3836 detail::function, detail::conj_funct<Backend>, number<Backend, et_on> >(
3837 detail::conj_funct<Backend>(), arg);
3838}
3839template <class Backend>
3840inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3841conj(const number<Backend, et_off>& arg)
3842{
3843 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3844 number<Backend, et_off> result;
3845 using default_ops::eval_conj;
3846 eval_conj(result.backend(), arg.backend());
3847 return result;
3848}
3849
3850template <class tag, class A1, class A2, class A3, class A4>
3851inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3852 detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >
3853proj(const detail::expression<tag, A1, A2, A3, A4>& arg)
3854{
3855 return detail::expression<
3856 detail::function, detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>, detail::expression<tag, A1, A2, A3, A4> >(
3857 detail::proj_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>(), arg);
3858}
3859template <class Backend>
3860inline BOOST_MP_CXX14_CONSTEXPR detail::expression<
3861 detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >
3862proj(const number<Backend, et_on>& arg)
3863{
3864 return detail::expression<
3865 detail::function, detail::proj_funct<Backend>, number<Backend, et_on> >(
3866 detail::proj_funct<Backend>(), arg);
3867}
3868template <class Backend>
3869inline BOOST_MP_CXX14_CONSTEXPR number<Backend, et_off>
3870proj(const number<Backend, et_off>& arg)
3871{
3872 detail::scoped_default_precision<multiprecision::number<Backend, et_off> > precision_guard(arg);
3873 number<Backend, et_off> result;
3874 using default_ops::eval_proj;
3875 eval_proj(result.backend(), arg.backend());
3876 return result;
3877}
3878
3879UNARY_OP_FUNCTOR(fabs, number_kind_floating_point)
3880UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point)
3881UNARY_OP_FUNCTOR(floor, number_kind_floating_point)
3882UNARY_OP_FUNCTOR(ceil, number_kind_floating_point)
3883UNARY_OP_FUNCTOR(trunc, number_kind_floating_point)
3884UNARY_OP_FUNCTOR(round, number_kind_floating_point)
3885UNARY_OP_FUNCTOR(exp, number_kind_floating_point)
3886UNARY_OP_FUNCTOR(exp2, number_kind_floating_point)
3887UNARY_OP_FUNCTOR(log, number_kind_floating_point)
3888UNARY_OP_FUNCTOR(log10, number_kind_floating_point)
3889UNARY_OP_FUNCTOR(cos, number_kind_floating_point)
3890UNARY_OP_FUNCTOR(sin, number_kind_floating_point)
3891UNARY_OP_FUNCTOR(tan, number_kind_floating_point)
3892UNARY_OP_FUNCTOR(asin, number_kind_floating_point)
3893UNARY_OP_FUNCTOR(acos, number_kind_floating_point)
3894UNARY_OP_FUNCTOR(atan, number_kind_floating_point)
3895UNARY_OP_FUNCTOR(cosh, number_kind_floating_point)
3896UNARY_OP_FUNCTOR(sinh, number_kind_floating_point)
3897UNARY_OP_FUNCTOR(tanh, number_kind_floating_point)
3898UNARY_OP_FUNCTOR(log2, number_kind_floating_point)
3899UNARY_OP_FUNCTOR(nearbyint, number_kind_floating_point)
3900UNARY_OP_FUNCTOR(rint, number_kind_floating_point)
3901
3902HETERO_BINARY_OP_FUNCTOR(ldexp, short, number_kind_floating_point)
3903//HETERO_BINARY_OP_FUNCTOR(frexp, short*, number_kind_floating_point)
3904HETERO_BINARY_OP_FUNCTOR_B(ldexp, int, number_kind_floating_point)
3905//HETERO_BINARY_OP_FUNCTOR_B(frexp, int*, number_kind_floating_point)
3906HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point)
3907//HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point)
3908HETERO_BINARY_OP_FUNCTOR_B(ldexp, long long, number_kind_floating_point)
3909//HETERO_BINARY_OP_FUNCTOR_B(frexp, long long*, number_kind_floating_point)
3910BINARY_OP_FUNCTOR(pow, number_kind_floating_point)
3911BINARY_OP_FUNCTOR(fmod, number_kind_floating_point)
3912BINARY_OP_FUNCTOR(fmax, number_kind_floating_point)
3913BINARY_OP_FUNCTOR(fmin, number_kind_floating_point)
3914BINARY_OP_FUNCTOR(atan2, number_kind_floating_point)
3915BINARY_OP_FUNCTOR(fdim, number_kind_floating_point)
3916BINARY_OP_FUNCTOR(hypot, number_kind_floating_point)
3917BINARY_OP_FUNCTOR(remainder, number_kind_floating_point)
3918
3919UNARY_OP_FUNCTOR(logb, number_kind_floating_point)
3920HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point)
3921HETERO_BINARY_OP_FUNCTOR(scalbln, short, number_kind_floating_point)
3922HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point)
3923HETERO_BINARY_OP_FUNCTOR_B(scalbln, int, number_kind_floating_point)
3924HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point)
3925HETERO_BINARY_OP_FUNCTOR_B(scalbln, long, number_kind_floating_point)
3926HETERO_BINARY_OP_FUNCTOR_B(scalbn, long long, number_kind_floating_point)
3927HETERO_BINARY_OP_FUNCTOR_B(scalbln, long long, number_kind_floating_point)
3928
3929//
3930// Complex functions:
3931//
3932UNARY_OP_FUNCTOR(exp, number_kind_complex)
3933UNARY_OP_FUNCTOR(log, number_kind_complex)
3934UNARY_OP_FUNCTOR(log10, number_kind_complex)
3935BINARY_OP_FUNCTOR(pow, number_kind_complex)
3936UNARY_OP_FUNCTOR(sqrt, number_kind_complex)
3937UNARY_OP_FUNCTOR(sin, number_kind_complex)
3938UNARY_OP_FUNCTOR(cos, number_kind_complex)
3939UNARY_OP_FUNCTOR(tan, number_kind_complex)
3940UNARY_OP_FUNCTOR(asin, number_kind_complex)
3941UNARY_OP_FUNCTOR(acos, number_kind_complex)
3942UNARY_OP_FUNCTOR(atan, number_kind_complex)
3943UNARY_OP_FUNCTOR(sinh, number_kind_complex)
3944UNARY_OP_FUNCTOR(cosh, number_kind_complex)
3945UNARY_OP_FUNCTOR(tanh, number_kind_complex)
3946UNARY_OP_FUNCTOR(asinh, number_kind_complex)
3947UNARY_OP_FUNCTOR(acosh, number_kind_complex)
3948UNARY_OP_FUNCTOR(atanh, number_kind_complex)
3949
3950//
3951// Integer functions:
3952//
3953BINARY_OP_FUNCTOR(gcd, number_kind_integer)
3954BINARY_OP_FUNCTOR(lcm, number_kind_integer)
3955HETERO_BINARY_OP_FUNCTOR(pow, unsigned, number_kind_integer)
3956
3957#undef BINARY_OP_FUNCTOR
3958#undef UNARY_OP_FUNCTOR
3959
3960//
3961// ilogb:
3962//
3963template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3964inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<number_category<Backend>::value == number_kind_floating_point, typename Backend::exponent_type>::type
3965ilogb(const multiprecision::number<Backend, ExpressionTemplates>& val)
3966{
3967 using default_ops::eval_ilogb;
3968 return eval_ilogb(val.backend());
3969}
3970
3971template <class tag, class A1, class A2, class A3, class A4>
3972inline 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
3973ilogb(const detail::expression<tag, A1, A2, A3, A4>& val)
3974{
3975 using default_ops::eval_ilogb;
3976 typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type arg(val);
3977 return eval_ilogb(arg.backend());
3978}
3979
3980} //namespace multiprecision
3981
3982namespace math {
3983//
3984// Overload of Boost.Math functions that find the wrong overload when used with number:
3985//
3986namespace detail {
3987template <class T>
3988T sinc_pi_imp(T);
3989template <class T>
3990T sinhc_pi_imp(T);
3991} // namespace detail
3992template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
3993inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
3994{
3995 boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
3996 return std::move(detail::sinc_pi_imp(x));
3997}
3998
3999template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
4000inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
4001{
4002 boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
4003 return std::move(detail::sinc_pi_imp(x));
4004}
4005
4006template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
4007inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
4008{
4009 boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
4010 return std::move(detail::sinhc_pi_imp(x));
4011}
4012
4013template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
4014inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
4015{
4016 boost::multiprecision::detail::scoped_default_precision<multiprecision::number<Backend, ExpressionTemplates> > precision_guard(x);
4017 return std::move(boost::math::sinhc_pi(x));
4018}
4019
4020using boost::multiprecision::gcd;
4021using boost::multiprecision::lcm;
4022
4023#ifdef BOOST_MSVC
4024#pragma warning(pop)
4025#endif
4026} // namespace math
4027
4028namespace integer {
4029
4030using boost::multiprecision::gcd;
4031using boost::multiprecision::lcm;
4032
4033} // namespace integer
4034
4035} // namespace boost
4036
4037//
4038// This has to come last of all:
4039//
4040#include <boost/multiprecision/detail/no_et_ops.hpp>
4041#include <boost/multiprecision/detail/et_ops.hpp>
4042//
4043// min/max overloads:
4044//
4045#include <boost/multiprecision/detail/min_max.hpp>
4046
4047#endif
4048

source code of boost/libs/multiprecision/include/boost/multiprecision/detail/default_ops.hpp