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