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