mpreal.hpp 29 KB

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