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/utility/enable_if.hpp>
13 #include <boost/mpl/front.hpp>
14 #include <boost/mpl/fold.hpp>
15 #include <boost/cstdint.hpp>
16 #include <boost/type_traits/make_unsigned.hpp>
17 
18 #ifndef INSTRUMENT_BACKEND
19 #ifndef BOOST_MP_INSTRUMENT
20 #define INSTRUMENT_BACKEND(x)
21 #else
22 #define INSTRUMENT_BACKEND(x)\
23    std::cout << BOOST_STRINGIZE(x) << " = " << x.str(0, std::ios_base::scientific) << std::endl;
24 #endif
25 #endif
26 
27 
28 namespace boost{ namespace multiprecision{ namespace default_ops{
29 
30 #ifdef BOOST_MSVC
31 // warning C4127: conditional expression is constant
32 #pragma warning(push)
33 #pragma warning(disable:4127)
34 #endif
35 //
36 // Default versions of mixed arithmetic, these just construct a temporary
37 // from the arithmetic value and then do the arithmetic on that, two versions
38 // of each depending on whether the backend can be directly constructed from type V.
39 //
40 // Note that we have to provide *all* the template parameters to class number when used in
41 // enable_if as MSVC-10 won't compile the code if we rely on a computed-default parameter.
42 // Since the result of the test doesn't depend on whether expression templates are on or off
43 // we just use et_on everywhere.  We could use a BOOST_WORKAROUND but that just obfuscates the
44 // code even more....
45 //
46 template <class T, class V>
47 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value >::type
eval_add(T & result,V const & v)48    eval_add(T& result, V const& v)
49 {
50    T t;
51    t = v;
52    eval_add(result, t);
53 }
54 template <class T, class V>
55 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value >::type
eval_add(T & result,V const & v)56    eval_add(T& result, V const& v)
57 {
58    T t(v);
59    eval_add(result, t);
60 }
61 template <class T, class V>
62 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
eval_subtract(T & result,V const & v)63    eval_subtract(T& result, V const& v)
64 {
65    T t;
66    t = v;
67    eval_subtract(result, t);
68 }
69 template <class T, class V>
70 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
eval_subtract(T & result,V const & v)71    eval_subtract(T& result, V const& v)
72 {
73    T t(v);
74    eval_subtract(result, t);
75 }
76 template <class T, class V>
77 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && !is_convertible<V, T>::value>::type
eval_multiply(T & result,V const & v)78    eval_multiply(T& result, V const& v)
79 {
80    T t;
81    t = v;
82    eval_multiply(result, t);
83 }
84 template <class T, class V>
85 inline typename enable_if_c<is_convertible<V, number<T, et_on> >::value && is_convertible<V, T>::value>::type
eval_multiply(T & result,V const & v)86    eval_multiply(T& result, V const& v)
87 {
88    T t(v);
89    eval_multiply(result, t);
90 }
91 
92 template <class T, class U, class V>
93 void eval_multiply(T& t, const U& u, const V& v);
94 
95 template <class T, class U, class V>
eval_multiply_add(T & t,const U & u,const V & v)96 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)
97 {
98    T z;
99    eval_multiply(z, u, v);
100    eval_add(t, z);
101 }
102 template <class T, class U, class V>
eval_multiply_add(T & t,const U & u,const V & v)103 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)
104 {
105    eval_multiply_add(t, v, u);
106 }
107 template <class T, class U, class V>
eval_multiply_subtract(T & t,const U & u,const V & v)108 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)
109 {
110    T z;
111    eval_multiply(z, u, v);
112    eval_subtract(t, z);
113 }
114 template <class T, class U, class V>
eval_multiply_subtract(T & t,const U & u,const V & v)115 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)
116 {
117    eval_multiply_subtract(t, v, u);
118 }
119 template <class T, class V>
120 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)121    eval_divide(T& result, V const& v)
122 {
123    T t;
124    t = v;
125    eval_divide(result, t);
126 }
127 template <class T, class V>
128 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)129    eval_divide(T& result, V const& v)
130 {
131    T t(v);
132    eval_divide(result, t);
133 }
134 template <class T, class V>
135 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)136    eval_modulus(T& result, V const& v)
137 {
138    T t;
139    t = v;
140    eval_modulus(result, t);
141 }
142 template <class T, class V>
143 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)144    eval_modulus(T& result, V const& v)
145 {
146    T t(v);
147    eval_modulus(result, t);
148 }
149 template <class T, class V>
150 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)151    eval_bitwise_and(T& result, V const& v)
152 {
153    T t;
154    t = v;
155    eval_bitwise_and(result, t);
156 }
157 template <class T, class V>
158 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)159    eval_bitwise_and(T& result, V const& v)
160 {
161    T t(v);
162    eval_bitwise_and(result, t);
163 }
164 template <class T, class V>
165 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)166    eval_bitwise_or(T& result, V const& v)
167 {
168    T t;
169    t = v;
170    eval_bitwise_or(result, t);
171 }
172 template <class T, class V>
173 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)174    eval_bitwise_or(T& result, V const& v)
175 {
176    T t(v);
177    eval_bitwise_or(result, t);
178 }
179 template <class T, class V>
180 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)181    eval_bitwise_xor(T& result, V const& v)
182 {
183    T t;
184    t = v;
185    eval_bitwise_xor(result, t);
186 }
187 template <class T, class V>
188 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)189    eval_bitwise_xor(T& result, V const& v)
190 {
191    T t(v);
192    eval_bitwise_xor(result, t);
193 }
194 
195 template <class T, class V>
196 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)197    eval_complement(T& result, V const& v)
198 {
199    T t;
200    t = v;
201    eval_complement(result, t);
202 }
203 template <class T, class V>
204 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)205    eval_complement(T& result, V const& v)
206 {
207    T t(v);
208    eval_complement(result, t);
209 }
210 
211 //
212 // Default versions of 3-arg arithmetic functions, these mostly just forward to the 2 arg versions:
213 //
214 template <class T, class U, class V>
215 void eval_add(T& t, const U& u, const V& v);
216 
217 template <class T>
eval_add_default(T & t,const T & u,const T & v)218 inline void eval_add_default(T& t, const T& u, const T& v)
219 {
220    if(&t == &v)
221    {
222       eval_add(t, u);
223    }
224    else if(&t == &u)
225    {
226       eval_add(t, v);
227    }
228    else
229    {
230       t = u;
231       eval_add(t, v);
232    }
233 }
234 template <class T, class U>
eval_add_default(T & t,const T & u,const U & v)235 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)
236 {
237    T vv;
238    vv = v;
239    eval_add(t, u, vv);
240 }
241 template <class T, class U>
eval_add_default(T & t,const T & u,const U & v)242 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)
243 {
244    T vv(v);
245    eval_add(t, u, vv);
246 }
247 template <class T, class U>
eval_add_default(T & t,const U & u,const T & v)248 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)
249 {
250    eval_add(t, v, u);
251 }
252 template <class T, class U, class V>
eval_add_default(T & t,const U & u,const V & v)253 inline void eval_add_default(T& t, const U& u, const V& v)
254 {
255    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
256    {
257       eval_add(t, u);
258    }
259    else
260    {
261       t = u;
262       eval_add(t, v);
263    }
264 }
265 template <class T, class U, class V>
eval_add(T & t,const U & u,const V & v)266 inline void eval_add(T& t, const U& u, const V& v)
267 {
268    eval_add_default(t, u, v);
269 }
270 
271 template <class T, class U, class V>
272 void eval_subtract(T& t, const U& u, const V& v);
273 
274 template <class T>
eval_subtract_default(T & t,const T & u,const T & v)275 inline void eval_subtract_default(T& t, const T& u, const T& v)
276 {
277    if((&t == &v) && is_signed_number<T>::value)
278    {
279       eval_subtract(t, u);
280       t.negate();
281    }
282    else if(&t == &u)
283    {
284       eval_subtract(t, v);
285    }
286    else
287    {
288       t = u;
289       eval_subtract(t, v);
290    }
291 }
292 template <class T, class U>
eval_subtract_default(T & t,const T & u,const U & v)293 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)
294 {
295    T vv;
296    vv = v;
297    eval_subtract(t, u, vv);
298 }
299 template <class T, class U>
eval_subtract_default(T & t,const T & u,const U & v)300 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)
301 {
302    T vv(v);
303    eval_subtract(t, u, vv);
304 }
305 template <class T, class U>
eval_subtract_default(T & t,const U & u,const T & v)306 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)
307 {
308    eval_subtract(t, v, u);
309    t.negate();
310 }
311 template <class T, class U>
eval_subtract_default(T & t,const U & u,const T & v)312 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_unsigned_number<T>::value>::type eval_subtract_default(T& t, const U& u, const T& v)
313 {
314    T temp(u);
315    eval_subtract(t, temp, v);
316 }
317 template <class T, class U, class V>
eval_subtract_default(T & t,const U & u,const V & v)318 inline void eval_subtract_default(T& t, const U& u, const V& v)
319 {
320    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
321    {
322       eval_subtract(t, u);
323       t.negate();
324    }
325    else
326    {
327       t = u;
328       eval_subtract(t, v);
329    }
330 }
331 template <class T, class U, class V>
eval_subtract(T & t,const U & u,const V & v)332 inline void eval_subtract(T& t, const U& u, const V& v)
333 {
334    eval_subtract_default(t, u, v);
335 }
336 
337 template <class T>
eval_multiply_default(T & t,const T & u,const T & v)338 inline void eval_multiply_default(T& t, const T& u, const T& v)
339 {
340    if(&t == &v)
341    {
342       eval_multiply(t, u);
343    }
344    else if(&t == &u)
345    {
346       eval_multiply(t, v);
347    }
348    else
349    {
350       t = u;
351       eval_multiply(t, v);
352    }
353 }
354 template <class T, class U>
eval_multiply_default(T & t,const T & u,const U & v)355 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)
356 {
357    T vv;
358    vv = v;
359    eval_multiply(t, u, vv);
360 }
361 template <class T, class U>
eval_multiply_default(T & t,const T & u,const U & v)362 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)
363 {
364    T vv(v);
365    eval_multiply(t, u, vv);
366 }
367 template <class T, class U>
eval_multiply_default(T & t,const U & u,const T & v)368 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)
369 {
370    eval_multiply(t, v, u);
371 }
372 template <class T, class U, class V>
eval_multiply_default(T & t,const U & u,const V & v)373 inline void eval_multiply_default(T& t, const U& u, const V& v)
374 {
375    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
376    {
377       eval_multiply(t, u);
378    }
379    else
380    {
381       t = u;
382       eval_multiply(t, v);
383    }
384 }
385 template <class T, class U, class V>
eval_multiply(T & t,const U & u,const V & v)386 inline void eval_multiply(T& t, const U& u, const V& v)
387 {
388    eval_multiply_default(t, u, v);
389 }
390 
391 template <class T, class U, class V, class X>
eval_multiply_add(T & t,const U & u,const V & v,const X & x)392 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)
393 {
394    if((void*)&x == (void*)&t)
395    {
396       T z;
397       z = x;
398       eval_multiply_add(t, u, v, z);
399    }
400    else
401    {
402       eval_multiply(t, u, v);
403       eval_add(t, x);
404    }
405 }
406 template <class T, class U, class V, class X>
eval_multiply_add(T & t,const U & u,const V & v,const X & x)407 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)
408 {
409    eval_multiply_add(t, v, u, x);
410 }
411 template <class T, class U, class V, class X>
eval_multiply_subtract(T & t,const U & u,const V & v,const X & x)412 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)
413 {
414    if((void*)&x == (void*)&t)
415    {
416       T z;
417       z = x;
418       eval_multiply_subtract(t, u, v, z);
419    }
420    else
421    {
422       eval_multiply(t, u, v);
423       eval_subtract(t, x);
424    }
425 }
426 template <class T, class U, class V, class X>
eval_multiply_subtract(T & t,const U & u,const V & v,const X & x)427 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)
428 {
429    eval_multiply_subtract(t, v, u, x);
430 }
431 
432 template <class T, class U, class V>
433 void eval_divide(T& t, const U& u, const V& v);
434 
435 template <class T>
eval_divide_default(T & t,const T & u,const T & v)436 inline void eval_divide_default(T& t, const T& u, const T& v)
437 {
438    if(&t == &u)
439       eval_divide(t, v);
440    else if(&t == &v)
441    {
442       T temp;
443       eval_divide(temp, u, v);
444       temp.swap(t);
445    }
446    else
447    {
448       t = u;
449       eval_divide(t, v);
450    }
451 }
452 template <class T, class U>
eval_divide_default(T & t,const T & u,const U & v)453 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)
454 {
455    T vv;
456    vv = v;
457    eval_divide(t, u, vv);
458 }
459 template <class T, class U>
eval_divide_default(T & t,const T & u,const U & v)460 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)
461 {
462    T vv(v);
463    eval_divide(t, u, vv);
464 }
465 template <class T, class U>
eval_divide_default(T & t,const U & u,const T & v)466 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)
467 {
468    T uu;
469    uu = u;
470    eval_divide(t, uu, v);
471 }
472 template <class T, class U>
eval_divide_default(T & t,const U & u,const T & v)473 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)
474 {
475    T uu(u);
476    eval_divide(t, uu, v);
477 }
478 template <class T, class U, class V>
eval_divide_default(T & t,const U & u,const V & v)479 inline void eval_divide_default(T& t, const U& u, const V& v)
480 {
481    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
482    {
483       T temp(u);
484       eval_divide(temp, v);
485       t = temp;
486    }
487    else
488    {
489       t = u;
490       eval_divide(t, v);
491    }
492 }
493 template <class T, class U, class V>
eval_divide(T & t,const U & u,const V & v)494 inline void eval_divide(T& t, const U& u, const V& v)
495 {
496    eval_divide_default(t, u, v);
497 }
498 
499 template <class T, class U, class V>
500 void eval_modulus(T& t, const U& u, const V& v);
501 
502 template <class T>
eval_modulus_default(T & t,const T & u,const T & v)503 inline void eval_modulus_default(T& t, const T& u, const T& v)
504 {
505    if(&t == &u)
506       eval_modulus(t, v);
507    else if(&t == &v)
508    {
509       T temp;
510       eval_modulus(temp, u, v);
511       temp.swap(t);
512    }
513    else
514    {
515       t = u;
516       eval_modulus(t, v);
517    }
518 }
519 template <class T, class U>
eval_modulus_default(T & t,const T & u,const U & v)520 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)
521 {
522    T vv;
523    vv = v;
524    eval_modulus(t, u, vv);
525 }
526 template <class T, class U>
eval_modulus_default(T & t,const T & u,const U & v)527 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)
528 {
529    T vv(v);
530    eval_modulus(t, u, vv);
531 }
532 template <class T, class U>
eval_modulus_default(T & t,const U & u,const T & v)533 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)
534 {
535    T uu;
536    uu = u;
537    eval_modulus(t, uu, v);
538 }
539 template <class T, class U>
eval_modulus_default(T & t,const U & u,const T & v)540 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)
541 {
542    T uu(u);
543    eval_modulus(t, uu, v);
544 }
545 template <class T, class U, class V>
eval_modulus_default(T & t,const U & u,const V & v)546 inline void eval_modulus_default(T& t, const U& u, const V& v)
547 {
548    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
549    {
550       T temp(u);
551       eval_modulus(temp, v);
552       t = temp;
553    }
554    else
555    {
556       t = u;
557       eval_modulus(t, v);
558    }
559 }
560 template <class T, class U, class V>
eval_modulus(T & t,const U & u,const V & v)561 inline void eval_modulus(T& t, const U& u, const V& v)
562 {
563    eval_modulus_default(t, u, v);
564 }
565 
566 template <class T, class U, class V>
567 void eval_bitwise_and(T& t, const U& u, const V& v);
568 
569 template <class T>
eval_bitwise_and_default(T & t,const T & u,const T & v)570 inline void eval_bitwise_and_default(T& t, const T& u, const T& v)
571 {
572    if(&t == &v)
573    {
574       eval_bitwise_and(t, u);
575    }
576    else if(&t == &u)
577    {
578       eval_bitwise_and(t, v);
579    }
580    else
581    {
582       t = u;
583       eval_bitwise_and(t, v);
584    }
585 }
586 template <class T, class U>
eval_bitwise_and_default(T & t,const T & u,const U & v)587 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && !is_convertible<U, T>::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v)
588 {
589    T vv;
590    vv = v;
591    eval_bitwise_and(t, u, vv);
592 }
593 template <class T, class U>
eval_bitwise_and_default(T & t,const T & u,const U & v)594 inline typename enable_if_c<is_convertible<U, number<T, et_on> >::value && is_convertible<U, T>::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v)
595 {
596    T vv(v);
597    eval_bitwise_and(t, u, vv);
598 }
599 template <class T, class U>
eval_bitwise_and_default(T & t,const U & u,const T & v)600 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)
601 {
602    eval_bitwise_and(t, v, u);
603 }
604 template <class T, class U, class V>
eval_bitwise_and_default(T & t,const U & u,const V & v)605 inline void eval_bitwise_and_default(T& t, const U& u, const V& v)
606 {
607    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
608    {
609       eval_bitwise_and(t, u);
610    }
611    else
612    {
613       t = u;
614       eval_bitwise_and(t, v);
615    }
616 }
617 template <class T, class U, class V>
eval_bitwise_and(T & t,const U & u,const V & v)618 inline void eval_bitwise_and(T& t, const U& u, const V& v)
619 {
620    eval_bitwise_and_default(t, u, v);
621 }
622 
623 template <class T, class U, class V>
624 void eval_bitwise_or(T& t, const U& u, const V& v);
625 
626 template <class T>
eval_bitwise_or_default(T & t,const T & u,const T & v)627 inline void eval_bitwise_or_default(T& t, const T& u, const T& v)
628 {
629    if(&t == &v)
630    {
631       eval_bitwise_or(t, u);
632    }
633    else if(&t == &u)
634    {
635       eval_bitwise_or(t, v);
636    }
637    else
638    {
639       t = u;
640       eval_bitwise_or(t, v);
641    }
642 }
643 template <class T, class U>
eval_bitwise_or_default(T & t,const T & u,const U & v)644 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)
645 {
646    T vv;
647    vv = v;
648    eval_bitwise_or(t, u, vv);
649 }
650 template <class T, class U>
eval_bitwise_or_default(T & t,const T & u,const U & v)651 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)
652 {
653    T vv(v);
654    eval_bitwise_or(t, u, vv);
655 }
656 template <class T, class U>
eval_bitwise_or_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_or_default(T& t, const U& u, const T& v)
658 {
659    eval_bitwise_or(t, v, u);
660 }
661 template <class T, class U, class V>
eval_bitwise_or_default(T & t,const U & u,const V & v)662 inline void eval_bitwise_or_default(T& t, const U& u, const V& v)
663 {
664    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
665    {
666       eval_bitwise_or(t, u);
667    }
668    else
669    {
670       t = u;
671       eval_bitwise_or(t, v);
672    }
673 }
674 template <class T, class U, class V>
eval_bitwise_or(T & t,const U & u,const V & v)675 inline void eval_bitwise_or(T& t, const U& u, const V& v)
676 {
677    eval_bitwise_or_default(t, u, v);
678 }
679 
680 template <class T, class U, class V>
681 void eval_bitwise_xor(T& t, const U& u, const V& v);
682 
683 template <class T>
eval_bitwise_xor_default(T & t,const T & u,const T & v)684 inline void eval_bitwise_xor_default(T& t, const T& u, const T& v)
685 {
686    if(&t == &v)
687    {
688       eval_bitwise_xor(t, u);
689    }
690    else if(&t == &u)
691    {
692       eval_bitwise_xor(t, v);
693    }
694    else
695    {
696       t = u;
697       eval_bitwise_xor(t, v);
698    }
699 }
700 template <class T, class U>
eval_bitwise_xor_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_xor_default(T& t, const T& u, const U& v)
702 {
703    T vv;
704    vv = v;
705    eval_bitwise_xor(t, u, vv);
706 }
707 template <class T, class U>
eval_bitwise_xor_default(T & t,const T & u,const U & v)708 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)
709 {
710    T vv(v);
711    eval_bitwise_xor(t, u, vv);
712 }
713 template <class T, class U>
eval_bitwise_xor_default(T & t,const U & u,const T & v)714 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)
715 {
716    eval_bitwise_xor(t, v, u);
717 }
718 template <class T, class U, class V>
eval_bitwise_xor_default(T & t,const U & u,const V & v)719 inline void eval_bitwise_xor_default(T& t, const U& u, const V& v)
720 {
721    if(is_same<T, V>::value && ((void*)&t == (void*)&v))
722    {
723       eval_bitwise_xor(t, u);
724    }
725    else
726    {
727       t = u;
728       eval_bitwise_xor(t, v);
729    }
730 }
731 template <class T, class U, class V>
eval_bitwise_xor(T & t,const U & u,const V & v)732 inline void eval_bitwise_xor(T& t, const U& u, const V& v)
733 {
734    eval_bitwise_xor_default(t, u, v);
735 }
736 
737 template <class T>
eval_increment(T & val)738 inline void eval_increment(T& val)
739 {
740    typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
741    eval_add(val, static_cast<ui_type>(1u));
742 }
743 template <class T>
eval_decrement(T & val)744 inline void eval_decrement(T& val)
745 {
746    typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
747    eval_subtract(val, static_cast<ui_type>(1u));
748 }
749 
750 template <class T, class V>
eval_left_shift(T & result,const T & arg,const V val)751 inline void eval_left_shift(T& result, const T& arg, const V val)
752 {
753    result = arg;
754    eval_left_shift(result, val);
755 }
756 
757 template <class T, class V>
eval_right_shift(T & result,const T & arg,const V val)758 inline void eval_right_shift(T& result, const T& arg, const V val)
759 {
760    result = arg;
761    eval_right_shift(result, val);
762 }
763 
764 template <class T>
eval_is_zero(const T & val)765 inline bool eval_is_zero(const T& val)
766 {
767    typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
768    return val.compare(static_cast<ui_type>(0)) == 0;
769 }
770 template <class T>
eval_get_sign(const T & val)771 inline int eval_get_sign(const T& val)
772 {
773    typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
774    return val.compare(static_cast<ui_type>(0));
775 }
776 
777 template <class T, class V>
assign_components_imp(T & result,const V & v1,const V & v2,const mpl::int_<number_kind_rational> &)778 inline void assign_components_imp(T& result, const V& v1, const V& v2, const mpl::int_<number_kind_rational>&)
779 {
780    result = v1;
781    T t;
782    t = v2;
783    eval_divide(result, t);
784 }
785 
786 template <class T, class V>
assign_components(T & result,const V & v1,const V & v2)787 inline void assign_components(T& result, const V& v1, const V& v2)
788 {
789    return assign_components_imp(result, v1, v2, typename number_category<T>::type());
790 }
791 
792 template <class R, int b>
793 struct has_enough_bits
794 {
795    template <class T>
796    struct type : public mpl::and_<mpl::not_<is_same<R, T> >, mpl::bool_<std::numeric_limits<T>::digits >= b> >{};
797 };
798 
799 template <class R>
800 struct terminal
801 {
terminalboost::multiprecision::default_ops::terminal802    terminal(const R& v) : value(v){}
terminalboost::multiprecision::default_ops::terminal803    terminal(){}
operator =boost::multiprecision::default_ops::terminal804    terminal& operator = (R val) { value = val;  return *this; }
805    R value;
operator Rboost::multiprecision::default_ops::terminal806    operator R()const {  return value;  }
807 };
808 
809 template<class R, class B>
810 struct calculate_next_larger_type
811 {
812    // Find which list we're looking through:
813    typedef typename mpl::if_<
814       is_signed<R>,
815       typename B::signed_types,
816       typename mpl::if_<
817          is_unsigned<R>,
818          typename B::unsigned_types,
819          typename B::float_types
820       >::type
821    >::type list_type;
822    // A predicate to find a type with enough bits:
823    typedef typename has_enough_bits<R, std::numeric_limits<R>::digits>::template type<mpl::_> pred_type;
824    // See if the last type is in the list, if so we have to start after this:
825    typedef typename mpl::find_if<
826       list_type,
827       is_same<R, mpl::_>
828    >::type start_last;
829    // Where we're starting from, either the start of the sequence or the last type found:
830    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;
831    // The range we're searching:
832    typedef mpl::iterator_range<start_seq, typename mpl::end<list_type>::type> range;
833    // Find the next type:
834    typedef typename mpl::find_if<
835       range,
836       pred_type
837    >::type iter_type;
838    // Either the next type, or a "terminal" to indicate we've run out of types to search:
839    typedef typename mpl::eval_if<
840       is_same<typename mpl::end<list_type>::type, iter_type>,
841       mpl::identity<terminal<R> >,
842       mpl::deref<iter_type>
843       >::type type;
844 };
845 
846 template <class R, class T>
check_in_range(const T & t)847 inline bool check_in_range(const T& t)
848 {
849    // Can t fit in an R?
850    if(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (t > (std::numeric_limits<R>::max)()))
851       return true;
852    return false;
853 }
854 
855 template <class R, class T>
check_in_range(const terminal<T> &)856 inline bool check_in_range(const terminal<T>&)
857 {
858    return false;
859 }
860 
861 template <class R, class B>
eval_convert_to(R * result,const B & backend)862 inline void eval_convert_to(R* result, const B& backend)
863 {
864    typedef typename calculate_next_larger_type<R, B>::type next_type;
865    next_type n;
866    eval_convert_to(&n, backend);
867    if(check_in_range<R>(n))
868    {
869       *result = (std::numeric_limits<R>::max)();
870    }
871    else
872       *result = static_cast<R>(n);
873 }
874 
875 template <class R, class B>
eval_convert_to(terminal<R> * result,const B & backend)876 inline void eval_convert_to(terminal<R>* result, const B& backend)
877 {
878    //
879    // We ran out of types to try for the conversion, try
880    // a lexical_cast and hope for the best:
881    //
882    result->value = boost::lexical_cast<R>(backend.str(0, std::ios_base::fmtflags(0)));
883 }
884 
885 template <class B>
eval_convert_to(std::string * result,const B & backend)886 inline void eval_convert_to(std::string* result, const B& backend)
887 {
888    *result = backend.str(0, std::ios_base::fmtflags(0));
889 }
890 //
891 // Functions:
892 //
893 template <class T>
eval_abs(T & result,const T & arg)894 void eval_abs(T& result, const T& arg)
895 {
896    typedef typename T::signed_types type_list;
897    typedef typename mpl::front<type_list>::type front;
898    result = arg;
899    if(arg.compare(front(0)) < 0)
900       result.negate();
901 }
902 template <class T>
eval_fabs(T & result,const T & arg)903 void eval_fabs(T& result, const T& arg)
904 {
905    BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The fabs function is only valid for floating point types.");
906    typedef typename T::signed_types type_list;
907    typedef typename mpl::front<type_list>::type front;
908    result = arg;
909    if(arg.compare(front(0)) < 0)
910       result.negate();
911 }
912 
913 template <class Backend>
eval_fpclassify(const Backend & arg)914 inline int eval_fpclassify(const Backend& arg)
915 {
916    BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_floating_point, "The fpclassify function is only valid for floating point types.");
917    return eval_is_zero(arg) ? FP_ZERO : FP_NORMAL;
918 }
919 
920 template <class T>
eval_fmod(T & result,const T & a,const T & b)921 inline void eval_fmod(T& result, const T& a, const T& b)
922 {
923    BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The fmod function is only valid for floating point types.");
924    if((&result == &a) || (&result == &b))
925    {
926       T temp;
927       eval_fmod(temp, a, b);
928       result = temp;
929       return;
930    }
931    T n;
932    eval_divide(result, a, b);
933    if(eval_get_sign(result) < 0)
934       eval_ceil(n, result);
935    else
936       eval_floor(n, result);
937    eval_multiply(n, b);
938    eval_subtract(result, a, n);
939 }
940 template<class T, class A>
eval_fmod(T & result,const T & x,const A & a)941 inline typename enable_if<is_arithmetic<A>, void>::type eval_fmod(T& result, const T& x, const A& a)
942 {
943    typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
944    typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
945    cast_type c;
946    c = a;
947    eval_fmod(result, x, c);
948 }
949 
950 template<class T, class A>
eval_fmod(T & result,const A & x,const T & a)951 inline typename enable_if<is_arithmetic<A>, void>::type eval_fmod(T& result, const A& x, const T& a)
952 {
953    typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
954    typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
955    cast_type c;
956    c = x;
957    eval_fmod(result, c, a);
958 }
959 
960 template <class T>
eval_trunc(T & result,const T & a)961 inline void eval_trunc(T& result, const T& a)
962 {
963    BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The trunc function is only valid for floating point types.");
964    int c = eval_fpclassify(a);
965    if(c == (int)FP_NAN || c == (int)FP_INFINITE)
966    {
967       result = boost::math::policies::raise_rounding_error("boost::multiprecision::trunc<%1%>(%1%)", 0, number<T>(a), number<T>(a), boost::math::policies::policy<>()).backend();
968       return;
969    }
970    if(eval_get_sign(a) < 0)
971       eval_ceil(result, a);
972    else
973       eval_floor(result, a);
974 }
975 
976 template <class T>
eval_round(T & result,const T & a)977 inline void eval_round(T& result, const T& a)
978 {
979    BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The round function is only valid for floating point types.");
980    typedef typename boost::multiprecision::detail::canonical<float, T>::type fp_type;
981    int c = eval_fpclassify(a);
982    if((c == (int)FP_NAN) || (c == (int)FP_INFINITE))
983    {
984       result = boost::math::policies::raise_rounding_error("boost::multiprecision::round<%1%>(%1%)", 0, number<T>(a), number<T>(a), boost::math::policies::policy<>()).backend();
985       return;
986    }
987    if(eval_get_sign(a) < 0)
988    {
989       eval_subtract(result, a, fp_type(0.5f));
990       eval_ceil(result, result);
991    }
992    else
993    {
994       eval_add(result, a, fp_type(0.5f));
995       eval_floor(result, result);
996    }
997 }
998 
999 template <class B>
1000 void eval_lcm(B& result, const B& a, const B& b);
1001 template <class B>
1002 void eval_gcd(B& result, const B& a, const B& b);
1003 
1004 template <class T, class Arithmetic>
eval_gcd(T & result,const T & a,const Arithmetic & b)1005 inline typename enable_if<is_integral<Arithmetic> >::type eval_gcd(T& result, const T& a, const Arithmetic& b)
1006 {
1007    typedef typename boost::multiprecision::detail::canonical<Arithmetic, T>::type si_type;
1008    using default_ops::eval_gcd;
1009    T t;
1010    t = static_cast<si_type>(b);
1011    eval_gcd(result, a, t);
1012 }
1013 template <class T, class Arithmetic>
eval_gcd(T & result,const Arithmetic & a,const T & b)1014 inline typename enable_if<is_integral<Arithmetic> >::type eval_gcd(T& result, const Arithmetic& a, const T& b)
1015 {
1016    eval_gcd(result, b, a);
1017 }
1018 template <class T, class Arithmetic>
eval_lcm(T & result,const T & a,const Arithmetic & b)1019 inline typename enable_if<is_integral<Arithmetic> >::type eval_lcm(T& result, const T& a, const Arithmetic& b)
1020 {
1021    typedef typename boost::multiprecision::detail::canonical<Arithmetic, T>::type si_type;
1022    using default_ops::eval_lcm;
1023    T t;
1024    t = static_cast<si_type>(b);
1025    eval_lcm(result, a, t);
1026 }
1027 template <class T, class Arithmetic>
eval_lcm(T & result,const Arithmetic & a,const T & b)1028 inline typename enable_if<is_integral<Arithmetic> >::type eval_lcm(T& result, const Arithmetic& a, const T& b)
1029 {
1030    eval_lcm(result, b, a);
1031 }
1032 
1033 template <class T>
eval_lsb(const T & val)1034 inline unsigned eval_lsb(const T& val)
1035 {
1036    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1037    int c = eval_get_sign(val);
1038    if(c == 0)
1039    {
1040       BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
1041    }
1042    if(c < 0)
1043    {
1044       BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
1045    }
1046    unsigned result = 0;
1047    T mask, t;
1048    mask = ui_type(1);
1049    do
1050    {
1051       eval_bitwise_and(t, mask, val);
1052       ++result;
1053       eval_left_shift(mask, 1);
1054    }
1055    while(eval_is_zero(t));
1056 
1057    return --result;
1058 }
1059 
1060 template <class T>
eval_msb(const T & val)1061 inline int eval_msb(const T& val)
1062 {
1063    int c = eval_get_sign(val);
1064    if(c == 0)
1065    {
1066       BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
1067    }
1068    if(c < 0)
1069    {
1070       BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
1071    }
1072    //
1073    // This implementation is really really rubbish - it does
1074    // a linear scan for the most-significant-bit.  We should really
1075    // do a binary search, but as none of our backends actually needs
1076    // this implementation, we'll leave it for now.  In fact for most
1077    // backends it's likely that there will always be a more efficient
1078    // native implementation possible.
1079    //
1080    unsigned result = 0;
1081    T t(val);
1082    while(!eval_is_zero(t))
1083    {
1084       eval_right_shift(t, 1);
1085       ++result;
1086    }
1087    return --result;
1088 }
1089 
1090 template <class T>
eval_bit_test(const T & val,unsigned index)1091 inline bool eval_bit_test(const T& val, unsigned index)
1092 {
1093    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1094    T mask, t;
1095    mask = ui_type(1);
1096    eval_left_shift(mask, index);
1097    eval_bitwise_and(t, mask, val);
1098    return !eval_is_zero(t);
1099 }
1100 
1101 template <class T>
eval_bit_set(T & val,unsigned index)1102 inline void eval_bit_set(T& val, unsigned index)
1103 {
1104    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1105    T mask;
1106    mask = ui_type(1);
1107    eval_left_shift(mask, index);
1108    eval_bitwise_or(val, mask);
1109 }
1110 
1111 template <class T>
eval_bit_flip(T & val,unsigned index)1112 inline void eval_bit_flip(T& val, unsigned index)
1113 {
1114    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1115    T mask;
1116    mask = ui_type(1);
1117    eval_left_shift(mask, index);
1118    eval_bitwise_xor(val, mask);
1119 }
1120 
1121 template <class T>
eval_bit_unset(T & val,unsigned index)1122 inline void eval_bit_unset(T& val, unsigned index)
1123 {
1124    typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
1125    T mask, t;
1126    mask = ui_type(1);
1127    eval_left_shift(mask, index);
1128    eval_bitwise_and(t, mask, val);
1129    if(!eval_is_zero(t))
1130       eval_bitwise_xor(val, mask);
1131 }
1132 
1133 template <class B>
eval_integer_sqrt(B & s,B & r,const B & x)1134 void eval_integer_sqrt(B& s, B& r, const B& x)
1135 {
1136    //
1137    // This is slow bit-by-bit integer square root, see for example
1138    // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
1139    // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
1140    // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
1141    // at some point.
1142    //
1143    typedef typename boost::multiprecision::detail::canonical<unsigned char, B>::type ui_type;
1144 
1145    s = ui_type(0u);
1146    if(eval_get_sign(x) == 0)
1147    {
1148       r = ui_type(0u);
1149       return;
1150    }
1151    int g = eval_msb(x);
1152    if(g == 0)
1153    {
1154       r = ui_type(1);
1155       return;
1156    }
1157 
1158    B t;
1159    r = x;
1160    g /= 2;
1161    int org_g = g;
1162    eval_bit_set(s, g);
1163    eval_bit_set(t, 2 * g);
1164    eval_subtract(r, x, t);
1165    --g;
1166    if(eval_get_sign(r) == 0)
1167       return;
1168    int msbr = eval_msb(r);
1169    do
1170    {
1171       if(msbr >= org_g + g + 1)
1172       {
1173          t = s;
1174          eval_left_shift(t, g + 1);
1175          eval_bit_set(t, 2 * g);
1176          if(t.compare(r) <= 0)
1177          {
1178             eval_bit_set(s, g);
1179             eval_subtract(r, t);
1180             if(eval_get_sign(r) == 0)
1181                return;
1182             msbr = eval_msb(r);
1183          }
1184       }
1185       --g;
1186    }
1187    while(g >= 0);
1188 }
1189 
1190 //
1191 // These have to implemented by the backend, declared here so that our macro generated code compiles OK.
1192 //
1193 template <class T>
1194 typename enable_if_c<sizeof(T) == 0>::type eval_floor();
1195 template <class T>
1196 typename enable_if_c<sizeof(T) == 0>::type eval_ceil();
1197 template <class T>
1198 typename enable_if_c<sizeof(T) == 0>::type eval_trunc();
1199 template <class T>
1200 typename enable_if_c<sizeof(T) == 0>::type eval_sqrt();
1201 template <class T>
1202 typename enable_if_c<sizeof(T) == 0>::type eval_ldexp();
1203 template <class T>
1204 typename enable_if_c<sizeof(T) == 0>::type eval_frexp();
1205 
1206 //
1207 // eval_logb and eval_scalbn simply assume base 2 and forward to
1208 // eval_ldexp and eval_frexp:
1209 //
1210 template <class B>
eval_ilogb(const B & val)1211 inline typename B::exponent_type eval_ilogb(const B& val)
1212 {
1213    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");
1214    typename B::exponent_type e;
1215    B result;
1216    eval_frexp(result, val, &e);
1217    return e - 1;
1218 }
1219 template <class B>
eval_logb(B & result,const B & val)1220 inline void eval_logb(B& result, const B& val)
1221 {
1222    typedef typename boost::mpl::if_c<boost::is_same<boost::intmax_t, long>::value, boost::long_long_type, boost::intmax_t>::type max_t;
1223    result = static_cast<max_t>(eval_ilogb(val));
1224 }
1225 template <class B, class A>
eval_scalbn(B & result,const B & val,A e)1226 inline void eval_scalbn(B& result, const B& val, A e)
1227 {
1228    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");
1229    eval_ldexp(result, val, static_cast<typename B::exponent_type>(e));
1230 }
1231 //
1232 // These functions are implemented in separate files, but expanded inline here,
1233 // DO NOT CHANGE THE ORDER OF THESE INCLUDES:
1234 //
1235 #include <boost/multiprecision/detail/functions/constants.hpp>
1236 #include <boost/multiprecision/detail/functions/pow.hpp>
1237 #include <boost/multiprecision/detail/functions/trig.hpp>
1238 
1239 }
1240 
1241 } // namespace multiprecision
1242 namespace math{
1243 //
1244 // Default versions of floating point classification routines:
1245 //
1246 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1247 inline int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1248 {
1249    using multiprecision::default_ops::eval_fpclassify;
1250    return eval_fpclassify(arg.backend());
1251 }
1252 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)1253 inline int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1254 {
1255    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1256    return (fpclassify)(value_type(arg));
1257 }
1258 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1259 inline bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1260 {
1261    int v = (fpclassify)(arg);
1262    return (v != (int)FP_INFINITE) && (v != (int)FP_NAN);
1263 }
1264 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)1265 inline bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1266 {
1267    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1268    return (isfinite)(value_type(arg));
1269 }
1270 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1271 inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1272 {
1273    return (fpclassify)(arg) == (int)FP_NAN;
1274 }
1275 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)1276 inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1277 {
1278    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1279    return (isnan)(value_type(arg));
1280 }
1281 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1282 inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1283 {
1284    return (fpclassify)(arg) == (int)FP_INFINITE;
1285 }
1286 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)1287 inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1288 {
1289    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1290    return (isinf)(value_type(arg));
1291 }
1292 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend,ExpressionTemplates> & arg)1293 inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
1294 {
1295    return (fpclassify)(arg) == (int)FP_NORMAL;
1296 }
1297 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)1298 inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
1299 {
1300    typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type value_type;
1301    return (isnormal)(value_type(arg));
1302 }
1303 
1304 } // namespace math
1305 namespace multiprecision{
1306 
1307 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)1308 inline number<B1, ET1>& add(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
1309 {
1310    BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
1311    BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
1312    using default_ops::eval_add;
1313    eval_add(result.backend(), a.backend(), b.backend());
1314    return result;
1315 }
1316 
1317 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)1318 inline number<B1, ET1>& subtract(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
1319 {
1320    BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
1321    BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
1322    using default_ops::eval_subtract;
1323    eval_subtract(result.backend(), a.backend(), b.backend());
1324    return result;
1325 }
1326 
1327 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)1328 inline number<B1, ET1>& multiply(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
1329 {
1330    BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
1331    BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
1332    using default_ops::eval_multiply;
1333    eval_multiply(result.backend(), a.backend(), b.backend());
1334    return result;
1335 }
1336 
1337 template <class B, expression_template_option ET, class I>
1338 inline typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
add(number<B,ET> & result,const I & a,const I & b)1339    add(number<B, ET>& result, const I& a, const I& b)
1340 {
1341    using default_ops::eval_add;
1342    typedef typename detail::canonical<I, B>::type canonical_type;
1343    eval_add(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
1344    return result;
1345 }
1346 
1347 template <class B, expression_template_option ET, class I>
1348 inline typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
subtract(number<B,ET> & result,const I & a,const I & b)1349    subtract(number<B, ET>& result, const I& a, const I& b)
1350 {
1351    using default_ops::eval_subtract;
1352    typedef typename detail::canonical<I, B>::type canonical_type;
1353    eval_subtract(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
1354    return result;
1355 }
1356 
1357 template <class B, expression_template_option ET, class I>
1358 inline typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
multiply(number<B,ET> & result,const I & a,const I & b)1359    multiply(number<B, ET>& result, const I& a, const I& b)
1360 {
1361    using default_ops::eval_multiply;
1362    typedef typename detail::canonical<I, B>::type canonical_type;
1363    eval_multiply(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
1364    return result;
1365 }
1366 
1367 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)1368 inline typename detail::expression<tag, A1, A2, A3, A4>::result_type trunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
1369 {
1370    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1371    return BOOST_MP_MOVE(trunc(number_type(v), pol));
1372 }
1373 
1374 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
trunc(const number<Backend,ExpressionTemplates> & v,const Policy &)1375 inline number<Backend, ExpressionTemplates> trunc(const number<Backend, ExpressionTemplates>& v, const Policy&)
1376 {
1377    using default_ops::eval_trunc;
1378    number<Backend, ExpressionTemplates> result;
1379    eval_trunc(result.backend(), v.backend());
1380    return BOOST_MP_MOVE(result);
1381 }
1382 
1383 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)1384 inline int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
1385 {
1386    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1387    number_type r = trunc(v, pol);
1388    if((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
1389       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, number_type(v), 0, pol);
1390    return r.template convert_to<int>();
1391 }
1392 template <class tag, class A1, class A2, class A3, class A4>
itrunc(const detail::expression<tag,A1,A2,A3,A4> & v)1393 inline int itrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
1394 {
1395    return itrunc(v, boost::math::policies::policy<>());
1396 }
1397 template <class Backend, expression_template_option ExpressionTemplates, class Policy>
itrunc(const number<Backend,ExpressionTemplates> & v,const Policy & pol)1398 inline int itrunc(const number<Backend, ExpressionTemplates>& v, const Policy& pol)
1399 {
1400    number<Backend, ExpressionTemplates> r = trunc(v, pol);
1401    if((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
1402       return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, v, 0, pol);
1403    return r.template convert_to<int>();
1404 }
1405 template <class Backend, expression_template_option ExpressionTemplates>
itrunc(const number<Backend,ExpressionTemplates> & v)1406 inline int itrunc(const number<Backend, ExpressionTemplates>& v)
1407 {
1408    return itrunc(v, boost::math::policies::policy<>());
1409 }
1410 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)1411 inline long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
1412 {
1413    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1414    number_type r = trunc(v, pol);
1415    if((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
1416       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, number_type(v), 0L, pol);
1417    return r.template convert_to<long>();
1418 }
1419 template <class tag, class A1, class A2, class A3, class A4>
ltrunc(const detail::expression<tag,A1,A2,A3,A4> & v)1420 inline long ltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
1421 {
1422    return ltrunc(v, boost::math::policies::policy<>());
1423 }
1424 template <class T, expression_template_option ExpressionTemplates, class Policy>
ltrunc(const number<T,ExpressionTemplates> & v,const Policy & pol)1425 inline long ltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
1426 {
1427    number<T, ExpressionTemplates> r = trunc(v, pol);
1428    if((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
1429       return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, v, 0L, pol);
1430    return r.template convert_to<long>();
1431 }
1432 template <class T, expression_template_option ExpressionTemplates>
ltrunc(const number<T,ExpressionTemplates> & v)1433 inline long ltrunc(const number<T, ExpressionTemplates>& v)
1434 {
1435    return ltrunc(v, boost::math::policies::policy<>());
1436 }
1437 #ifndef BOOST_NO_LONG_LONG
1438 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)1439 inline boost::long_long_type lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
1440 {
1441    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1442    number_type r = trunc(v, pol);
1443    if((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
1444       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, number_type(v), 0LL, pol);
1445    return r.template convert_to<boost::long_long_type>();
1446 }
1447 template <class tag, class A1, class A2, class A3, class A4>
lltrunc(const detail::expression<tag,A1,A2,A3,A4> & v)1448 inline boost::long_long_type lltrunc(const detail::expression<tag, A1, A2, A3, A4>& v)
1449 {
1450    return lltrunc(v, boost::math::policies::policy<>());
1451 }
1452 template <class T, expression_template_option ExpressionTemplates, class Policy>
lltrunc(const number<T,ExpressionTemplates> & v,const Policy & pol)1453 inline boost::long_long_type lltrunc(const number<T, ExpressionTemplates>& v, const Policy& pol)
1454 {
1455    number<T, ExpressionTemplates> r = trunc(v, pol);
1456    if((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
1457       return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, v, 0LL, pol);
1458    return r.template convert_to<boost::long_long_type>();
1459 }
1460 template <class T, expression_template_option ExpressionTemplates>
lltrunc(const number<T,ExpressionTemplates> & v)1461 inline boost::long_long_type lltrunc(const number<T, ExpressionTemplates>& v)
1462 {
1463    return lltrunc(v, boost::math::policies::policy<>());
1464 }
1465 #endif
1466 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)1467 inline typename detail::expression<tag, A1, A2, A3, A4>::result_type round(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
1468 {
1469    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1470    return BOOST_MP_MOVE(round(static_cast<number_type>(v), pol));
1471 }
1472 template <class T, expression_template_option ExpressionTemplates, class Policy>
round(const number<T,ExpressionTemplates> & v,const Policy &)1473 inline number<T, ExpressionTemplates> round(const number<T, ExpressionTemplates>& v, const Policy&)
1474 {
1475    using default_ops::eval_round;
1476    number<T, ExpressionTemplates> result;
1477    eval_round(result.backend(), v.backend());
1478    return BOOST_MP_MOVE(result);
1479 }
1480 
1481 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)1482 inline int iround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
1483 {
1484    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1485    number_type r = round(v, pol);
1486    if((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
1487       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0, pol);
1488    return r.template convert_to<int>();
1489 }
1490 template <class tag, class A1, class A2, class A3, class A4>
iround(const detail::expression<tag,A1,A2,A3,A4> & v)1491 inline int iround(const detail::expression<tag, A1, A2, A3, A4>& v)
1492 {
1493    return iround(v, boost::math::policies::policy<>());
1494 }
1495 template <class T, expression_template_option ExpressionTemplates, class Policy>
iround(const number<T,ExpressionTemplates> & v,const Policy & pol)1496 inline int iround(const number<T, ExpressionTemplates>& v, const Policy& pol)
1497 {
1498    number<T, ExpressionTemplates> r = round(v, pol);
1499    if((r > (std::numeric_limits<int>::max)()) || r < (std::numeric_limits<int>::min)() || !(boost::math::isfinite)(v))
1500       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0, pol);
1501    return r.template convert_to<int>();
1502 }
1503 template <class T, expression_template_option ExpressionTemplates>
iround(const number<T,ExpressionTemplates> & v)1504 inline int iround(const number<T, ExpressionTemplates>& v)
1505 {
1506    return iround(v, boost::math::policies::policy<>());
1507 }
1508 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)1509 inline long lround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
1510 {
1511    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1512    number_type r = round(v, pol);
1513    if((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
1514       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, number_type(v), 0L, pol);
1515    return r.template convert_to<long>();
1516 }
1517 template <class tag, class A1, class A2, class A3, class A4>
lround(const detail::expression<tag,A1,A2,A3,A4> & v)1518 inline long lround(const detail::expression<tag, A1, A2, A3, A4>& v)
1519 {
1520    return lround(v, boost::math::policies::policy<>());
1521 }
1522 template <class T, expression_template_option ExpressionTemplates, class Policy>
lround(const number<T,ExpressionTemplates> & v,const Policy & pol)1523 inline long lround(const number<T, ExpressionTemplates>& v, const Policy& pol)
1524 {
1525    number<T, ExpressionTemplates> r = round(v, pol);
1526    if((r > (std::numeric_limits<long>::max)()) || r < (std::numeric_limits<long>::min)() || !(boost::math::isfinite)(v))
1527       return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, v, 0L, pol);
1528    return r.template convert_to<long>();
1529 }
1530 template <class T, expression_template_option ExpressionTemplates>
lround(const number<T,ExpressionTemplates> & v)1531 inline long lround(const number<T, ExpressionTemplates>& v)
1532 {
1533    return lround(v, boost::math::policies::policy<>());
1534 }
1535 #ifndef BOOST_NO_LONG_LONG
1536 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)1537 inline boost::long_long_type llround(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
1538 {
1539    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1540    number_type r = round(v, pol);
1541    if((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
1542       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0LL, pol);
1543    return r.template convert_to<boost::long_long_type>();
1544 }
1545 template <class tag, class A1, class A2, class A3, class A4>
llround(const detail::expression<tag,A1,A2,A3,A4> & v)1546 inline boost::long_long_type llround(const detail::expression<tag, A1, A2, A3, A4>& v)
1547 {
1548    return llround(v, boost::math::policies::policy<>());
1549 }
1550 template <class T, expression_template_option ExpressionTemplates, class Policy>
llround(const number<T,ExpressionTemplates> & v,const Policy & pol)1551 inline boost::long_long_type llround(const number<T, ExpressionTemplates>& v, const Policy& pol)
1552 {
1553    number<T, ExpressionTemplates> r = round(v, pol);
1554    if((r > (std::numeric_limits<boost::long_long_type>::max)()) || r < (std::numeric_limits<boost::long_long_type>::min)() || !(boost::math::isfinite)(v))
1555       return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0LL, pol);
1556    return r.template convert_to<boost::long_long_type>();
1557 }
1558 template <class T, expression_template_option ExpressionTemplates>
llround(const number<T,ExpressionTemplates> & v)1559 inline boost::long_long_type llround(const number<T, ExpressionTemplates>& v)
1560 {
1561    return llround(v, boost::math::policies::policy<>());
1562 }
1563 #endif
1564 //
1565 // frexp does not return an expression template since we require the
1566 // integer argument to be evaluated even if the returned value is
1567 // not assigned to anything...
1568 //
1569 template <class T, expression_template_option ExpressionTemplates>
frexp(const number<T,ExpressionTemplates> & v,short * pint)1570 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)
1571 {
1572    using default_ops::eval_frexp;
1573    number<T, ExpressionTemplates> result;
1574    eval_frexp(result.backend(), v.backend(), pint);
1575    return BOOST_MP_MOVE(result);
1576 }
1577 template <class tag, class A1, class A2, class A3, class A4>
1578 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)1579    frexp(const detail::expression<tag, A1, A2, A3, A4>& v, short* pint)
1580 {
1581    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1582    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
1583 }
1584 template <class T, expression_template_option ExpressionTemplates>
frexp(const number<T,ExpressionTemplates> & v,int * pint)1585 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)
1586 {
1587    using default_ops::eval_frexp;
1588    number<T, ExpressionTemplates> result;
1589    eval_frexp(result.backend(), v.backend(), pint);
1590    return BOOST_MP_MOVE(result);
1591 }
1592 template <class tag, class A1, class A2, class A3, class A4>
1593 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)1594 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, int* pint)
1595 {
1596    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1597    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
1598 }
1599 template <class T, expression_template_option ExpressionTemplates>
frexp(const number<T,ExpressionTemplates> & v,long * pint)1600 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)
1601 {
1602    using default_ops::eval_frexp;
1603    number<T, ExpressionTemplates> result;
1604    eval_frexp(result.backend(), v.backend(), pint);
1605    return BOOST_MP_MOVE(result);
1606 }
1607 template <class tag, class A1, class A2, class A3, class A4>
1608 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)1609 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, long* pint)
1610 {
1611    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1612    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
1613 }
1614 template <class T, expression_template_option ExpressionTemplates>
frexp(const number<T,ExpressionTemplates> & v,boost::long_long_type * pint)1615 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)
1616 {
1617    using default_ops::eval_frexp;
1618    number<T, ExpressionTemplates> result;
1619    eval_frexp(result.backend(), v.backend(), pint);
1620    return BOOST_MP_MOVE(result);
1621 }
1622 template <class tag, class A1, class A2, class A3, class A4>
1623 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)1624 frexp(const detail::expression<tag, A1, A2, A3, A4>& v, boost::long_long_type* pint)
1625 {
1626    typedef typename detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
1627    return BOOST_MP_MOVE(frexp(static_cast<number_type>(v), pint));
1628 }
1629 
1630 template <class B, expression_template_option ExpressionTemplates>
1631 inline typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, ExpressionTemplates> >::type
sqrt(const number<B,ExpressionTemplates> & x)1632    sqrt(const number<B, ExpressionTemplates>& x)
1633 {
1634    using default_ops::eval_integer_sqrt;
1635    number<B, ExpressionTemplates> s, r;
1636    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
1637    return s;
1638 }
1639 
1640 template <class B, expression_template_option ExpressionTemplates>
1641 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)1642    sqrt(const number<B, ExpressionTemplates>& x, number<B, ExpressionTemplates>& r)
1643 {
1644    using default_ops::eval_integer_sqrt;
1645    number<B, ExpressionTemplates> s;
1646    eval_integer_sqrt(s.backend(), r.backend(), x.backend());
1647    return s;
1648 }
1649 
1650 #define UNARY_OP_FUNCTOR(func, category)\
1651 namespace detail{\
1652 template <class Backend> \
1653 struct BOOST_JOIN(func, _funct)\
1654 {\
1655    void operator()(Backend& result, const Backend& arg)const\
1656    {\
1657       using default_ops::BOOST_JOIN(eval_,func);\
1658       BOOST_JOIN(eval_,func)(result, arg);\
1659    }\
1660 };\
1661 \
1662 }\
1663 \
1664 template <class tag, class A1, class A2, class A3, class A4> \
1665 inline typename enable_if_c<number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category,\
1666    detail::expression<\
1667     detail::function\
1668   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1669   , detail::expression<tag, A1, A2, A3, A4> > \
1670 >::type \
1671 func(const detail::expression<tag, A1, A2, A3, A4>& arg)\
1672 {\
1673     return detail::expression<\
1674     detail::function\
1675   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1676   , detail::expression<tag, A1, A2, A3, A4> \
1677 > (\
1678         detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
1679       , arg   \
1680     );\
1681 }\
1682 template <class Backend> \
1683 inline typename enable_if_c<number_category<Backend>::value == category,\
1684    detail::expression<\
1685     detail::function\
1686   , detail::BOOST_JOIN(func, _funct)<Backend> \
1687   , number<Backend, et_on> > \
1688 >::type \
1689 func(const number<Backend, et_on>& arg)\
1690 {\
1691     return detail::expression<\
1692     detail::function\
1693   , detail::BOOST_JOIN(func, _funct)<Backend> \
1694   , number<Backend, et_on> \
1695   >(\
1696         detail::BOOST_JOIN(func, _funct)<Backend>() \
1697       , arg   \
1698     );\
1699 }\
1700 template <class Backend> \
1701 inline typename boost::enable_if_c<\
1702    boost::multiprecision::number_category<Backend>::value == category,\
1703    number<Backend, et_off> >::type \
1704 func(const number<Backend, et_off>& arg)\
1705 {\
1706    number<Backend, et_off> result;\
1707    using default_ops::BOOST_JOIN(eval_,func);\
1708    BOOST_JOIN(eval_,func)(result.backend(), arg.backend());\
1709    return BOOST_MP_MOVE(result);\
1710 }
1711 
1712 #define BINARY_OP_FUNCTOR(func, category)\
1713 namespace detail{\
1714 template <class Backend> \
1715 struct BOOST_JOIN(func, _funct)\
1716 {\
1717    void operator()(Backend& result, const Backend& arg, const Backend& a)const\
1718    {\
1719       using default_ops:: BOOST_JOIN(eval_,func);\
1720       BOOST_JOIN(eval_,func)(result, arg, a);\
1721    }\
1722    template <class Arithmetic> \
1723    void operator()(Backend& result, const Backend& arg, const Arithmetic& a)const\
1724    {\
1725       using default_ops:: BOOST_JOIN(eval_,func);\
1726       BOOST_JOIN(eval_,func)(result, arg, a);\
1727    }\
1728    template <class Arithmetic> \
1729    void operator()(Backend& result, const Arithmetic& arg, const Backend& a)const\
1730    {\
1731       using default_ops:: BOOST_JOIN(eval_,func);\
1732       BOOST_JOIN(eval_,func)(result, arg, a);\
1733    }\
1734 };\
1735 \
1736 }\
1737 template <class Backend> \
1738 inline typename enable_if_c<number_category<Backend>::value == category,\
1739    detail::expression<\
1740     detail::function\
1741   , detail::BOOST_JOIN(func, _funct)<Backend> \
1742   , number<Backend, et_on> \
1743   , number<Backend, et_on> > \
1744 >::type \
1745 func(const number<Backend, et_on>& arg, const number<Backend, et_on>& a)\
1746 {\
1747     return detail::expression<\
1748     detail::function\
1749   , detail::BOOST_JOIN(func, _funct)<Backend> \
1750   , number<Backend, et_on> \
1751   , number<Backend, et_on> \
1752   >(\
1753         detail::BOOST_JOIN(func, _funct)<Backend>() \
1754       , arg,\
1755       a\
1756     );\
1757 }\
1758 template <class Backend, class tag, class A1, class A2, class A3, class A4> \
1759 inline typename enable_if_c<\
1760    (number_category<Backend>::value == category) && (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),\
1761    detail::expression<\
1762     detail::function\
1763   , detail::BOOST_JOIN(func, _funct)<Backend> \
1764   , number<Backend, et_on> \
1765   , detail::expression<tag, A1, A2, A3, A4> > \
1766 >::type \
1767 func(const number<Backend, et_on>& arg, const detail::expression<tag, A1, A2, A3, A4>& a)\
1768 {\
1769     return detail::expression<\
1770     detail::function\
1771   , detail::BOOST_JOIN(func, _funct)<Backend> \
1772   , number<Backend, et_on> \
1773   , detail::expression<tag, A1, A2, A3, A4> \
1774   >(\
1775         detail::BOOST_JOIN(func, _funct)<Backend>() \
1776       , arg,\
1777       a\
1778     );\
1779 }\
1780 template <class tag, class A1, class A2, class A3, class A4, class Backend> \
1781 inline typename enable_if_c<\
1782    (number_category<Backend>::value == category) && (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),\
1783    detail::expression<\
1784     detail::function\
1785   , detail::BOOST_JOIN(func, _funct)<Backend> \
1786   , detail::expression<tag, A1, A2, A3, A4> \
1787   , number<Backend, et_on> > \
1788 >::type \
1789 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const number<Backend, et_on>& a)\
1790 {\
1791     return detail::expression<\
1792     detail::function\
1793   , detail::BOOST_JOIN(func, _funct)<Backend> \
1794   , detail::expression<tag, A1, A2, A3, A4> \
1795   , number<Backend, et_on> \
1796   >(\
1797         detail::BOOST_JOIN(func, _funct)<Backend>() \
1798       , arg,\
1799       a\
1800     );\
1801 }\
1802 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b> \
1803 inline typename enable_if_c<\
1804       (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category) && (number_category<detail::expression<tagb, A1b, A2b, A3b, A4b> >::value == category),\
1805    detail::expression<\
1806     detail::function\
1807   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1808   , detail::expression<tag, A1, A2, A3, A4> \
1809   , detail::expression<tagb, A1b, A2b, A3b, A4b> > \
1810 >::type \
1811 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const detail::expression<tagb, A1b, A2b, A3b, A4b>& a)\
1812 {\
1813     return detail::expression<\
1814     detail::function\
1815   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1816   , detail::expression<tag, A1, A2, A3, A4> \
1817   , detail::expression<tagb, A1b, A2b, A3b, A4b> \
1818   >(\
1819         detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
1820       , arg,\
1821       a\
1822     );\
1823 }\
1824 template <class Backend, class Arithmetic> \
1825 inline typename enable_if_c<\
1826    is_arithmetic<Arithmetic>::value && (number_category<Backend>::value == category),\
1827    detail::expression<\
1828     detail::function\
1829   , detail::BOOST_JOIN(func, _funct)<Backend> \
1830   , number<Backend, et_on> \
1831   , Arithmetic\
1832   > \
1833 >::type \
1834 func(const number<Backend, et_on>& arg, const Arithmetic& a)\
1835 {\
1836     return detail::expression<\
1837     detail::function\
1838   , detail::BOOST_JOIN(func, _funct)<Backend> \
1839   , number<Backend, et_on> \
1840   , Arithmetic\
1841   >(\
1842         detail::BOOST_JOIN(func, _funct)<Backend>() \
1843       , arg,\
1844       a\
1845     );\
1846 }\
1847 template <class tag, class A1, class A2, class A3, class A4, class Arithmetic> \
1848 inline typename enable_if_c<\
1849    is_arithmetic<Arithmetic>::value && (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),\
1850    detail::expression<\
1851     detail::function\
1852   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1853   , detail::expression<tag, A1, A2, A3, A4> \
1854   , Arithmetic\
1855   > \
1856 >::type \
1857 func(const detail::expression<tag, A1, A2, A3, A4>& arg, const Arithmetic& a)\
1858 {\
1859     return detail::expression<\
1860     detail::function\
1861   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1862   , detail::expression<tag, A1, A2, A3, A4> \
1863   , Arithmetic\
1864    >(\
1865         detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
1866       , arg,\
1867       a\
1868     );\
1869 }\
1870 template <class Backend, class Arithmetic> \
1871 inline typename enable_if_c<\
1872    is_arithmetic<Arithmetic>::value && (number_category<Backend>::value == category),\
1873    detail::expression<\
1874     detail::function\
1875   , detail::BOOST_JOIN(func, _funct)<Backend> \
1876   , Arithmetic \
1877   , number<Backend, et_on> \
1878   > \
1879 >::type \
1880 func(const Arithmetic& arg, const number<Backend, et_on>& a)\
1881 {\
1882     return detail::expression<\
1883     detail::function\
1884   , detail::BOOST_JOIN(func, _funct)<Backend> \
1885   , Arithmetic \
1886   , number<Backend, et_on> \
1887   >(\
1888         detail::BOOST_JOIN(func, _funct)<Backend>() \
1889       , arg,\
1890       a\
1891     );\
1892 }\
1893 template <class tag, class A1, class A2, class A3, class A4, class Arithmetic> \
1894 inline typename enable_if_c<\
1895    is_arithmetic<Arithmetic>::value && (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),\
1896    detail::expression<\
1897     detail::function\
1898   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1899   , Arithmetic \
1900   , detail::expression<tag, A1, A2, A3, A4> \
1901   > \
1902 >::type \
1903 func(const Arithmetic& arg, const detail::expression<tag, A1, A2, A3, A4>& a)\
1904 {\
1905     return detail::expression<\
1906     detail::function\
1907   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1908   , Arithmetic \
1909   , detail::expression<tag, A1, A2, A3, A4> \
1910    >(\
1911         detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
1912       , arg,\
1913       a\
1914     );\
1915 }\
1916 template <class Backend> \
1917 inline typename enable_if_c<(number_category<Backend>::value == category),\
1918    number<Backend, et_off> >::type \
1919 func(const number<Backend, et_off>& arg, const number<Backend, et_off>& a)\
1920 {\
1921    number<Backend, et_off> result;\
1922    using default_ops:: BOOST_JOIN(eval_,func);\
1923    BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), a.backend());\
1924    return BOOST_MP_MOVE(result);\
1925 }\
1926 template <class Backend, class Arithmetic> \
1927 inline typename enable_if_c<\
1928    is_arithmetic<Arithmetic>::value && (number_category<Backend>::value == category),\
1929    number<Backend, et_off> \
1930 >::type \
1931 func(const number<Backend, et_off>& arg, const Arithmetic& a)\
1932 {\
1933    typedef typename detail::canonical<Arithmetic, Backend>::type canonical_type;\
1934    number<Backend, et_off> result;\
1935    using default_ops:: BOOST_JOIN(eval_,func);\
1936    BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), static_cast<canonical_type>(a));\
1937    return BOOST_MP_MOVE(result);\
1938 }\
1939 template <class Backend, class Arithmetic> \
1940 inline typename enable_if_c<\
1941    is_arithmetic<Arithmetic>::value && (number_category<Backend>::value == category),\
1942    number<Backend, et_off> \
1943 >::type \
1944 func(const Arithmetic& a, const number<Backend, et_off>& arg)\
1945 {\
1946    typedef typename detail::canonical<Arithmetic, Backend>::type canonical_type;\
1947    number<Backend, et_off> result;\
1948    using default_ops:: BOOST_JOIN(eval_,func);\
1949    BOOST_JOIN(eval_,func)(result.backend(), static_cast<canonical_type>(a), arg.backend());\
1950    return BOOST_MP_MOVE(result);\
1951 }\
1952 
1953 
1954 #define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)\
1955 template <class tag, class A1, class A2, class A3, class A4> \
1956 inline typename enable_if_c<\
1957    (number_category<detail::expression<tag, A1, A2, A3, A4> >::value == category),\
1958    detail::expression<\
1959     detail::function\
1960   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1961   , detail::expression<tag, A1, A2, A3, A4> \
1962   , Arg2> \
1963 >::type \
1964 func(const detail::expression<tag, A1, A2, A3, A4>& arg, Arg2 const& a)\
1965 {\
1966     return detail::expression<\
1967     detail::function\
1968   , detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type> \
1969   , detail::expression<tag, A1, A2, A3, A4> \
1970   , Arg2\
1971    >(\
1972         detail::BOOST_JOIN(func, _funct)<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>() \
1973       , arg, a   \
1974     );\
1975 }\
1976 template <class Backend> \
1977 inline typename enable_if_c<\
1978    (number_category<Backend>::value == category),\
1979   detail::expression<\
1980     detail::function\
1981   , detail::BOOST_JOIN(func, _funct)<Backend> \
1982   , number<Backend, et_on> \
1983   , Arg2> \
1984 >::type \
1985 func(const number<Backend, et_on>& arg, Arg2 const& a)\
1986 {\
1987     return detail::expression<\
1988     detail::function\
1989   , detail::BOOST_JOIN(func, _funct)<Backend> \
1990   , number<Backend, et_on> \
1991   , Arg2\
1992   >(\
1993         detail::BOOST_JOIN(func, _funct)<Backend>() \
1994       , arg,\
1995       a\
1996     );\
1997 }\
1998 template <class Backend> \
1999 inline typename enable_if_c<\
2000   (number_category<Backend>::value == category),\
2001   number<Backend, et_off> >::type \
2002 func(const number<Backend, et_off>& arg, Arg2 const& a)\
2003 {\
2004    number<Backend, et_off> result;\
2005    using default_ops:: BOOST_JOIN(eval_,func);\
2006    BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), a);\
2007    return BOOST_MP_MOVE(result);\
2008 }\
2009 
2010 #define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category)\
2011 namespace detail{\
2012 template <class Backend> \
2013 struct BOOST_JOIN(func, _funct)\
2014 {\
2015    template <class Arg>\
2016    void operator()(Backend& result, Backend const& arg, Arg a)const\
2017    {\
2018       using default_ops:: BOOST_JOIN(eval_,func);\
2019       BOOST_JOIN(eval_,func)(result, arg, a);\
2020    }\
2021 };\
2022 \
2023 }\
2024 \
2025 HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)
2026 
2027 namespace detail{
2028 template <class Backend>
2029 struct abs_funct
2030 {
operator ()boost::multiprecision::detail::abs_funct2031    void operator()(Backend& result, const Backend& arg)const
2032    {
2033       using default_ops::eval_abs;
2034       eval_abs(result, arg);
2035    }
2036 };
2037 
2038 }
2039 
2040 template <class tag, class A1, class A2, class A3, class A4>
2041 inline detail::expression<
2042     detail::function
2043   , detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>
2044   , detail::expression<tag, A1, A2, A3, A4> >
abs(const detail::expression<tag,A1,A2,A3,A4> & arg)2045 abs(const detail::expression<tag, A1, A2, A3, A4>& arg)
2046 {
2047     return detail::expression<
2048     detail::function
2049   , detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>
2050   , detail::expression<tag, A1, A2, A3, A4>
2051 > (
2052         detail::abs_funct<typename detail::backend_type<detail::expression<tag, A1, A2, A3, A4> >::type>()
2053       , arg
2054     );
2055 }
2056 template <class Backend>
2057 inline detail::expression<
2058     detail::function
2059   , detail::abs_funct<Backend>
2060   , number<Backend, et_on> >
abs(const number<Backend,et_on> & arg)2061 abs(const number<Backend, et_on>& arg)
2062 {
2063     return detail::expression<
2064     detail::function
2065   , detail::abs_funct<Backend>
2066   , number<Backend, et_on>
2067   >(
2068         detail::abs_funct<Backend>()
2069       , arg
2070     );
2071 }
2072 template <class Backend>
2073 inline number<Backend, et_off>
abs(const number<Backend,et_off> & arg)2074 abs(const number<Backend, et_off>& arg)
2075 {
2076    number<Backend, et_off> result;
2077    using default_ops::eval_abs;
2078    eval_abs(result.backend(), arg.backend());
2079    return BOOST_MP_MOVE(result);
2080 }
2081 
UNARY_OP_FUNCTOR(fabs,number_kind_floating_point)2082 UNARY_OP_FUNCTOR(fabs, number_kind_floating_point)
2083 UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point)
2084 UNARY_OP_FUNCTOR(floor, number_kind_floating_point)
2085 UNARY_OP_FUNCTOR(ceil, number_kind_floating_point)
2086 UNARY_OP_FUNCTOR(trunc, number_kind_floating_point)
2087 UNARY_OP_FUNCTOR(round, number_kind_floating_point)
2088 UNARY_OP_FUNCTOR(exp, number_kind_floating_point)
2089 UNARY_OP_FUNCTOR(log, number_kind_floating_point)
2090 UNARY_OP_FUNCTOR(log10, number_kind_floating_point)
2091 UNARY_OP_FUNCTOR(cos, number_kind_floating_point)
2092 UNARY_OP_FUNCTOR(sin, number_kind_floating_point)
2093 UNARY_OP_FUNCTOR(tan, number_kind_floating_point)
2094 UNARY_OP_FUNCTOR(asin, number_kind_floating_point)
2095 UNARY_OP_FUNCTOR(acos, number_kind_floating_point)
2096 UNARY_OP_FUNCTOR(atan, number_kind_floating_point)
2097 UNARY_OP_FUNCTOR(cosh, number_kind_floating_point)
2098 UNARY_OP_FUNCTOR(sinh, number_kind_floating_point)
2099 UNARY_OP_FUNCTOR(tanh, number_kind_floating_point)
2100 
2101 HETERO_BINARY_OP_FUNCTOR(ldexp, short, number_kind_floating_point)
2102 //HETERO_BINARY_OP_FUNCTOR(frexp, short*, number_kind_floating_point)
2103 HETERO_BINARY_OP_FUNCTOR_B(ldexp, int, number_kind_floating_point)
2104 //HETERO_BINARY_OP_FUNCTOR_B(frexp, int*, number_kind_floating_point)
2105 HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point)
2106 //HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point)
2107 HETERO_BINARY_OP_FUNCTOR_B(ldexp, boost::long_long_type, number_kind_floating_point)
2108 //HETERO_BINARY_OP_FUNCTOR_B(frexp, boost::long_long_type*, number_kind_floating_point)
2109 BINARY_OP_FUNCTOR(pow, number_kind_floating_point)
2110 BINARY_OP_FUNCTOR(fmod, number_kind_floating_point)
2111 BINARY_OP_FUNCTOR(atan2, number_kind_floating_point)
2112 
2113 UNARY_OP_FUNCTOR(logb, number_kind_floating_point)
2114 HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point)
2115 HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point)
2116 HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point)
2117 HETERO_BINARY_OP_FUNCTOR_B(scalbn, boost::long_long_type, number_kind_floating_point)
2118 
2119 //
2120 // Integer functions:
2121 //
2122 BINARY_OP_FUNCTOR(gcd, number_kind_integer)
2123 BINARY_OP_FUNCTOR(lcm, number_kind_integer)
2124 HETERO_BINARY_OP_FUNCTOR_B(pow, unsigned, number_kind_integer)
2125 
2126 #undef BINARY_OP_FUNCTOR
2127 #undef UNARY_OP_FUNCTOR
2128 
2129 //
2130 // ilogb:
2131 //
2132 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
2133 inline typename enable_if_c<number_category<Backend>::value == number_kind_floating_point, typename Backend::exponent_type>::type
2134    ilogb(const multiprecision::number<Backend, ExpressionTemplates>& val)
2135 {
2136    using default_ops::eval_ilogb;
2137    return eval_ilogb(val.backend());
2138 }
2139 
2140 template <class tag, class A1, class A2, class A3, class A4>
2141 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)2142 ilogb(const detail::expression<tag, A1, A2, A3, A4>& val)
2143 {
2144    using default_ops::eval_ilogb;
2145    typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type arg(val);
2146    return eval_ilogb(arg.backend());
2147 }
2148 
2149 } //namespace multiprecision
2150 
2151 namespace math{
2152 //
2153 // Overload of Boost.Math functions that find the wrong overload when used with number:
2154 //
2155 namespace detail{
2156    template <class T> T sinc_pi_imp(T);
2157    template <class T> T sinhc_pi_imp(T);
2158 }
2159 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
sinc_pi(const multiprecision::number<Backend,ExpressionTemplates> & x)2160 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
2161 {
2162    return BOOST_MP_MOVE(detail::sinc_pi_imp(x));
2163 }
2164 
2165 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
sinc_pi(const multiprecision::number<Backend,ExpressionTemplates> & x,const Policy &)2166 inline multiprecision::number<Backend, ExpressionTemplates> sinc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
2167 {
2168    return BOOST_MP_MOVE(detail::sinc_pi_imp(x));
2169 }
2170 
2171 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
sinhc_pi(const multiprecision::number<Backend,ExpressionTemplates> & x)2172 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x)
2173 {
2174    return BOOST_MP_MOVE(detail::sinhc_pi_imp(x));
2175 }
2176 
2177 template <class Backend, multiprecision::expression_template_option ExpressionTemplates, class Policy>
sinhc_pi(const multiprecision::number<Backend,ExpressionTemplates> & x,const Policy &)2178 inline multiprecision::number<Backend, ExpressionTemplates> sinhc_pi(const multiprecision::number<Backend, ExpressionTemplates>& x, const Policy&)
2179 {
2180    return BOOST_MP_MOVE(boost::math::sinhc_pi(x));
2181 }
2182 
2183 #ifdef BOOST_MSVC
2184 #pragma warning(pop)
2185 #endif
2186 } // namespace math
2187 } // namespace boost
2188 
2189 //
2190 // This has to come last of all:
2191 //
2192 #include <boost/multiprecision/detail/no_et_ops.hpp>
2193 #include <boost/multiprecision/detail/et_ops.hpp>
2194 
2195 #endif
2196 
2197