hypergeometric_luke_algorithms.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright Christopher Kormanyos 2013 - 2014.
  3. // Copyright John Maddock 2013.
  4. // Distributed under the Boost Software License,
  5. // Version 1.0. (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // This work is based on an earlier work:
  9. // "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
  10. // in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
  11. //
  12. #include <algorithm>
  13. #include <cstdint>
  14. #include <deque>
  15. #include <functional>
  16. #include <iostream>
  17. #include <limits>
  18. #include <numeric>
  19. #include <vector>
  20. #include <boost/math/constants/constants.hpp>
  21. #include <boost/noncopyable.hpp>
  22. //#define USE_CPP_BIN_FLOAT
  23. #define USE_CPP_DEC_FLOAT
  24. //#define USE_MPFR
  25. #if !defined(DIGIT_COUNT)
  26. #define DIGIT_COUNT 100
  27. #endif
  28. #if !defined(BOOST_NO_CXX11_HDR_CHRONO)
  29. #include <chrono>
  30. #define STD_CHRONO std::chrono
  31. #else
  32. #include <boost/chrono.hpp>
  33. #define STD_CHRONO boost::chrono
  34. #endif
  35. #if defined(USE_CPP_BIN_FLOAT)
  36. #include <boost/multiprecision/cpp_bin_float.hpp>
  37. typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<DIGIT_COUNT + 10> > mp_type;
  38. #elif defined(USE_CPP_DEC_FLOAT)
  39. #include <boost/multiprecision/cpp_dec_float.hpp>
  40. typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<DIGIT_COUNT + 10> > mp_type;
  41. #elif defined(USE_MPFR)
  42. #include <boost/multiprecision/mpfr.hpp>
  43. typedef boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<DIGIT_COUNT + 10> > mp_type;
  44. #else
  45. #error no multiprecision floating type is defined
  46. #endif
  47. template <class clock_type>
  48. struct stopwatch
  49. {
  50. public:
  51. typedef typename clock_type::duration duration_type;
  52. stopwatch() : m_start(clock_type::now()) { }
  53. stopwatch(const stopwatch& other) : m_start(other.m_start) { }
  54. stopwatch& operator=(const stopwatch& other)
  55. {
  56. m_start = other.m_start;
  57. return *this;
  58. }
  59. ~stopwatch() { }
  60. duration_type elapsed() const
  61. {
  62. return (clock_type::now() - m_start);
  63. }
  64. void reset()
  65. {
  66. m_start = clock_type::now();
  67. }
  68. private:
  69. typename clock_type::time_point m_start;
  70. };
  71. namespace my_math
  72. {
  73. template<class T> T chebyshev_t(const std::int32_t n, const T& x);
  74. template<class T> T chebyshev_t(const std::uint32_t n, const T& x, std::vector<T>* vp);
  75. template<class T> bool isneg(const T& x) { return (x < T(0)); }
  76. template<class T> const T& zero() { static const T value_zero(0); return value_zero; }
  77. template<class T> const T& one () { static const T value_one (1); return value_one; }
  78. template<class T> const T& two () { static const T value_two (2); return value_two; }
  79. }
  80. namespace orthogonal_polynomial_series
  81. {
  82. template<typename T> static inline T orthogonal_polynomial_template(const T& x, const std::uint32_t n, std::vector<T>* const vp = static_cast<std::vector<T>*>(0u))
  83. {
  84. // Compute the value of an orthogonal chebyshev polinomial.
  85. // Use stable upward recursion.
  86. if(vp != nullptr)
  87. {
  88. vp->clear();
  89. vp->reserve(static_cast<std::size_t>(n + 1u));
  90. }
  91. T y0 = my_math::one<T>();
  92. if(vp != nullptr) { vp->push_back(y0); }
  93. if(n == static_cast<std::uint32_t>(0u))
  94. {
  95. return y0;
  96. }
  97. T y1 = x;
  98. if(vp != nullptr) { vp->push_back(y1); }
  99. if(n == static_cast<std::uint32_t>(1u))
  100. {
  101. return y1;
  102. }
  103. T a = my_math::two <T>();
  104. T b = my_math::zero<T>();
  105. T c = my_math::one <T>();
  106. T yk;
  107. // Calculate higher orders using the recurrence relation.
  108. // The direction of stability is upward recursion.
  109. for(std::int32_t k = static_cast<std::int32_t>(2); k <= static_cast<std::int32_t>(n); ++k)
  110. {
  111. yk = (((a * x) + b) * y1) - (c * y0);
  112. y0 = y1;
  113. y1 = yk;
  114. if(vp != nullptr) { vp->push_back(yk); }
  115. }
  116. return yk;
  117. }
  118. }
  119. template<class T> T my_math::chebyshev_t(const std::int32_t n, const T& x)
  120. {
  121. if(my_math::isneg(x))
  122. {
  123. const bool b_negate = ((n % static_cast<std::int32_t>(2)) != static_cast<std::int32_t>(0));
  124. const T y = chebyshev_t(n, -x);
  125. return (!b_negate ? y : -y);
  126. }
  127. if(n < static_cast<std::int32_t>(0))
  128. {
  129. const std::int32_t nn = static_cast<std::int32_t>(-n);
  130. return chebyshev_t(nn, x);
  131. }
  132. else
  133. {
  134. return orthogonal_polynomial_series::orthogonal_polynomial_template(x, static_cast<std::uint32_t>(n));
  135. }
  136. }
  137. template<class T> T my_math::chebyshev_t(const std::uint32_t n, const T& x, std::vector<T>* const vp) { return orthogonal_polynomial_series::orthogonal_polynomial_template(x, static_cast<std::int32_t>(n), vp); }
  138. namespace util
  139. {
  140. template <class T> float digit_scale()
  141. {
  142. const int d = ((std::max)(std::numeric_limits<T>::digits10, 15));
  143. return static_cast<float>(d) / 300.0F;
  144. }
  145. }
  146. namespace examples
  147. {
  148. namespace nr_006
  149. {
  150. template<typename T> class hypergeometric_pfq_base : private boost::noncopyable
  151. {
  152. public:
  153. virtual ~hypergeometric_pfq_base() { }
  154. virtual void ccoef() const = 0;
  155. virtual T series() const
  156. {
  157. using my_math::chebyshev_t;
  158. // Compute the Chebyshev coefficients.
  159. // Get the values of the shifted Chebyshev polynomials.
  160. std::vector<T> chebyshev_t_shifted_values;
  161. const T z_shifted = ((Z / W) * static_cast<std::int32_t>(2)) - static_cast<std::int32_t>(1);
  162. chebyshev_t(static_cast<std::uint32_t>(C.size()),
  163. z_shifted,
  164. &chebyshev_t_shifted_values);
  165. // Luke: C ---------- COMPUTE SCALE FACTOR ----------
  166. // Luke: C
  167. // Luke: C ---------- SCALE THE COEFFICIENTS ----------
  168. // Luke: C
  169. // The coefficient scaling is preformed after the Chebyshev summation,
  170. // and it is carried out with a single division operation.
  171. bool b_neg = false;
  172. const T scale = std::accumulate(C.begin(),
  173. C.end(),
  174. T(0),
  175. [&b_neg](T scale_sum, const T& ck) -> T
  176. {
  177. ((!b_neg) ? (scale_sum += ck) : (scale_sum -= ck));
  178. b_neg = (!b_neg);
  179. return scale_sum;
  180. });
  181. // Compute the result of the series expansion using unscaled coefficients.
  182. const T sum = std::inner_product(C.begin(),
  183. C.end(),
  184. chebyshev_t_shifted_values.begin(),
  185. T(0));
  186. // Return the properly scaled result.
  187. return sum / scale;
  188. }
  189. protected:
  190. const T Z;
  191. const T W;
  192. mutable std::deque<T> C;
  193. hypergeometric_pfq_base(const T& z,
  194. const T& w) : Z(z),
  195. W(w),
  196. C(0u) { }
  197. virtual std::int32_t N() const { return static_cast<std::int32_t>(util::digit_scale<T>() * 500.0F); }
  198. };
  199. template<typename T> class ccoef4_hypergeometric_0f1 : public hypergeometric_pfq_base<T>
  200. {
  201. public:
  202. ccoef4_hypergeometric_0f1(const T& c,
  203. const T& z,
  204. const T& w) : hypergeometric_pfq_base<T>(z, w),
  205. CP(c) { }
  206. virtual ~ccoef4_hypergeometric_0f1() { }
  207. virtual void ccoef() const
  208. {
  209. // See Luke 1977 page 80.
  210. const std::int32_t N1 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(1));
  211. const std::int32_t N2 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(2));
  212. // Luke: C ---------- START COMPUTING COEFFICIENTS USING ----------
  213. // Luke: C ---------- BACKWARD RECURRENCE SCHEME ----------
  214. // Luke: C
  215. T A3(0);
  216. T A2(0);
  217. T A1(boost::math::tools::root_epsilon<T>());
  218. hypergeometric_pfq_base<T>::C.resize(1u, A1);
  219. std::int32_t X1 = N2;
  220. T C1 = T(1) - CP;
  221. const T Z1 = T(4) / hypergeometric_pfq_base<T>::W;
  222. for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k)
  223. {
  224. const T DIVFAC = T(1) / X1;
  225. --X1;
  226. // The terms have been slightly re-arranged resulting in lower complexity.
  227. // Parentheses have been added to avoid reliance on operator precedence.
  228. const T term = (A2 - ((A3 * DIVFAC) * X1))
  229. + ((A2 * X1) * ((1 + (C1 + X1)) * Z1))
  230. + ((A1 * X1) * ((DIVFAC - (C1 * Z1)) + (X1 * Z1)));
  231. hypergeometric_pfq_base<T>::C.push_front(term);
  232. A3 = A2;
  233. A2 = A1;
  234. A1 = hypergeometric_pfq_base<T>::C.front();
  235. }
  236. hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2);
  237. }
  238. private:
  239. const T CP;
  240. };
  241. template<typename T> class ccoef1_hypergeometric_1f0 : public hypergeometric_pfq_base<T>
  242. {
  243. public:
  244. ccoef1_hypergeometric_1f0(const T& a,
  245. const T& z,
  246. const T& w) : hypergeometric_pfq_base<T>(z, w),
  247. AP(a) { }
  248. virtual ~ccoef1_hypergeometric_1f0() { }
  249. virtual void ccoef() const
  250. {
  251. // See Luke 1977 page 67.
  252. const std::int32_t N1 = static_cast<std::int32_t>(N() + static_cast<std::int32_t>(1));
  253. const std::int32_t N2 = static_cast<std::int32_t>(N() + static_cast<std::int32_t>(2));
  254. // Luke: C ---------- START COMPUTING COEFFICIENTS USING ----------
  255. // Luke: C ---------- BACKWARD RECURRENCE SCHEME ----------
  256. // Luke: C
  257. T A2(0);
  258. T A1(boost::math::tools::root_epsilon<T>());
  259. hypergeometric_pfq_base<T>::C.resize(1u, A1);
  260. std::int32_t X1 = N2;
  261. T V1 = T(1) - AP;
  262. // Here, we have corrected what appears to be an error in Luke's code.
  263. // Luke's original code listing has:
  264. // AFAC = 2 + FOUR/W
  265. // But it appears as though the correct form is:
  266. // AFAC = 2 - FOUR/W.
  267. const T AFAC = 2 - (T(4) / hypergeometric_pfq_base<T>::W);
  268. for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k)
  269. {
  270. --X1;
  271. // The terms have been slightly re-arranged resulting in lower complexity.
  272. // Parentheses have been added to avoid reliance on operator precedence.
  273. const T term = -(((X1 * AFAC) * A1) + ((X1 + V1) * A2)) / (X1 - V1);
  274. hypergeometric_pfq_base<T>::C.push_front(term);
  275. A2 = A1;
  276. A1 = hypergeometric_pfq_base<T>::C.front();
  277. }
  278. hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2);
  279. }
  280. private:
  281. const T AP;
  282. virtual std::int32_t N() const { return static_cast<std::int32_t>(util::digit_scale<T>() * 1600.0F); }
  283. };
  284. template<typename T> class ccoef3_hypergeometric_1f1 : public hypergeometric_pfq_base<T>
  285. {
  286. public:
  287. ccoef3_hypergeometric_1f1(const T& a,
  288. const T& c,
  289. const T& z,
  290. const T& w) : hypergeometric_pfq_base<T>(z, w),
  291. AP(a),
  292. CP(c) { }
  293. virtual ~ccoef3_hypergeometric_1f1() { }
  294. virtual void ccoef() const
  295. {
  296. // See Luke 1977 page 74.
  297. const std::int32_t N1 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(1));
  298. const std::int32_t N2 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(2));
  299. // Luke: C ---------- START COMPUTING COEFFICIENTS USING ----------
  300. // Luke: C ---------- BACKWARD RECURRENCE SCHEME ----------
  301. // Luke: C
  302. T A3(0);
  303. T A2(0);
  304. T A1(boost::math::tools::root_epsilon<T>());
  305. hypergeometric_pfq_base<T>::C.resize(1u, A1);
  306. std::int32_t X = N1;
  307. std::int32_t X1 = N2;
  308. T XA = X + AP;
  309. T X3A = (X + 3) - AP;
  310. const T Z1 = T(4) / hypergeometric_pfq_base<T>::W;
  311. for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k)
  312. {
  313. --X;
  314. --X1;
  315. --XA;
  316. --X3A;
  317. const T X3A_over_X2 = X3A / static_cast<std::int32_t>(X + 2);
  318. // The terms have been slightly re-arranged resulting in lower complexity.
  319. // Parentheses have been added to avoid reliance on operator precedence.
  320. const T PART1 = A1 * (((X + CP) * Z1) - X3A_over_X2);
  321. const T PART2 = A2 * (Z1 * ((X + 3) - CP) + (XA / X1));
  322. const T PART3 = A3 * X3A_over_X2;
  323. const T term = (((PART1 + PART2) + PART3) * X1) / XA;
  324. hypergeometric_pfq_base<T>::C.push_front(term);
  325. A3 = A2;
  326. A2 = A1;
  327. A1 = hypergeometric_pfq_base<T>::C.front();
  328. }
  329. hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2);
  330. }
  331. private:
  332. const T AP;
  333. const T CP;
  334. };
  335. template<typename T> class ccoef6_hypergeometric_1f2 : public hypergeometric_pfq_base<T>
  336. {
  337. public:
  338. ccoef6_hypergeometric_1f2(const T& a,
  339. const T& b,
  340. const T& c,
  341. const T& z,
  342. const T& w) : hypergeometric_pfq_base<T>(z, w),
  343. AP(a),
  344. BP(b),
  345. CP(c) { }
  346. virtual ~ccoef6_hypergeometric_1f2() { }
  347. virtual void ccoef() const
  348. {
  349. // See Luke 1977 page 85.
  350. const std::int32_t N1 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(1));
  351. // Luke: C ---------- START COMPUTING COEFFICIENTS USING ----------
  352. // Luke: C ---------- BACKWARD RECURRENCE SCHEME ----------
  353. // Luke: C
  354. T A4(0);
  355. T A3(0);
  356. T A2(0);
  357. T A1(boost::math::tools::root_epsilon<T>());
  358. hypergeometric_pfq_base<T>::C.resize(1u, A1);
  359. std::int32_t X = N1;
  360. T PP = X + AP;
  361. const T Z1 = T(4) / hypergeometric_pfq_base<T>::W;
  362. for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k)
  363. {
  364. --X;
  365. --PP;
  366. const std::int32_t TWO_X = static_cast<std::int32_t>(X * 2);
  367. const std::int32_t X_PLUS_1 = static_cast<std::int32_t>(X + 1);
  368. const std::int32_t X_PLUS_3 = static_cast<std::int32_t>(X + 3);
  369. const std::int32_t X_PLUS_4 = static_cast<std::int32_t>(X + 4);
  370. const T QQ = T(TWO_X + 3) / static_cast<std::int32_t>(TWO_X + static_cast<std::int32_t>(5));
  371. const T SS = (X + BP) * (X + CP);
  372. // The terms have been slightly re-arranged resulting in lower complexity.
  373. // Parentheses have been added to avoid reliance on operator precedence.
  374. const T PART1 = A1 * (((PP - (QQ * (PP + 1))) * 2) + (SS * Z1));
  375. const T PART2 = (A2 * (X + 2)) * ((((TWO_X + 1) * PP) / X_PLUS_1) - ((QQ * 4) * (PP + 1)) + (((TWO_X + 3) * (PP + 2)) / X_PLUS_3) + ((Z1 * 2) * (SS - (QQ * (X_PLUS_1 + BP)) * (X_PLUS_1 + CP))));
  376. const T PART3 = A3 * ((((X_PLUS_3 - AP) - (QQ * (X_PLUS_4 - AP))) * 2) + (((QQ * Z1) * (X_PLUS_4 - BP)) * (X_PLUS_4 - CP)));
  377. const T PART4 = ((A4 * QQ) * (X_PLUS_4 - AP)) / X_PLUS_3;
  378. const T term = (((PART1 - PART2) + (PART3 - PART4)) * X_PLUS_1) / PP;
  379. hypergeometric_pfq_base<T>::C.push_front(term);
  380. A4 = A3;
  381. A3 = A2;
  382. A2 = A1;
  383. A1 = hypergeometric_pfq_base<T>::C.front();
  384. }
  385. hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2);
  386. }
  387. private:
  388. const T AP;
  389. const T BP;
  390. const T CP;
  391. };
  392. template<typename T> class ccoef2_hypergeometric_2f1 : public hypergeometric_pfq_base<T>
  393. {
  394. public:
  395. ccoef2_hypergeometric_2f1(const T& a,
  396. const T& b,
  397. const T& c,
  398. const T& z,
  399. const T& w) : hypergeometric_pfq_base<T>(z, w),
  400. AP(a),
  401. BP(b),
  402. CP(c) { }
  403. virtual ~ccoef2_hypergeometric_2f1() { }
  404. virtual void ccoef() const
  405. {
  406. // See Luke 1977 page 59.
  407. const std::int32_t N1 = static_cast<std::int32_t>(N() + static_cast<std::int32_t>(1));
  408. const std::int32_t N2 = static_cast<std::int32_t>(N() + static_cast<std::int32_t>(2));
  409. // Luke: C ---------- START COMPUTING COEFFICIENTS USING ----------
  410. // Luke: C ---------- BACKWARD RECURRENCE SCHEME ----------
  411. // Luke: C
  412. T A3(0);
  413. T A2(0);
  414. T A1(boost::math::tools::root_epsilon<T>());
  415. hypergeometric_pfq_base<T>::C.resize(1u, A1);
  416. std::int32_t X = N1;
  417. std::int32_t X1 = N2;
  418. std::int32_t X3 = static_cast<std::int32_t>((X * 2) + 3);
  419. T X3A = (X + 3) - AP;
  420. T X3B = (X + 3) - BP;
  421. const T Z1 = T(4) / hypergeometric_pfq_base<T>::W;
  422. for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k)
  423. {
  424. --X;
  425. --X1;
  426. --X3A;
  427. --X3B;
  428. X3 -= 2;
  429. const std::int32_t X_PLUS_2 = static_cast<std::int32_t>(X + 2);
  430. const T XAB = T(1) / ((X + AP) * (X + BP));
  431. // The terms have been slightly re-arranged resulting in lower complexity.
  432. // Parentheses have been added to avoid reliance on operator precedence.
  433. const T PART1 = (A1 * X1) * (2 - (((AP + X1) * (BP + X1)) * ((T(X3) / X_PLUS_2) * XAB)) + ((CP + X) * (XAB * Z1)));
  434. const T PART2 = (A2 * XAB) * ((X3A * X3B) - (X3 * ((X3A + X3B) - 1)) + (((3 - CP) + X) * (X1 * Z1)));
  435. const T PART3 = (A3 * X1) * (X3A / X_PLUS_2) * (X3B * XAB);
  436. const T term = (PART1 + PART2) - PART3;
  437. hypergeometric_pfq_base<T>::C.push_front(term);
  438. A3 = A2;
  439. A2 = A1;
  440. A1 = hypergeometric_pfq_base<T>::C.front();
  441. }
  442. hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2);
  443. }
  444. private:
  445. const T AP;
  446. const T BP;
  447. const T CP;
  448. virtual std::int32_t N() const { return static_cast<std::int32_t>(util::digit_scale<T>() * 1600.0F); }
  449. };
  450. template<class T> T luke_ccoef4_hypergeometric_0f1(const T& a, const T& x);
  451. template<class T> T luke_ccoef1_hypergeometric_1f0(const T& a, const T& x);
  452. template<class T> T luke_ccoef3_hypergeometric_1f1(const T& a, const T& b, const T& x);
  453. template<class T> T luke_ccoef6_hypergeometric_1f2(const T& a, const T& b, const T& c, const T& x);
  454. template<class T> T luke_ccoef2_hypergeometric_2f1(const T& a, const T& b, const T& c, const T& x);
  455. }
  456. }
  457. template<class T>
  458. T examples::nr_006::luke_ccoef4_hypergeometric_0f1(const T& a, const T& x)
  459. {
  460. const ccoef4_hypergeometric_0f1<T> hypergeometric_0f1_object(a, x, T(-20));
  461. hypergeometric_0f1_object.ccoef();
  462. return hypergeometric_0f1_object.series();
  463. }
  464. template<class T>
  465. T examples::nr_006::luke_ccoef1_hypergeometric_1f0(const T& a, const T& x)
  466. {
  467. const ccoef1_hypergeometric_1f0<T> hypergeometric_1f0_object(a, x, T(-20));
  468. hypergeometric_1f0_object.ccoef();
  469. return hypergeometric_1f0_object.series();
  470. }
  471. template<class T>
  472. T examples::nr_006::luke_ccoef3_hypergeometric_1f1(const T& a, const T& b, const T& x)
  473. {
  474. const ccoef3_hypergeometric_1f1<T> hypergeometric_1f1_object(a, b, x, T(-20));
  475. hypergeometric_1f1_object.ccoef();
  476. return hypergeometric_1f1_object.series();
  477. }
  478. template<class T>
  479. T examples::nr_006::luke_ccoef6_hypergeometric_1f2(const T& a, const T& b, const T& c, const T& x)
  480. {
  481. const ccoef6_hypergeometric_1f2<T> hypergeometric_1f2_object(a, b, c, x, T(-20));
  482. hypergeometric_1f2_object.ccoef();
  483. return hypergeometric_1f2_object.series();
  484. }
  485. template<class T>
  486. T examples::nr_006::luke_ccoef2_hypergeometric_2f1(const T& a, const T& b, const T& c, const T& x)
  487. {
  488. const ccoef2_hypergeometric_2f1<T> hypergeometric_2f1_object(a, b, c, x, T(-20));
  489. hypergeometric_2f1_object.ccoef();
  490. return hypergeometric_2f1_object.series();
  491. }
  492. int main()
  493. {
  494. stopwatch<STD_CHRONO::high_resolution_clock> my_stopwatch;
  495. float total_time = 0.0F;
  496. std::vector<mp_type> hypergeometric_0f1_results(20U);
  497. std::vector<mp_type> hypergeometric_1f0_results(20U);
  498. std::vector<mp_type> hypergeometric_1f1_results(20U);
  499. std::vector<mp_type> hypergeometric_2f1_results(20U);
  500. std::vector<mp_type> hypergeometric_1f2_results(20U);
  501. const mp_type a(mp_type(3) / 7);
  502. const mp_type b(mp_type(2) / 3);
  503. const mp_type c(mp_type(1) / 4);
  504. std::int_least16_t i;
  505. std::cout << "test hypergeometric_0f1." << std::endl;
  506. i = 1U;
  507. my_stopwatch.reset();
  508. // Generate a table of values of Hypergeometric0F1.
  509. // Compare with the Mathematica command:
  510. // Table[N[HypergeometricPFQ[{}, {3/7}, -(i*EulerGamma)], 100], {i, 1, 20, 1}]
  511. std::for_each(hypergeometric_0f1_results.begin(),
  512. hypergeometric_0f1_results.end(),
  513. [&i, &a](mp_type& new_value)
  514. {
  515. const mp_type x(-(boost::math::constants::euler<mp_type>() * i));
  516. new_value = examples::nr_006::luke_ccoef4_hypergeometric_0f1(a, x);
  517. ++i;
  518. });
  519. total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count();
  520. // Print the values of Hypergeometric0F1.
  521. std::for_each(hypergeometric_0f1_results.begin(),
  522. hypergeometric_0f1_results.end(),
  523. [](const mp_type& h)
  524. {
  525. std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl;
  526. });
  527. std::cout << "test hypergeometric_1f0." << std::endl;
  528. i = 1U;
  529. my_stopwatch.reset();
  530. // Generate a table of values of Hypergeometric1F0.
  531. // Compare with the Mathematica command:
  532. // Table[N[HypergeometricPFQ[{3/7}, {}, -(i*EulerGamma)], 100], {i, 1, 20, 1}]
  533. std::for_each(hypergeometric_1f0_results.begin(),
  534. hypergeometric_1f0_results.end(),
  535. [&i, &a](mp_type& new_value)
  536. {
  537. const mp_type x(-(boost::math::constants::euler<mp_type>() * i));
  538. new_value = examples::nr_006::luke_ccoef1_hypergeometric_1f0(a, x);
  539. ++i;
  540. });
  541. total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count();
  542. // Print the values of Hypergeometric1F0.
  543. std::for_each(hypergeometric_1f0_results.begin(),
  544. hypergeometric_1f0_results.end(),
  545. [](const mp_type& h)
  546. {
  547. std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl;
  548. });
  549. std::cout << "test hypergeometric_1f1." << std::endl;
  550. i = 1U;
  551. my_stopwatch.reset();
  552. // Generate a table of values of Hypergeometric1F1.
  553. // Compare with the Mathematica command:
  554. // Table[N[HypergeometricPFQ[{3/7}, {2/3}, -(i*EulerGamma)], 100], {i, 1, 20, 1}]
  555. std::for_each(hypergeometric_1f1_results.begin(),
  556. hypergeometric_1f1_results.end(),
  557. [&i, &a, &b](mp_type& new_value)
  558. {
  559. const mp_type x(-(boost::math::constants::euler<mp_type>() * i));
  560. new_value = examples::nr_006::luke_ccoef3_hypergeometric_1f1(a, b, x);
  561. ++i;
  562. });
  563. total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count();
  564. // Print the values of Hypergeometric1F1.
  565. std::for_each(hypergeometric_1f1_results.begin(),
  566. hypergeometric_1f1_results.end(),
  567. [](const mp_type& h)
  568. {
  569. std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl;
  570. });
  571. std::cout << "test hypergeometric_1f2." << std::endl;
  572. i = 1U;
  573. my_stopwatch.reset();
  574. // Generate a table of values of Hypergeometric1F2.
  575. // Compare with the Mathematica command:
  576. // Table[N[HypergeometricPFQ[{3/7}, {2/3, 1/4}, -(i*EulerGamma)], 100], {i, 1, 20, 1}]
  577. std::for_each(hypergeometric_1f2_results.begin(),
  578. hypergeometric_1f2_results.end(),
  579. [&i, &a, &b, &c](mp_type& new_value)
  580. {
  581. const mp_type x(-(boost::math::constants::euler<mp_type>() * i));
  582. new_value = examples::nr_006::luke_ccoef6_hypergeometric_1f2(a, b, c, x);
  583. ++i;
  584. });
  585. total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count();
  586. // Print the values of Hypergeometric1F2.
  587. std::for_each(hypergeometric_1f2_results.begin(),
  588. hypergeometric_1f2_results.end(),
  589. [](const mp_type& h)
  590. {
  591. std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl;
  592. });
  593. std::cout << "test hypergeometric_2f1." << std::endl;
  594. i = 1U;
  595. my_stopwatch.reset();
  596. // Generate a table of values of Hypergeometric2F1.
  597. // Compare with the Mathematica command:
  598. // Table[N[HypergeometricPFQ[{3/7, 2/3}, {1/4}, -(i * EulerGamma)], 100], {i, 1, 20, 1}]
  599. std::for_each(hypergeometric_2f1_results.begin(),
  600. hypergeometric_2f1_results.end(),
  601. [&i, &a, &b, &c](mp_type& new_value)
  602. {
  603. const mp_type x(-(boost::math::constants::euler<mp_type>() * i));
  604. new_value = examples::nr_006::luke_ccoef2_hypergeometric_2f1(a, b, c, x);
  605. ++i;
  606. });
  607. total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count();
  608. // Print the values of Hypergeometric2F1.
  609. std::for_each(hypergeometric_2f1_results.begin(),
  610. hypergeometric_2f1_results.end(),
  611. [](const mp_type& h)
  612. {
  613. std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl;
  614. });
  615. std::cout << "Total execution time = " << std::setprecision(3) << total_time << "s" << std::endl;
  616. }