mpreal.hpp 30 KB

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