mpreal.hpp 29 KB

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