hypergeometric_pFq_checked_series.hpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2018 John Maddock
  3. // Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_HYPERGEOMETRIC_PFQ_SERIES_HPP_
  7. #define BOOST_HYPERGEOMETRIC_PFQ_SERIES_HPP_
  8. #ifndef BOOST_MATH_PFQ_MAX_B_TERMS
  9. # define BOOST_MATH_PFQ_MAX_B_TERMS 5
  10. #endif
  11. #include <array>
  12. #include <cstdint>
  13. #include <boost/math/special_functions/gamma.hpp>
  14. #include <boost/math/special_functions/expm1.hpp>
  15. #include <boost/math/special_functions/detail/hypergeometric_series.hpp>
  16. namespace boost { namespace math { namespace detail {
  17. template <class Seq, class Real>
  18. unsigned set_crossover_locations(const Seq& aj, const Seq& bj, const Real& z, unsigned int* crossover_locations)
  19. {
  20. BOOST_MATH_STD_USING
  21. unsigned N_terms = 0;
  22. if(aj.size() == 1 && bj.size() == 1)
  23. {
  24. //
  25. // For 1F1 we can work out where the peaks in the series occur,
  26. // which is to say when:
  27. //
  28. // (a + k)z / (k(b + k)) == +-1
  29. //
  30. // Then we are at either a maxima or a minima in the series, and the
  31. // last such point must be a maxima since the series is globally convergent.
  32. // Potentially then we are solving 2 quadratic equations and have up to 4
  33. // solutions, any solutions which are complex or negative are discarded,
  34. // leaving us with 4 options:
  35. //
  36. // 0 solutions: The series is directly convergent.
  37. // 1 solution : The series diverges to a maxima before converging.
  38. // 2 solutions: The series is initially convergent, followed by divergence to a maxima before final convergence.
  39. // 3 solutions: The series diverges to a maxima, converges to a minima before diverging again to a second maxima before final convergence.
  40. // 4 solutions: The series converges to a minima before diverging to a maxima, converging to a minima, diverging to a second maxima and then converging.
  41. //
  42. // The first 2 situations are adequately handled by direct series evaluation, while the 2,3 and 4 solutions are not.
  43. //
  44. Real a = *aj.begin();
  45. Real b = *bj.begin();
  46. Real sq = 4 * a * z + b * b - 2 * b * z + z * z;
  47. if (sq >= 0)
  48. {
  49. Real t = (-sqrt(sq) - b + z) / 2;
  50. if (t >= 0)
  51. {
  52. crossover_locations[N_terms] = itrunc(t);
  53. ++N_terms;
  54. }
  55. t = (sqrt(sq) - b + z) / 2;
  56. if (t >= 0)
  57. {
  58. crossover_locations[N_terms] = itrunc(t);
  59. ++N_terms;
  60. }
  61. }
  62. sq = -4 * a * z + b * b + 2 * b * z + z * z;
  63. if (sq >= 0)
  64. {
  65. Real t = (-sqrt(sq) - b - z) / 2;
  66. if (t >= 0)
  67. {
  68. crossover_locations[N_terms] = itrunc(t);
  69. ++N_terms;
  70. }
  71. t = (sqrt(sq) - b - z) / 2;
  72. if (t >= 0)
  73. {
  74. crossover_locations[N_terms] = itrunc(t);
  75. ++N_terms;
  76. }
  77. }
  78. std::sort(crossover_locations, crossover_locations + N_terms, std::less<Real>());
  79. //
  80. // Now we need to discard every other terms, as these are the minima:
  81. //
  82. switch (N_terms)
  83. {
  84. case 0:
  85. case 1:
  86. break;
  87. case 2:
  88. crossover_locations[0] = crossover_locations[1];
  89. --N_terms;
  90. break;
  91. case 3:
  92. crossover_locations[1] = crossover_locations[2];
  93. --N_terms;
  94. break;
  95. case 4:
  96. crossover_locations[0] = crossover_locations[1];
  97. crossover_locations[1] = crossover_locations[3];
  98. N_terms -= 2;
  99. break;
  100. }
  101. }
  102. else
  103. {
  104. unsigned n = 0;
  105. for (auto bi = bj.begin(); bi != bj.end(); ++bi, ++n)
  106. {
  107. crossover_locations[n] = *bi >= 0 ? 0 : itrunc(-*bi) + 1;
  108. }
  109. std::sort(crossover_locations, crossover_locations + bj.size(), std::less<Real>());
  110. N_terms = (unsigned)bj.size();
  111. }
  112. return N_terms;
  113. }
  114. template <class Seq, class Real, class Policy, class Terminal>
  115. std::pair<Real, Real> hypergeometric_pFq_checked_series_impl(const Seq& aj, const Seq& bj, const Real& z, const Policy& pol, const Terminal& termination, long long& log_scale)
  116. {
  117. BOOST_MATH_STD_USING
  118. Real result = 1;
  119. Real abs_result = 1;
  120. Real term = 1;
  121. Real term0 = 0;
  122. Real tol = boost::math::policies::get_epsilon<Real, Policy>();
  123. std::uintmax_t k = 0;
  124. Real upper_limit(sqrt(boost::math::tools::max_value<Real>())), diff;
  125. Real lower_limit(1 / upper_limit);
  126. long long log_scaling_factor = lltrunc(boost::math::tools::log_max_value<Real>()) - 2;
  127. Real scaling_factor = exp(Real(log_scaling_factor));
  128. Real term_m1;
  129. long long local_scaling = 0;
  130. bool have_no_correct_bits = false;
  131. if ((aj.size() == 1) && (bj.size() == 0))
  132. {
  133. if (fabs(z) > 1)
  134. {
  135. if ((z > 0) && (floor(*aj.begin()) != *aj.begin()))
  136. {
  137. Real r = policies::raise_domain_error("boost::math::hypergeometric_pFq", "Got p == 1 and q == 0 and |z| > 1, result is imaginary", z, pol);
  138. return std::make_pair(r, r);
  139. }
  140. std::pair<Real, Real> r = hypergeometric_pFq_checked_series_impl(aj, bj, Real(1 / z), pol, termination, log_scale);
  141. #if (defined(__GNUC__) && __GNUC__ == 13)
  142. Real mul = pow(-z, Real(-*aj.begin()));
  143. #else
  144. Real mul = pow(-z, -*aj.begin());
  145. #endif
  146. r.first *= mul;
  147. r.second *= mul;
  148. return r;
  149. }
  150. }
  151. if (aj.size() > bj.size())
  152. {
  153. if (aj.size() == bj.size() + 1)
  154. {
  155. if (fabs(z) > 1)
  156. {
  157. Real r = policies::raise_domain_error("boost::math::hypergeometric_pFq", "Got p == q+1 and |z| > 1, series does not converge", z, pol);
  158. return std::make_pair(r, r);
  159. }
  160. if (fabs(z) == 1)
  161. {
  162. Real s = 0;
  163. for (auto i = bj.begin(); i != bj.end(); ++i)
  164. s += *i;
  165. for (auto i = aj.begin(); i != aj.end(); ++i)
  166. s -= *i;
  167. if ((z == 1) && (s <= 0))
  168. {
  169. Real r = policies::raise_domain_error("boost::math::hypergeometric_pFq", "Got p == q+1 and |z| == 1, in a situation where the series does not converge", z, pol);
  170. return std::make_pair(r, r);
  171. }
  172. if ((z == -1) && (s <= -1))
  173. {
  174. Real r = policies::raise_domain_error("boost::math::hypergeometric_pFq", "Got p == q+1 and |z| == 1, in a situation where the series does not converge", z, pol);
  175. return std::make_pair(r, r);
  176. }
  177. }
  178. }
  179. else
  180. {
  181. Real r = policies::raise_domain_error("boost::math::hypergeometric_pFq", "Got p > q+1, series does not converge", z, pol);
  182. return std::make_pair(r, r);
  183. }
  184. }
  185. while (!termination(k))
  186. {
  187. for (auto ai = aj.begin(); ai != aj.end(); ++ai)
  188. {
  189. term *= *ai + k;
  190. }
  191. if (term == 0)
  192. {
  193. // There is a negative integer in the aj's:
  194. return std::make_pair(result, abs_result);
  195. }
  196. for (auto bi = bj.begin(); bi != bj.end(); ++bi)
  197. {
  198. if (*bi + k == 0)
  199. {
  200. // The series is undefined:
  201. result = boost::math::policies::raise_domain_error("boost::math::hypergeometric_pFq<%1%>", "One of the b values was the negative integer %1%", *bi, pol);
  202. return std::make_pair(result, result);
  203. }
  204. term /= *bi + k;
  205. }
  206. term *= z;
  207. ++k;
  208. term /= k;
  209. //std::cout << k << " " << *bj.begin() + k << " " << result << " " << term << /*" " << term_at_k(*aj.begin(), *bj.begin(), z, k, pol) <<*/ std::endl;
  210. result += term;
  211. abs_result += abs(term);
  212. //std::cout << "k = " << k << " term = " << term * exp(log_scale) << " result = " << result * exp(log_scale) << " abs_result = " << abs_result * exp(log_scale) << std::endl;
  213. //
  214. // Rescaling:
  215. //
  216. if (fabs(abs_result) >= upper_limit)
  217. {
  218. abs_result /= scaling_factor;
  219. result /= scaling_factor;
  220. term /= scaling_factor;
  221. log_scale += log_scaling_factor;
  222. local_scaling += log_scaling_factor;
  223. }
  224. if (fabs(abs_result) < lower_limit)
  225. {
  226. abs_result *= scaling_factor;
  227. result *= scaling_factor;
  228. term *= scaling_factor;
  229. log_scale -= log_scaling_factor;
  230. local_scaling -= log_scaling_factor;
  231. }
  232. if ((abs(result * tol) > abs(term)) && (abs(term0) > abs(term)))
  233. break;
  234. if (abs_result * tol > abs(result))
  235. {
  236. // Check if result is so small compared to abs_resuslt that there are no longer any
  237. // correct bits... we require two consecutive passes here before aborting to
  238. // avoid false positives when result transiently drops to near zero then rebounds.
  239. if (have_no_correct_bits)
  240. {
  241. // We have no correct bits in the result... just give up!
  242. result = boost::math::policies::raise_evaluation_error("boost::math::hypergeometric_pFq<%1%>", "Cancellation is so severe that no bits in the result are correct, last result was %1%", Real(result * exp(Real(log_scale))), pol);
  243. return std::make_pair(result, result);
  244. }
  245. else
  246. have_no_correct_bits = true;
  247. }
  248. else
  249. have_no_correct_bits = false;
  250. term0 = term;
  251. }
  252. //std::cout << "result = " << result << std::endl;
  253. //std::cout << "local_scaling = " << local_scaling << std::endl;
  254. //std::cout << "Norm result = " << std::setprecision(35) << boost::multiprecision::mpfr_float_50(result) * exp(boost::multiprecision::mpfr_float_50(local_scaling)) << std::endl;
  255. //
  256. // We have to be careful when one of the b's crosses the origin:
  257. //
  258. if(bj.size() > BOOST_MATH_PFQ_MAX_B_TERMS)
  259. policies::raise_domain_error<Real>("boost::math::hypergeometric_pFq<%1%>(Seq, Seq, %1%)",
  260. "The number of b terms must be less than the value of BOOST_MATH_PFQ_MAX_B_TERMS (" BOOST_MATH_STRINGIZE(BOOST_MATH_PFQ_MAX_B_TERMS) "), but got %1%.",
  261. Real(bj.size()), pol);
  262. unsigned crossover_locations[BOOST_MATH_PFQ_MAX_B_TERMS];
  263. unsigned N_crossovers = set_crossover_locations(aj, bj, z, crossover_locations);
  264. bool terminate = false; // Set to true if one of the a's passes through the origin and terminates the series.
  265. for (unsigned n = 0; n < N_crossovers; ++n)
  266. {
  267. if (k < crossover_locations[n])
  268. {
  269. for (auto ai = aj.begin(); ai != aj.end(); ++ai)
  270. {
  271. if ((*ai < 0) && (floor(*ai) == *ai) && (*ai > static_cast<decltype(*ai)>(crossover_locations[n])))
  272. return std::make_pair(result, abs_result); // b's will never cross the origin!
  273. }
  274. //
  275. // local results:
  276. //
  277. Real loop_result = 0;
  278. Real loop_abs_result = 0;
  279. long long loop_scale = 0;
  280. //
  281. // loop_error_scale will be used to increase the size of the error
  282. // estimate (absolute sum), based on the errors inherent in calculating
  283. // the pochhammer symbols.
  284. //
  285. Real loop_error_scale = 0;
  286. //boost::multiprecision::mpfi_float err_est = 0;
  287. //
  288. // b hasn't crossed the origin yet and the series may spring back into life at that point
  289. // so we need to jump forward to that term and then evaluate forwards and backwards from there:
  290. //
  291. unsigned s = crossover_locations[n];
  292. std::uintmax_t backstop = k;
  293. long long s1(1), s2(1);
  294. term = 0;
  295. for (auto ai = aj.begin(); ai != aj.end(); ++ai)
  296. {
  297. if ((floor(*ai) == *ai) && (*ai < 0) && (-*ai <= static_cast<decltype(*ai)>(s)))
  298. {
  299. // One of the a terms has passed through zero and terminated the series:
  300. terminate = true;
  301. break;
  302. }
  303. else
  304. {
  305. int ls = 1;
  306. Real p = log_pochhammer(*ai, s, pol, &ls);
  307. s1 *= ls;
  308. term += p;
  309. loop_error_scale = (std::max)(p, loop_error_scale);
  310. //err_est += boost::multiprecision::mpfi_float(p);
  311. }
  312. }
  313. //std::cout << "term = " << term << std::endl;
  314. if (terminate)
  315. break;
  316. for (auto bi = bj.begin(); bi != bj.end(); ++bi)
  317. {
  318. int ls = 1;
  319. Real p = log_pochhammer(*bi, s, pol, &ls);
  320. s2 *= ls;
  321. term -= p;
  322. loop_error_scale = (std::max)(p, loop_error_scale);
  323. //err_est -= boost::multiprecision::mpfi_float(p);
  324. }
  325. //std::cout << "term = " << term << std::endl;
  326. Real p = lgamma(Real(s + 1), pol);
  327. term -= p;
  328. loop_error_scale = (std::max)(p, loop_error_scale);
  329. //err_est -= boost::multiprecision::mpfi_float(p);
  330. p = s * log(fabs(z));
  331. term += p;
  332. loop_error_scale = (std::max)(p, loop_error_scale);
  333. //err_est += boost::multiprecision::mpfi_float(p);
  334. //err_est = exp(err_est);
  335. //std::cout << err_est << std::endl;
  336. //
  337. // Convert loop_error scale to the absolute error
  338. // in term after exp is applied:
  339. //
  340. loop_error_scale *= tools::epsilon<Real>();
  341. //
  342. // Convert to relative error after exp:
  343. //
  344. loop_error_scale = fabs(expm1(loop_error_scale, pol));
  345. //
  346. // Convert to multiplier for the error term:
  347. //
  348. loop_error_scale /= tools::epsilon<Real>();
  349. if (z < 0)
  350. s1 *= (s & 1 ? -1 : 1);
  351. if (term <= tools::log_min_value<Real>())
  352. {
  353. // rescale if we can:
  354. long long scale = lltrunc(floor(term - tools::log_min_value<Real>()) - 2);
  355. term -= scale;
  356. loop_scale += scale;
  357. }
  358. if (term > 10)
  359. {
  360. int scale = itrunc(floor(term));
  361. term -= scale;
  362. loop_scale += scale;
  363. }
  364. //std::cout << "term = " << term << std::endl;
  365. term = s1 * s2 * exp(term);
  366. //std::cout << "term = " << term << std::endl;
  367. //std::cout << "loop_scale = " << loop_scale << std::endl;
  368. k = s;
  369. term0 = term;
  370. long long saved_loop_scale = loop_scale;
  371. bool terms_are_growing = true;
  372. bool trivial_small_series_check = false;
  373. do
  374. {
  375. loop_result += term;
  376. loop_abs_result += fabs(term);
  377. //std::cout << "k = " << k << " term = " << term * exp(loop_scale) << " result = " << loop_result * exp(loop_scale) << " abs_result = " << loop_abs_result * exp(loop_scale) << std::endl;
  378. if (fabs(loop_result) >= upper_limit)
  379. {
  380. loop_result /= scaling_factor;
  381. loop_abs_result /= scaling_factor;
  382. term /= scaling_factor;
  383. loop_scale += log_scaling_factor;
  384. }
  385. if (fabs(loop_result) < lower_limit)
  386. {
  387. loop_result *= scaling_factor;
  388. loop_abs_result *= scaling_factor;
  389. term *= scaling_factor;
  390. loop_scale -= log_scaling_factor;
  391. }
  392. term_m1 = term;
  393. for (auto ai = aj.begin(); ai != aj.end(); ++ai)
  394. {
  395. term *= *ai + k;
  396. }
  397. if (term == 0)
  398. {
  399. // There is a negative integer in the aj's:
  400. return std::make_pair(result, abs_result);
  401. }
  402. for (auto bi = bj.begin(); bi != bj.end(); ++bi)
  403. {
  404. if (*bi + k == 0)
  405. {
  406. // The series is undefined:
  407. result = boost::math::policies::raise_domain_error("boost::math::hypergeometric_pFq<%1%>", "One of the b values was the negative integer %1%", *bi, pol);
  408. return std::make_pair(result, result);
  409. }
  410. term /= *bi + k;
  411. }
  412. term *= z / (k + 1);
  413. ++k;
  414. diff = fabs(term / loop_result);
  415. terms_are_growing = fabs(term) > fabs(term_m1);
  416. if (!trivial_small_series_check && !terms_are_growing)
  417. {
  418. //
  419. // Now that we have started to converge, check to see if the value of
  420. // this local sum is trivially small compared to the result. If so
  421. // abort this part of the series.
  422. //
  423. trivial_small_series_check = true;
  424. Real d;
  425. if (loop_scale > local_scaling)
  426. {
  427. long long rescale = local_scaling - loop_scale;
  428. if (rescale < tools::log_min_value<Real>())
  429. d = 1; // arbitrary value, we want to keep going
  430. else
  431. d = fabs(term / (result * exp(Real(rescale))));
  432. }
  433. else
  434. {
  435. long long rescale = loop_scale - local_scaling;
  436. if (rescale < tools::log_min_value<Real>())
  437. d = 0; // terminate this loop
  438. else
  439. d = fabs(term * exp(Real(rescale)) / result);
  440. }
  441. if (d < boost::math::policies::get_epsilon<Real, Policy>())
  442. break;
  443. }
  444. } while (!termination(k - s) && ((diff > boost::math::policies::get_epsilon<Real, Policy>()) || terms_are_growing));
  445. //std::cout << "Norm loop result = " << std::setprecision(35) << boost::multiprecision::mpfr_float_50(loop_result)* exp(boost::multiprecision::mpfr_float_50(loop_scale)) << std::endl;
  446. //
  447. // We now need to combine the results of the first series summation with whatever
  448. // local results we have now. First though, rescale abs_result by loop_error_scale
  449. // to factor in the error in the pochhammer terms at the start of this block:
  450. //
  451. std::uintmax_t next_backstop = k;
  452. loop_abs_result += loop_error_scale * fabs(loop_result);
  453. if (loop_scale > local_scaling)
  454. {
  455. //
  456. // Need to shrink previous result:
  457. //
  458. long long rescale = local_scaling - loop_scale;
  459. local_scaling = loop_scale;
  460. log_scale -= rescale;
  461. Real ex = exp(Real(rescale));
  462. result *= ex;
  463. abs_result *= ex;
  464. result += loop_result;
  465. abs_result += loop_abs_result;
  466. }
  467. else if (local_scaling > loop_scale)
  468. {
  469. //
  470. // Need to shrink local result:
  471. //
  472. long long rescale = loop_scale - local_scaling;
  473. Real ex = exp(Real(rescale));
  474. loop_result *= ex;
  475. loop_abs_result *= ex;
  476. result += loop_result;
  477. abs_result += loop_abs_result;
  478. }
  479. else
  480. {
  481. result += loop_result;
  482. abs_result += loop_abs_result;
  483. }
  484. //
  485. // Now go backwards as well:
  486. //
  487. k = s;
  488. term = term0;
  489. loop_result = 0;
  490. loop_abs_result = 0;
  491. loop_scale = saved_loop_scale;
  492. trivial_small_series_check = false;
  493. do
  494. {
  495. --k;
  496. if (k == backstop)
  497. break;
  498. term_m1 = term;
  499. for (auto ai = aj.begin(); ai != aj.end(); ++ai)
  500. {
  501. term /= *ai + k;
  502. }
  503. for (auto bi = bj.begin(); bi != bj.end(); ++bi)
  504. {
  505. if (*bi + k == 0)
  506. {
  507. // The series is undefined:
  508. result = boost::math::policies::raise_domain_error("boost::math::hypergeometric_pFq<%1%>", "One of the b values was the negative integer %1%", *bi, pol);
  509. return std::make_pair(result, result);
  510. }
  511. term *= *bi + k;
  512. }
  513. term *= (k + 1) / z;
  514. loop_result += term;
  515. loop_abs_result += fabs(term);
  516. if (!trivial_small_series_check && (fabs(term) < fabs(term_m1)))
  517. {
  518. //
  519. // Now that we have started to converge, check to see if the value of
  520. // this local sum is trivially small compared to the result. If so
  521. // abort this part of the series.
  522. //
  523. trivial_small_series_check = true;
  524. Real d;
  525. if (loop_scale > local_scaling)
  526. {
  527. long long rescale = local_scaling - loop_scale;
  528. if (rescale < tools::log_min_value<Real>())
  529. d = 1; // keep going
  530. else
  531. d = fabs(term / (result * exp(Real(rescale))));
  532. }
  533. else
  534. {
  535. long long rescale = loop_scale - local_scaling;
  536. if (rescale < tools::log_min_value<Real>())
  537. d = 0; // stop, underflow
  538. else
  539. d = fabs(term * exp(Real(rescale)) / result);
  540. }
  541. if (d < boost::math::policies::get_epsilon<Real, Policy>())
  542. break;
  543. }
  544. //std::cout << "k = " << k << " result = " << result << " abs_result = " << abs_result << std::endl;
  545. if (fabs(loop_result) >= upper_limit)
  546. {
  547. loop_result /= scaling_factor;
  548. loop_abs_result /= scaling_factor;
  549. term /= scaling_factor;
  550. loop_scale += log_scaling_factor;
  551. }
  552. if (fabs(loop_result) < lower_limit)
  553. {
  554. loop_result *= scaling_factor;
  555. loop_abs_result *= scaling_factor;
  556. term *= scaling_factor;
  557. loop_scale -= log_scaling_factor;
  558. }
  559. diff = fabs(term / loop_result);
  560. } while (!termination(s - k) && ((diff > boost::math::policies::get_epsilon<Real, Policy>()) || (fabs(term) > fabs(term_m1))));
  561. //std::cout << "Norm loop result = " << std::setprecision(35) << boost::multiprecision::mpfr_float_50(loop_result)* exp(boost::multiprecision::mpfr_float_50(loop_scale)) << std::endl;
  562. //
  563. // We now need to combine the results of the first series summation with whatever
  564. // local results we have now. First though, rescale abs_result by loop_error_scale
  565. // to factor in the error in the pochhammer terms at the start of this block:
  566. //
  567. loop_abs_result += loop_error_scale * fabs(loop_result);
  568. //
  569. if (loop_scale > local_scaling)
  570. {
  571. //
  572. // Need to shrink previous result:
  573. //
  574. long long rescale = local_scaling - loop_scale;
  575. local_scaling = loop_scale;
  576. log_scale -= rescale;
  577. Real ex = exp(Real(rescale));
  578. result *= ex;
  579. abs_result *= ex;
  580. result += loop_result;
  581. abs_result += loop_abs_result;
  582. }
  583. else if (local_scaling > loop_scale)
  584. {
  585. //
  586. // Need to shrink local result:
  587. //
  588. long long rescale = loop_scale - local_scaling;
  589. Real ex = exp(Real(rescale));
  590. loop_result *= ex;
  591. loop_abs_result *= ex;
  592. result += loop_result;
  593. abs_result += loop_abs_result;
  594. }
  595. else
  596. {
  597. result += loop_result;
  598. abs_result += loop_abs_result;
  599. }
  600. //
  601. // Reset k to the largest k we reached
  602. //
  603. k = next_backstop;
  604. }
  605. }
  606. return std::make_pair(result, abs_result);
  607. }
  608. struct iteration_terminator
  609. {
  610. iteration_terminator(std::uintmax_t i) : m(i) {}
  611. bool operator()(std::uintmax_t v) const { return v >= m; }
  612. std::uintmax_t m;
  613. };
  614. template <class Seq, class Real, class Policy>
  615. Real hypergeometric_pFq_checked_series_impl(const Seq& aj, const Seq& bj, const Real& z, const Policy& pol, long long& log_scale)
  616. {
  617. BOOST_MATH_STD_USING
  618. iteration_terminator term(boost::math::policies::get_max_series_iterations<Policy>());
  619. std::pair<Real, Real> result = hypergeometric_pFq_checked_series_impl(aj, bj, z, pol, term, log_scale);
  620. //
  621. // Check to see how many digits we've lost, if it's more than half, raise an evaluation error -
  622. // this is an entirely arbitrary cut off, but not unreasonable.
  623. //
  624. if (result.second * sqrt(boost::math::policies::get_epsilon<Real, Policy>()) > abs(result.first))
  625. {
  626. return boost::math::policies::raise_evaluation_error("boost::math::hypergeometric_pFq<%1%>", "Cancellation is so severe that fewer than half the bits in the result are correct, last result was %1%", Real(result.first * exp(Real(log_scale))), pol);
  627. }
  628. return result.first;
  629. }
  630. template <class Real, class Policy>
  631. inline Real hypergeometric_1F1_checked_series_impl(const Real& a, const Real& b, const Real& z, const Policy& pol, long long& log_scale)
  632. {
  633. std::array<Real, 1> aj = { a };
  634. std::array<Real, 1> bj = { b };
  635. return hypergeometric_pFq_checked_series_impl(aj, bj, z, pol, log_scale);
  636. }
  637. } } } // namespaces
  638. #endif // BOOST_HYPERGEOMETRIC_PFQ_SERIES_HPP_