comparison DEPENDENCIES/generic/include/boost/math/bindings/mpfr.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children c530137014c0
comparison
equal deleted inserted replaced
15:663ca0da4350 16:2665513ce2d3
1 // Copyright John Maddock 2008.
2 // Use, modification and distribution are subject to the
3 // Boost 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 // Wrapper that works with mpfr_class defined in gmpfrxx.h
7 // See http://math.berkeley.edu/~wilken/code/gmpfrxx/
8 // Also requires the gmp and mpfr libraries.
9 //
10
11 #ifndef BOOST_MATH_MPLFR_BINDINGS_HPP
12 #define BOOST_MATH_MPLFR_BINDINGS_HPP
13
14 #include <boost/config.hpp>
15 #include <boost/lexical_cast.hpp>
16
17 #ifdef BOOST_MSVC
18 //
19 // We get a lot of warnings from the gmp, mpfr and gmpfrxx headers,
20 // disable them here, so we only see warnings from *our* code:
21 //
22 #pragma warning(push)
23 #pragma warning(disable: 4127 4800 4512)
24 #endif
25
26 #include <gmpfrxx.h>
27
28 #ifdef BOOST_MSVC
29 #pragma warning(pop)
30 #endif
31
32 #include <boost/math/tools/precision.hpp>
33 #include <boost/math/tools/real_cast.hpp>
34 #include <boost/math/policies/policy.hpp>
35 #include <boost/math/distributions/fwd.hpp>
36 #include <boost/math/special_functions/math_fwd.hpp>
37 #include <boost/math/bindings/detail/big_digamma.hpp>
38 #include <boost/math/bindings/detail/big_lanczos.hpp>
39
40 inline mpfr_class fabs(const mpfr_class& v)
41 {
42 return abs(v);
43 }
44 template <class T, class U>
45 inline mpfr_class fabs(const __gmp_expr<T,U>& v)
46 {
47 return abs(static_cast<mpfr_class>(v));
48 }
49
50 inline mpfr_class pow(const mpfr_class& b, const mpfr_class& e)
51 {
52 mpfr_class result;
53 mpfr_pow(result.__get_mp(), b.__get_mp(), e.__get_mp(), GMP_RNDN);
54 return result;
55 }
56 /*
57 template <class T, class U, class V, class W>
58 inline mpfr_class pow(const __gmp_expr<T,U>& b, const __gmp_expr<V,W>& e)
59 {
60 return pow(static_cast<mpfr_class>(b), static_cast<mpfr_class>(e));
61 }
62 */
63 inline mpfr_class ldexp(const mpfr_class& v, int e)
64 {
65 //int e = mpfr_get_exp(*v.__get_mp());
66 mpfr_class result(v);
67 mpfr_set_exp(result.__get_mp(), e);
68 return result;
69 }
70 template <class T, class U>
71 inline mpfr_class ldexp(const __gmp_expr<T,U>& v, int e)
72 {
73 return ldexp(static_cast<mpfr_class>(v), e);
74 }
75
76 inline mpfr_class frexp(const mpfr_class& v, int* expon)
77 {
78 int e = mpfr_get_exp(v.__get_mp());
79 mpfr_class result(v);
80 mpfr_set_exp(result.__get_mp(), 0);
81 *expon = e;
82 return result;
83 }
84 template <class T, class U>
85 inline mpfr_class frexp(const __gmp_expr<T,U>& v, int* expon)
86 {
87 return frexp(static_cast<mpfr_class>(v), expon);
88 }
89
90 inline mpfr_class fmod(const mpfr_class& v1, const mpfr_class& v2)
91 {
92 mpfr_class n;
93 if(v1 < 0)
94 n = ceil(v1 / v2);
95 else
96 n = floor(v1 / v2);
97 return v1 - n * v2;
98 }
99 template <class T, class U, class V, class W>
100 inline mpfr_class fmod(const __gmp_expr<T,U>& v1, const __gmp_expr<V,W>& v2)
101 {
102 return fmod(static_cast<mpfr_class>(v1), static_cast<mpfr_class>(v2));
103 }
104
105 template <class Policy>
106 inline mpfr_class modf(const mpfr_class& v, long long* ipart, const Policy& pol)
107 {
108 *ipart = lltrunc(v, pol);
109 return v - boost::math::tools::real_cast<mpfr_class>(*ipart);
110 }
111 template <class T, class U, class Policy>
112 inline mpfr_class modf(const __gmp_expr<T,U>& v, long long* ipart, const Policy& pol)
113 {
114 return modf(static_cast<mpfr_class>(v), ipart, pol);
115 }
116
117 template <class Policy>
118 inline int iround(mpfr_class const& x, const Policy&)
119 {
120 return boost::math::tools::real_cast<int>(boost::math::round(x, typename boost::math::policies::normalise<Policy, boost::math::policies::rounding_error< boost::math::policies::throw_on_error> >::type()));
121 }
122 template <class T, class U, class Policy>
123 inline int iround(__gmp_expr<T,U> const& x, const Policy& pol)
124 {
125 return iround(static_cast<mpfr_class>(x), pol);
126 }
127
128 template <class Policy>
129 inline long lround(mpfr_class const& x, const Policy&)
130 {
131 return boost::math::tools::real_cast<long>(boost::math::round(x, typename boost::math::policies::normalise<Policy, boost::math::policies::rounding_error< boost::math::policies::throw_on_error> >::type()));
132 }
133 template <class T, class U, class Policy>
134 inline long lround(__gmp_expr<T,U> const& x, const Policy& pol)
135 {
136 return lround(static_cast<mpfr_class>(x), pol);
137 }
138
139 template <class Policy>
140 inline long long llround(mpfr_class const& x, const Policy&)
141 {
142 return boost::math::tools::real_cast<long long>(boost::math::round(x, typename boost::math::policies::normalise<Policy, boost::math::policies::rounding_error< boost::math::policies::throw_on_error> >::type()));
143 }
144 template <class T, class U, class Policy>
145 inline long long llround(__gmp_expr<T,U> const& x, const Policy& pol)
146 {
147 return llround(static_cast<mpfr_class>(x), pol);
148 }
149
150 template <class Policy>
151 inline int itrunc(mpfr_class const& x, const Policy&)
152 {
153 return boost::math::tools::real_cast<int>(boost::math::trunc(x, typename boost::math::policies::normalise<Policy, boost::math::policies::rounding_error< boost::math::policies::throw_on_error> >::type()));
154 }
155 template <class T, class U, class Policy>
156 inline int itrunc(__gmp_expr<T,U> const& x, const Policy& pol)
157 {
158 return itrunc(static_cast<mpfr_class>(x), pol);
159 }
160
161 template <class Policy>
162 inline long ltrunc(mpfr_class const& x, const Policy&)
163 {
164 return boost::math::tools::real_cast<long>(boost::math::trunc(x, typename boost::math::policies::normalise<Policy, boost::math::policies::rounding_error< boost::math::policies::throw_on_error> >::type()));
165 }
166 template <class T, class U, class Policy>
167 inline long ltrunc(__gmp_expr<T,U> const& x, const Policy& pol)
168 {
169 return ltrunc(static_cast<mpfr_class>(x), pol);
170 }
171
172 template <class Policy>
173 inline long long lltrunc(mpfr_class const& x, const Policy&)
174 {
175 return boost::math::tools::real_cast<long long>(boost::math::trunc(x, typename boost::math::policies::normalise<Policy, boost::math::policies::rounding_error< boost::math::policies::throw_on_error> >::type()));
176 }
177 template <class T, class U, class Policy>
178 inline long long lltrunc(__gmp_expr<T,U> const& x, const Policy& pol)
179 {
180 return lltrunc(static_cast<mpfr_class>(x), pol);
181 }
182
183 namespace boost{ namespace math{
184
185 #if defined(__GNUC__) && (__GNUC__ < 4)
186 using ::iround;
187 using ::lround;
188 using ::llround;
189 using ::itrunc;
190 using ::ltrunc;
191 using ::lltrunc;
192 using ::modf;
193 #endif
194
195 namespace lanczos{
196
197 struct mpfr_lanczos
198 {
199 static mpfr_class lanczos_sum(const mpfr_class& z)
200 {
201 unsigned long p = z.get_dprec();
202 if(p <= 72)
203 return lanczos13UDT::lanczos_sum(z);
204 else if(p <= 120)
205 return lanczos22UDT::lanczos_sum(z);
206 else if(p <= 170)
207 return lanczos31UDT::lanczos_sum(z);
208 else //if(p <= 370) approx 100 digit precision:
209 return lanczos61UDT::lanczos_sum(z);
210 }
211 static mpfr_class lanczos_sum_expG_scaled(const mpfr_class& z)
212 {
213 unsigned long p = z.get_dprec();
214 if(p <= 72)
215 return lanczos13UDT::lanczos_sum_expG_scaled(z);
216 else if(p <= 120)
217 return lanczos22UDT::lanczos_sum_expG_scaled(z);
218 else if(p <= 170)
219 return lanczos31UDT::lanczos_sum_expG_scaled(z);
220 else //if(p <= 370) approx 100 digit precision:
221 return lanczos61UDT::lanczos_sum_expG_scaled(z);
222 }
223 static mpfr_class lanczos_sum_near_1(const mpfr_class& z)
224 {
225 unsigned long p = z.get_dprec();
226 if(p <= 72)
227 return lanczos13UDT::lanczos_sum_near_1(z);
228 else if(p <= 120)
229 return lanczos22UDT::lanczos_sum_near_1(z);
230 else if(p <= 170)
231 return lanczos31UDT::lanczos_sum_near_1(z);
232 else //if(p <= 370) approx 100 digit precision:
233 return lanczos61UDT::lanczos_sum_near_1(z);
234 }
235 static mpfr_class lanczos_sum_near_2(const mpfr_class& z)
236 {
237 unsigned long p = z.get_dprec();
238 if(p <= 72)
239 return lanczos13UDT::lanczos_sum_near_2(z);
240 else if(p <= 120)
241 return lanczos22UDT::lanczos_sum_near_2(z);
242 else if(p <= 170)
243 return lanczos31UDT::lanczos_sum_near_2(z);
244 else //if(p <= 370) approx 100 digit precision:
245 return lanczos61UDT::lanczos_sum_near_2(z);
246 }
247 static mpfr_class g()
248 {
249 unsigned long p = mpfr_class::get_dprec();
250 if(p <= 72)
251 return lanczos13UDT::g();
252 else if(p <= 120)
253 return lanczos22UDT::g();
254 else if(p <= 170)
255 return lanczos31UDT::g();
256 else //if(p <= 370) approx 100 digit precision:
257 return lanczos61UDT::g();
258 }
259 };
260
261 template<class Policy>
262 struct lanczos<mpfr_class, Policy>
263 {
264 typedef mpfr_lanczos type;
265 };
266
267 } // namespace lanczos
268
269 namespace constants{
270
271 template <class Real, class Policy>
272 struct construction_traits;
273
274 template <class Policy>
275 struct construction_traits<mpfr_class, Policy>
276 {
277 typedef mpl::int_<0> type;
278 };
279
280 }
281
282 namespace tools
283 {
284
285 template <class T, class U>
286 struct promote_arg<__gmp_expr<T,U> >
287 { // If T is integral type, then promote to double.
288 typedef mpfr_class type;
289 };
290
291 template<>
292 inline int digits<mpfr_class>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(mpfr_class))
293 {
294 return mpfr_class::get_dprec();
295 }
296
297 namespace detail{
298
299 template<class I>
300 void convert_to_long_result(mpfr_class const& r, I& result)
301 {
302 result = 0;
303 I last_result(0);
304 mpfr_class t(r);
305 double term;
306 do
307 {
308 term = real_cast<double>(t);
309 last_result = result;
310 result += static_cast<I>(term);
311 t -= term;
312 }while(result != last_result);
313 }
314
315 }
316
317 template <>
318 inline mpfr_class real_cast<mpfr_class, long long>(long long t)
319 {
320 mpfr_class result;
321 int expon = 0;
322 int sign = 1;
323 if(t < 0)
324 {
325 sign = -1;
326 t = -t;
327 }
328 while(t)
329 {
330 result += ldexp((double)(t & 0xffffL), expon);
331 expon += 32;
332 t >>= 32;
333 }
334 return result * sign;
335 }
336 template <>
337 inline unsigned real_cast<unsigned, mpfr_class>(mpfr_class t)
338 {
339 return t.get_ui();
340 }
341 template <>
342 inline int real_cast<int, mpfr_class>(mpfr_class t)
343 {
344 return t.get_si();
345 }
346 template <>
347 inline double real_cast<double, mpfr_class>(mpfr_class t)
348 {
349 return t.get_d();
350 }
351 template <>
352 inline float real_cast<float, mpfr_class>(mpfr_class t)
353 {
354 return static_cast<float>(t.get_d());
355 }
356 template <>
357 inline long real_cast<long, mpfr_class>(mpfr_class t)
358 {
359 long result;
360 detail::convert_to_long_result(t, result);
361 return result;
362 }
363 template <>
364 inline long long real_cast<long long, mpfr_class>(mpfr_class t)
365 {
366 long long result;
367 detail::convert_to_long_result(t, result);
368 return result;
369 }
370
371 template <>
372 inline mpfr_class max_value<mpfr_class>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(mpfr_class))
373 {
374 static bool has_init = false;
375 static mpfr_class val;
376 if(!has_init)
377 {
378 val = 0.5;
379 mpfr_set_exp(val.__get_mp(), mpfr_get_emax());
380 has_init = true;
381 }
382 return val;
383 }
384
385 template <>
386 inline mpfr_class min_value<mpfr_class>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(mpfr_class))
387 {
388 static bool has_init = false;
389 static mpfr_class val;
390 if(!has_init)
391 {
392 val = 0.5;
393 mpfr_set_exp(val.__get_mp(), mpfr_get_emin());
394 has_init = true;
395 }
396 return val;
397 }
398
399 template <>
400 inline mpfr_class log_max_value<mpfr_class>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(mpfr_class))
401 {
402 static bool has_init = false;
403 static mpfr_class val = max_value<mpfr_class>();
404 if(!has_init)
405 {
406 val = log(val);
407 has_init = true;
408 }
409 return val;
410 }
411
412 template <>
413 inline mpfr_class log_min_value<mpfr_class>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(mpfr_class))
414 {
415 static bool has_init = false;
416 static mpfr_class val = max_value<mpfr_class>();
417 if(!has_init)
418 {
419 val = log(val);
420 has_init = true;
421 }
422 return val;
423 }
424
425 template <>
426 inline mpfr_class epsilon<mpfr_class>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(mpfr_class))
427 {
428 return ldexp(mpfr_class(1), 1-boost::math::policies::digits<mpfr_class, boost::math::policies::policy<> >());
429 }
430
431 } // namespace tools
432
433 namespace policies{
434
435 template <class T, class U, class Policy>
436 struct evaluation<__gmp_expr<T, U>, Policy>
437 {
438 typedef mpfr_class type;
439 };
440
441 }
442
443 template <class Policy>
444 inline mpfr_class skewness(const extreme_value_distribution<mpfr_class, Policy>& /*dist*/)
445 {
446 //
447 // This is 12 * sqrt(6) * zeta(3) / pi^3:
448 // See http://mathworld.wolfram.com/ExtremeValueDistribution.html
449 //
450 return boost::lexical_cast<mpfr_class>("1.1395470994046486574927930193898461120875997958366");
451 }
452
453 template <class Policy>
454 inline mpfr_class skewness(const rayleigh_distribution<mpfr_class, Policy>& /*dist*/)
455 {
456 // using namespace boost::math::constants;
457 return boost::lexical_cast<mpfr_class>("0.63111065781893713819189935154422777984404221106391");
458 // Computed using NTL at 150 bit, about 50 decimal digits.
459 // return 2 * root_pi<RealType>() * pi_minus_three<RealType>() / pow23_four_minus_pi<RealType>();
460 }
461
462 template <class Policy>
463 inline mpfr_class kurtosis(const rayleigh_distribution<mpfr_class, Policy>& /*dist*/)
464 {
465 // using namespace boost::math::constants;
466 return boost::lexical_cast<mpfr_class>("3.2450893006876380628486604106197544154170667057995");
467 // Computed using NTL at 150 bit, about 50 decimal digits.
468 // return 3 - (6 * pi<RealType>() * pi<RealType>() - 24 * pi<RealType>() + 16) /
469 // (four_minus_pi<RealType>() * four_minus_pi<RealType>());
470 }
471
472 template <class Policy>
473 inline mpfr_class kurtosis_excess(const rayleigh_distribution<mpfr_class, Policy>& /*dist*/)
474 {
475 //using namespace boost::math::constants;
476 // Computed using NTL at 150 bit, about 50 decimal digits.
477 return boost::lexical_cast<mpfr_class>("0.2450893006876380628486604106197544154170667057995");
478 // return -(6 * pi<RealType>() * pi<RealType>() - 24 * pi<RealType>() + 16) /
479 // (four_minus_pi<RealType>() * four_minus_pi<RealType>());
480 } // kurtosis
481
482 namespace detail{
483
484 //
485 // Version of Digamma accurate to ~100 decimal digits.
486 //
487 template <class Policy>
488 mpfr_class digamma_imp(mpfr_class x, const mpl::int_<0>* , const Policy& pol)
489 {
490 //
491 // This handles reflection of negative arguments, and all our
492 // empfr_classor handling, then forwards to the T-specific approximation.
493 //
494 BOOST_MATH_STD_USING // ADL of std functions.
495
496 mpfr_class result = 0;
497 //
498 // Check for negative arguments and use reflection:
499 //
500 if(x < 0)
501 {
502 // Reflect:
503 x = 1 - x;
504 // Argument reduction for tan:
505 mpfr_class remainder = x - floor(x);
506 // Shift to negative if > 0.5:
507 if(remainder > 0.5)
508 {
509 remainder -= 1;
510 }
511 //
512 // check for evaluation at a negative pole:
513 //
514 if(remainder == 0)
515 {
516 return policies::raise_pole_error<mpfr_class>("boost::math::digamma<%1%>(%1%)", 0, (1-x), pol);
517 }
518 result = constants::pi<mpfr_class>() / tan(constants::pi<mpfr_class>() * remainder);
519 }
520 result += big_digamma(x);
521 return result;
522 }
523 //
524 // Specialisations of this function provides the initial
525 // starting guess for Halley iteration:
526 //
527 template <class Policy>
528 inline mpfr_class erf_inv_imp(const mpfr_class& p, const mpfr_class& q, const Policy&, const boost::mpl::int_<64>*)
529 {
530 BOOST_MATH_STD_USING // for ADL of std names.
531
532 mpfr_class result = 0;
533
534 if(p <= 0.5)
535 {
536 //
537 // Evaluate inverse erf using the rational approximation:
538 //
539 // x = p(p+10)(Y+R(p))
540 //
541 // Where Y is a constant, and R(p) is optimised for a low
542 // absolute empfr_classor compared to |Y|.
543 //
544 // double: Max empfr_classor found: 2.001849e-18
545 // long double: Max empfr_classor found: 1.017064e-20
546 // Maximum Deviation Found (actual empfr_classor term at infinite precision) 8.030e-21
547 //
548 static const float Y = 0.0891314744949340820313f;
549 static const mpfr_class P[] = {
550 -0.000508781949658280665617,
551 -0.00836874819741736770379,
552 0.0334806625409744615033,
553 -0.0126926147662974029034,
554 -0.0365637971411762664006,
555 0.0219878681111168899165,
556 0.00822687874676915743155,
557 -0.00538772965071242932965
558 };
559 static const mpfr_class Q[] = {
560 1,
561 -0.970005043303290640362,
562 -1.56574558234175846809,
563 1.56221558398423026363,
564 0.662328840472002992063,
565 -0.71228902341542847553,
566 -0.0527396382340099713954,
567 0.0795283687341571680018,
568 -0.00233393759374190016776,
569 0.000886216390456424707504
570 };
571 mpfr_class g = p * (p + 10);
572 mpfr_class r = tools::evaluate_polynomial(P, p) / tools::evaluate_polynomial(Q, p);
573 result = g * Y + g * r;
574 }
575 else if(q >= 0.25)
576 {
577 //
578 // Rational approximation for 0.5 > q >= 0.25
579 //
580 // x = sqrt(-2*log(q)) / (Y + R(q))
581 //
582 // Where Y is a constant, and R(q) is optimised for a low
583 // absolute empfr_classor compared to Y.
584 //
585 // double : Max empfr_classor found: 7.403372e-17
586 // long double : Max empfr_classor found: 6.084616e-20
587 // Maximum Deviation Found (empfr_classor term) 4.811e-20
588 //
589 static const float Y = 2.249481201171875f;
590 static const mpfr_class P[] = {
591 -0.202433508355938759655,
592 0.105264680699391713268,
593 8.37050328343119927838,
594 17.6447298408374015486,
595 -18.8510648058714251895,
596 -44.6382324441786960818,
597 17.445385985570866523,
598 21.1294655448340526258,
599 -3.67192254707729348546
600 };
601 static const mpfr_class Q[] = {
602 1,
603 6.24264124854247537712,
604 3.9713437953343869095,
605 -28.6608180499800029974,
606 -20.1432634680485188801,
607 48.5609213108739935468,
608 10.8268667355460159008,
609 -22.6436933413139721736,
610 1.72114765761200282724
611 };
612 mpfr_class g = sqrt(-2 * log(q));
613 mpfr_class xs = q - 0.25;
614 mpfr_class r = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
615 result = g / (Y + r);
616 }
617 else
618 {
619 //
620 // For q < 0.25 we have a series of rational approximations all
621 // of the general form:
622 //
623 // let: x = sqrt(-log(q))
624 //
625 // Then the result is given by:
626 //
627 // x(Y+R(x-B))
628 //
629 // where Y is a constant, B is the lowest value of x for which
630 // the approximation is valid, and R(x-B) is optimised for a low
631 // absolute empfr_classor compared to Y.
632 //
633 // Note that almost all code will really go through the first
634 // or maybe second approximation. After than we're dealing with very
635 // small input values indeed: 80 and 128 bit long double's go all the
636 // way down to ~ 1e-5000 so the "tail" is rather long...
637 //
638 mpfr_class x = sqrt(-log(q));
639 if(x < 3)
640 {
641 // Max empfr_classor found: 1.089051e-20
642 static const float Y = 0.807220458984375f;
643 static const mpfr_class P[] = {
644 -0.131102781679951906451,
645 -0.163794047193317060787,
646 0.117030156341995252019,
647 0.387079738972604337464,
648 0.337785538912035898924,
649 0.142869534408157156766,
650 0.0290157910005329060432,
651 0.00214558995388805277169,
652 -0.679465575181126350155e-6,
653 0.285225331782217055858e-7,
654 -0.681149956853776992068e-9
655 };
656 static const mpfr_class Q[] = {
657 1,
658 3.46625407242567245975,
659 5.38168345707006855425,
660 4.77846592945843778382,
661 2.59301921623620271374,
662 0.848854343457902036425,
663 0.152264338295331783612,
664 0.01105924229346489121
665 };
666 mpfr_class xs = x - 1.125;
667 mpfr_class R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
668 result = Y * x + R * x;
669 }
670 else if(x < 6)
671 {
672 // Max empfr_classor found: 8.389174e-21
673 static const float Y = 0.93995571136474609375f;
674 static const mpfr_class P[] = {
675 -0.0350353787183177984712,
676 -0.00222426529213447927281,
677 0.0185573306514231072324,
678 0.00950804701325919603619,
679 0.00187123492819559223345,
680 0.000157544617424960554631,
681 0.460469890584317994083e-5,
682 -0.230404776911882601748e-9,
683 0.266339227425782031962e-11
684 };
685 static const mpfr_class Q[] = {
686 1,
687 1.3653349817554063097,
688 0.762059164553623404043,
689 0.220091105764131249824,
690 0.0341589143670947727934,
691 0.00263861676657015992959,
692 0.764675292302794483503e-4
693 };
694 mpfr_class xs = x - 3;
695 mpfr_class R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
696 result = Y * x + R * x;
697 }
698 else if(x < 18)
699 {
700 // Max empfr_classor found: 1.481312e-19
701 static const float Y = 0.98362827301025390625f;
702 static const mpfr_class P[] = {
703 -0.0167431005076633737133,
704 -0.00112951438745580278863,
705 0.00105628862152492910091,
706 0.000209386317487588078668,
707 0.149624783758342370182e-4,
708 0.449696789927706453732e-6,
709 0.462596163522878599135e-8,
710 -0.281128735628831791805e-13,
711 0.99055709973310326855e-16
712 };
713 static const mpfr_class Q[] = {
714 1,
715 0.591429344886417493481,
716 0.138151865749083321638,
717 0.0160746087093676504695,
718 0.000964011807005165528527,
719 0.275335474764726041141e-4,
720 0.282243172016108031869e-6
721 };
722 mpfr_class xs = x - 6;
723 mpfr_class R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
724 result = Y * x + R * x;
725 }
726 else if(x < 44)
727 {
728 // Max empfr_classor found: 5.697761e-20
729 static const float Y = 0.99714565277099609375f;
730 static const mpfr_class P[] = {
731 -0.0024978212791898131227,
732 -0.779190719229053954292e-5,
733 0.254723037413027451751e-4,
734 0.162397777342510920873e-5,
735 0.396341011304801168516e-7,
736 0.411632831190944208473e-9,
737 0.145596286718675035587e-11,
738 -0.116765012397184275695e-17
739 };
740 static const mpfr_class Q[] = {
741 1,
742 0.207123112214422517181,
743 0.0169410838120975906478,
744 0.000690538265622684595676,
745 0.145007359818232637924e-4,
746 0.144437756628144157666e-6,
747 0.509761276599778486139e-9
748 };
749 mpfr_class xs = x - 18;
750 mpfr_class R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
751 result = Y * x + R * x;
752 }
753 else
754 {
755 // Max empfr_classor found: 1.279746e-20
756 static const float Y = 0.99941349029541015625f;
757 static const mpfr_class P[] = {
758 -0.000539042911019078575891,
759 -0.28398759004727721098e-6,
760 0.899465114892291446442e-6,
761 0.229345859265920864296e-7,
762 0.225561444863500149219e-9,
763 0.947846627503022684216e-12,
764 0.135880130108924861008e-14,
765 -0.348890393399948882918e-21
766 };
767 static const mpfr_class Q[] = {
768 1,
769 0.0845746234001899436914,
770 0.00282092984726264681981,
771 0.468292921940894236786e-4,
772 0.399968812193862100054e-6,
773 0.161809290887904476097e-8,
774 0.231558608310259605225e-11
775 };
776 mpfr_class xs = x - 44;
777 mpfr_class R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
778 result = Y * x + R * x;
779 }
780 }
781 return result;
782 }
783
784 inline mpfr_class bessel_i0(mpfr_class x)
785 {
786 static const mpfr_class P1[] = {
787 boost::lexical_cast<mpfr_class>("-2.2335582639474375249e+15"),
788 boost::lexical_cast<mpfr_class>("-5.5050369673018427753e+14"),
789 boost::lexical_cast<mpfr_class>("-3.2940087627407749166e+13"),
790 boost::lexical_cast<mpfr_class>("-8.4925101247114157499e+11"),
791 boost::lexical_cast<mpfr_class>("-1.1912746104985237192e+10"),
792 boost::lexical_cast<mpfr_class>("-1.0313066708737980747e+08"),
793 boost::lexical_cast<mpfr_class>("-5.9545626019847898221e+05"),
794 boost::lexical_cast<mpfr_class>("-2.4125195876041896775e+03"),
795 boost::lexical_cast<mpfr_class>("-7.0935347449210549190e+00"),
796 boost::lexical_cast<mpfr_class>("-1.5453977791786851041e-02"),
797 boost::lexical_cast<mpfr_class>("-2.5172644670688975051e-05"),
798 boost::lexical_cast<mpfr_class>("-3.0517226450451067446e-08"),
799 boost::lexical_cast<mpfr_class>("-2.6843448573468483278e-11"),
800 boost::lexical_cast<mpfr_class>("-1.5982226675653184646e-14"),
801 boost::lexical_cast<mpfr_class>("-5.2487866627945699800e-18"),
802 };
803 static const mpfr_class Q1[] = {
804 boost::lexical_cast<mpfr_class>("-2.2335582639474375245e+15"),
805 boost::lexical_cast<mpfr_class>("7.8858692566751002988e+12"),
806 boost::lexical_cast<mpfr_class>("-1.2207067397808979846e+10"),
807 boost::lexical_cast<mpfr_class>("1.0377081058062166144e+07"),
808 boost::lexical_cast<mpfr_class>("-4.8527560179962773045e+03"),
809 boost::lexical_cast<mpfr_class>("1.0"),
810 };
811 static const mpfr_class P2[] = {
812 boost::lexical_cast<mpfr_class>("-2.2210262233306573296e-04"),
813 boost::lexical_cast<mpfr_class>("1.3067392038106924055e-02"),
814 boost::lexical_cast<mpfr_class>("-4.4700805721174453923e-01"),
815 boost::lexical_cast<mpfr_class>("5.5674518371240761397e+00"),
816 boost::lexical_cast<mpfr_class>("-2.3517945679239481621e+01"),
817 boost::lexical_cast<mpfr_class>("3.1611322818701131207e+01"),
818 boost::lexical_cast<mpfr_class>("-9.6090021968656180000e+00"),
819 };
820 static const mpfr_class Q2[] = {
821 boost::lexical_cast<mpfr_class>("-5.5194330231005480228e-04"),
822 boost::lexical_cast<mpfr_class>("3.2547697594819615062e-02"),
823 boost::lexical_cast<mpfr_class>("-1.1151759188741312645e+00"),
824 boost::lexical_cast<mpfr_class>("1.3982595353892851542e+01"),
825 boost::lexical_cast<mpfr_class>("-6.0228002066743340583e+01"),
826 boost::lexical_cast<mpfr_class>("8.5539563258012929600e+01"),
827 boost::lexical_cast<mpfr_class>("-3.1446690275135491500e+01"),
828 boost::lexical_cast<mpfr_class>("1.0"),
829 };
830 mpfr_class value, factor, r;
831
832 BOOST_MATH_STD_USING
833 using namespace boost::math::tools;
834
835 if (x < 0)
836 {
837 x = -x; // even function
838 }
839 if (x == 0)
840 {
841 return static_cast<mpfr_class>(1);
842 }
843 if (x <= 15) // x in (0, 15]
844 {
845 mpfr_class y = x * x;
846 value = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
847 }
848 else // x in (15, \infty)
849 {
850 mpfr_class y = 1 / x - mpfr_class(1) / 15;
851 r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
852 factor = exp(x) / sqrt(x);
853 value = factor * r;
854 }
855
856 return value;
857 }
858
859 inline mpfr_class bessel_i1(mpfr_class x)
860 {
861 static const mpfr_class P1[] = {
862 static_cast<mpfr_class>("-1.4577180278143463643e+15"),
863 static_cast<mpfr_class>("-1.7732037840791591320e+14"),
864 static_cast<mpfr_class>("-6.9876779648010090070e+12"),
865 static_cast<mpfr_class>("-1.3357437682275493024e+11"),
866 static_cast<mpfr_class>("-1.4828267606612366099e+09"),
867 static_cast<mpfr_class>("-1.0588550724769347106e+07"),
868 static_cast<mpfr_class>("-5.1894091982308017540e+04"),
869 static_cast<mpfr_class>("-1.8225946631657315931e+02"),
870 static_cast<mpfr_class>("-4.7207090827310162436e-01"),
871 static_cast<mpfr_class>("-9.1746443287817501309e-04"),
872 static_cast<mpfr_class>("-1.3466829827635152875e-06"),
873 static_cast<mpfr_class>("-1.4831904935994647675e-09"),
874 static_cast<mpfr_class>("-1.1928788903603238754e-12"),
875 static_cast<mpfr_class>("-6.5245515583151902910e-16"),
876 static_cast<mpfr_class>("-1.9705291802535139930e-19"),
877 };
878 static const mpfr_class Q1[] = {
879 static_cast<mpfr_class>("-2.9154360556286927285e+15"),
880 static_cast<mpfr_class>("9.7887501377547640438e+12"),
881 static_cast<mpfr_class>("-1.4386907088588283434e+10"),
882 static_cast<mpfr_class>("1.1594225856856884006e+07"),
883 static_cast<mpfr_class>("-5.1326864679904189920e+03"),
884 static_cast<mpfr_class>("1.0"),
885 };
886 static const mpfr_class P2[] = {
887 static_cast<mpfr_class>("1.4582087408985668208e-05"),
888 static_cast<mpfr_class>("-8.9359825138577646443e-04"),
889 static_cast<mpfr_class>("2.9204895411257790122e-02"),
890 static_cast<mpfr_class>("-3.4198728018058047439e-01"),
891 static_cast<mpfr_class>("1.3960118277609544334e+00"),
892 static_cast<mpfr_class>("-1.9746376087200685843e+00"),
893 static_cast<mpfr_class>("8.5591872901933459000e-01"),
894 static_cast<mpfr_class>("-6.0437159056137599999e-02"),
895 };
896 static const mpfr_class Q2[] = {
897 static_cast<mpfr_class>("3.7510433111922824643e-05"),
898 static_cast<mpfr_class>("-2.2835624489492512649e-03"),
899 static_cast<mpfr_class>("7.4212010813186530069e-02"),
900 static_cast<mpfr_class>("-8.5017476463217924408e-01"),
901 static_cast<mpfr_class>("3.2593714889036996297e+00"),
902 static_cast<mpfr_class>("-3.8806586721556593450e+00"),
903 static_cast<mpfr_class>("1.0"),
904 };
905 mpfr_class value, factor, r, w;
906
907 BOOST_MATH_STD_USING
908 using namespace boost::math::tools;
909
910 w = abs(x);
911 if (x == 0)
912 {
913 return static_cast<mpfr_class>(0);
914 }
915 if (w <= 15) // w in (0, 15]
916 {
917 mpfr_class y = x * x;
918 r = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
919 factor = w;
920 value = factor * r;
921 }
922 else // w in (15, \infty)
923 {
924 mpfr_class y = 1 / w - mpfr_class(1) / 15;
925 r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
926 factor = exp(w) / sqrt(w);
927 value = factor * r;
928 }
929
930 if (x < 0)
931 {
932 value *= -value; // odd function
933 }
934 return value;
935 }
936
937 } // namespace detail
938
939 }
940
941 template<> struct is_convertible<long double, mpfr_class> : public mpl::false_{};
942
943 }
944
945 #endif // BOOST_MATH_MPLFR_BINDINGS_HPP
946