digamma.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. // (C) Copyright John Maddock 2006.
  2. // (C) Copyright Matt Borland 2024.
  3. // Use, modification and distribution are subject to the
  4. // Boost 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_MATH_SF_DIGAMMA_HPP
  7. #define BOOST_MATH_SF_DIGAMMA_HPP
  8. #ifdef _MSC_VER
  9. #pragma once
  10. #pragma warning(push)
  11. #pragma warning(disable:4702) // Unreachable code (release mode only warning)
  12. #endif
  13. #include <boost/math/tools/config.hpp>
  14. #include <boost/math/tools/type_traits.hpp>
  15. #include <boost/math/tools/rational.hpp>
  16. #include <boost/math/tools/promotion.hpp>
  17. #include <boost/math/policies/policy.hpp>
  18. #include <boost/math/policies/error_handling.hpp>
  19. #include <boost/math/constants/constants.hpp>
  20. #ifndef BOOST_MATH_HAS_NVRTC
  21. #include <boost/math/special_functions/math_fwd.hpp>
  22. #include <boost/math/tools/series.hpp>
  23. #include <boost/math/policies/error_handling.hpp>
  24. #include <boost/math/constants/constants.hpp>
  25. #include <boost/math/tools/big_constant.hpp>
  26. #endif
  27. #if defined(__GNUC__) && defined(BOOST_MATH_USE_FLOAT128)
  28. //
  29. // This is the only way we can avoid
  30. // warning: non-standard suffix on floating constant [-Wpedantic]
  31. // when building with -Wall -pedantic. Neither __extension__
  32. // nor #pragma diagnostic ignored work :(
  33. //
  34. #pragma GCC system_header
  35. #endif
  36. namespace boost{
  37. namespace math{
  38. namespace detail{
  39. //
  40. // Begin by defining the smallest value for which it is safe to
  41. // use the asymptotic expansion for digamma:
  42. //
  43. BOOST_MATH_GPU_ENABLED inline unsigned digamma_large_lim(const boost::math::integral_constant<int, 0>*)
  44. { return 20; }
  45. BOOST_MATH_GPU_ENABLED inline unsigned digamma_large_lim(const boost::math::integral_constant<int, 113>*)
  46. { return 20; }
  47. BOOST_MATH_GPU_ENABLED inline unsigned digamma_large_lim(const void*)
  48. { return 10; }
  49. //
  50. // Implementations of the asymptotic expansion come next,
  51. // the coefficients of the series have been evaluated
  52. // in advance at high precision, and the series truncated
  53. // at the first term that's too small to effect the result.
  54. // Note that the series becomes divergent after a while
  55. // so truncation is very important.
  56. //
  57. // This first one gives 34-digit precision for x >= 20:
  58. //
  59. #ifndef BOOST_MATH_HAS_NVRTC
  60. template <class T>
  61. inline T digamma_imp_large(T x, const boost::math::integral_constant<int, 113>*)
  62. {
  63. BOOST_MATH_STD_USING // ADL of std functions.
  64. static const T P[] = {
  65. BOOST_MATH_BIG_CONSTANT(T, 113, 0.083333333333333333333333333333333333333333333333333),
  66. BOOST_MATH_BIG_CONSTANT(T, 113, -0.0083333333333333333333333333333333333333333333333333),
  67. BOOST_MATH_BIG_CONSTANT(T, 113, 0.003968253968253968253968253968253968253968253968254),
  68. BOOST_MATH_BIG_CONSTANT(T, 113, -0.0041666666666666666666666666666666666666666666666667),
  69. BOOST_MATH_BIG_CONSTANT(T, 113, 0.0075757575757575757575757575757575757575757575757576),
  70. BOOST_MATH_BIG_CONSTANT(T, 113, -0.021092796092796092796092796092796092796092796092796),
  71. BOOST_MATH_BIG_CONSTANT(T, 113, 0.083333333333333333333333333333333333333333333333333),
  72. BOOST_MATH_BIG_CONSTANT(T, 113, -0.44325980392156862745098039215686274509803921568627),
  73. BOOST_MATH_BIG_CONSTANT(T, 113, 3.0539543302701197438039543302701197438039543302701),
  74. BOOST_MATH_BIG_CONSTANT(T, 113, -26.456212121212121212121212121212121212121212121212),
  75. BOOST_MATH_BIG_CONSTANT(T, 113, 281.4601449275362318840579710144927536231884057971),
  76. BOOST_MATH_BIG_CONSTANT(T, 113, -3607.510546398046398046398046398046398046398046398),
  77. BOOST_MATH_BIG_CONSTANT(T, 113, 54827.583333333333333333333333333333333333333333333),
  78. BOOST_MATH_BIG_CONSTANT(T, 113, -974936.82385057471264367816091954022988505747126437),
  79. BOOST_MATH_BIG_CONSTANT(T, 113, 20052695.796688078946143462272494530559046688078946),
  80. BOOST_MATH_BIG_CONSTANT(T, 113, -472384867.72162990196078431372549019607843137254902),
  81. BOOST_MATH_BIG_CONSTANT(T, 113, 12635724795.916666666666666666666666666666666666667)
  82. };
  83. x -= 1;
  84. T result = log(x);
  85. result += 1 / (2 * x);
  86. T z = 1 / (x*x);
  87. result -= z * tools::evaluate_polynomial(P, z);
  88. return result;
  89. }
  90. //
  91. // 19-digit precision for x >= 10:
  92. //
  93. template <class T>
  94. inline T digamma_imp_large(T x, const boost::math::integral_constant<int, 64>*)
  95. {
  96. BOOST_MATH_STD_USING // ADL of std functions.
  97. static const T P[] = {
  98. BOOST_MATH_BIG_CONSTANT(T, 64, 0.083333333333333333333333333333333333333333333333333),
  99. BOOST_MATH_BIG_CONSTANT(T, 64, -0.0083333333333333333333333333333333333333333333333333),
  100. BOOST_MATH_BIG_CONSTANT(T, 64, 0.003968253968253968253968253968253968253968253968254),
  101. BOOST_MATH_BIG_CONSTANT(T, 64, -0.0041666666666666666666666666666666666666666666666667),
  102. BOOST_MATH_BIG_CONSTANT(T, 64, 0.0075757575757575757575757575757575757575757575757576),
  103. BOOST_MATH_BIG_CONSTANT(T, 64, -0.021092796092796092796092796092796092796092796092796),
  104. BOOST_MATH_BIG_CONSTANT(T, 64, 0.083333333333333333333333333333333333333333333333333),
  105. BOOST_MATH_BIG_CONSTANT(T, 64, -0.44325980392156862745098039215686274509803921568627),
  106. BOOST_MATH_BIG_CONSTANT(T, 64, 3.0539543302701197438039543302701197438039543302701),
  107. BOOST_MATH_BIG_CONSTANT(T, 64, -26.456212121212121212121212121212121212121212121212),
  108. BOOST_MATH_BIG_CONSTANT(T, 64, 281.4601449275362318840579710144927536231884057971),
  109. };
  110. x -= 1;
  111. T result = log(x);
  112. result += 1 / (2 * x);
  113. T z = 1 / (x*x);
  114. result -= z * tools::evaluate_polynomial(P, z);
  115. return result;
  116. }
  117. #endif
  118. //
  119. // 17-digit precision for x >= 10:
  120. //
  121. template <class T>
  122. BOOST_MATH_GPU_ENABLED inline T digamma_imp_large(T x, const boost::math::integral_constant<int, 53>*)
  123. {
  124. BOOST_MATH_STD_USING // ADL of std functions.
  125. BOOST_MATH_STATIC const T P[] = {
  126. 0.083333333333333333333333333333333333333333333333333,
  127. -0.0083333333333333333333333333333333333333333333333333,
  128. 0.003968253968253968253968253968253968253968253968254,
  129. -0.0041666666666666666666666666666666666666666666666667,
  130. 0.0075757575757575757575757575757575757575757575757576,
  131. -0.021092796092796092796092796092796092796092796092796,
  132. 0.083333333333333333333333333333333333333333333333333,
  133. -0.44325980392156862745098039215686274509803921568627
  134. };
  135. x -= 1;
  136. T result = log(x);
  137. result += 1 / (2 * x);
  138. T z = 1 / (x*x);
  139. result -= z * tools::evaluate_polynomial(P, z);
  140. return result;
  141. }
  142. //
  143. // 9-digit precision for x >= 10:
  144. //
  145. template <class T>
  146. BOOST_MATH_GPU_ENABLED inline T digamma_imp_large(T x, const boost::math::integral_constant<int, 24>*)
  147. {
  148. BOOST_MATH_STD_USING // ADL of std functions.
  149. BOOST_MATH_STATIC const T P[] = {
  150. 0.083333333333333333333333333333333333333333333333333f,
  151. -0.0083333333333333333333333333333333333333333333333333f,
  152. 0.003968253968253968253968253968253968253968253968254f
  153. };
  154. x -= 1;
  155. T result = log(x);
  156. result += 1 / (2 * x);
  157. T z = 1 / (x*x);
  158. result -= z * tools::evaluate_polynomial(P, z);
  159. return result;
  160. }
  161. #ifndef BOOST_MATH_HAS_NVRTC
  162. //
  163. // Fully generic asymptotic expansion in terms of Bernoulli numbers, see:
  164. // http://functions.wolfram.com/06.14.06.0012.01
  165. //
  166. // LCOV_EXCL_START muliprecision only.
  167. template <class T>
  168. struct digamma_series_func
  169. {
  170. private:
  171. int k;
  172. T xx;
  173. T term;
  174. public:
  175. digamma_series_func(T x) : k(1), xx(x * x), term(1 / (x * x)) {}
  176. T operator()()
  177. {
  178. T result = term * boost::math::bernoulli_b2n<T>(k) / (2 * k);
  179. term /= xx;
  180. ++k;
  181. return result;
  182. }
  183. typedef T result_type;
  184. };
  185. template <class T, class Policy>
  186. inline T digamma_imp_large(T x, const Policy& pol, const boost::math::integral_constant<int, 0>*)
  187. {
  188. BOOST_MATH_STD_USING
  189. digamma_series_func<T> s(x);
  190. T result = log(x) - 1 / (2 * x);
  191. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  192. result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, -result);
  193. result = -result;
  194. policies::check_series_iterations<T>("boost::math::digamma<%1%>(%1%)", max_iter, pol);
  195. return result;
  196. }
  197. // LCOV_EXCL_STOP
  198. //
  199. // Now follow rational approximations over the range [1,2].
  200. //
  201. // 35-digit precision:
  202. //
  203. template <class T>
  204. T digamma_imp_1_2(T x, const boost::math::integral_constant<int, 113>*)
  205. {
  206. //
  207. // Now the approximation, we use the form:
  208. //
  209. // digamma(x) = (x - root) * (Y + R(x-1))
  210. //
  211. // Where root is the location of the positive root of digamma,
  212. // Y is a constant, and R is optimised for low absolute error
  213. // compared to Y.
  214. //
  215. // Max error found at 128-bit long double precision: 5.541e-35
  216. // Maximum Deviation Found (approximation error): 1.965e-35
  217. //
  218. // LCOV_EXCL_START
  219. static const float Y = 0.99558162689208984375F;
  220. static const T root1 = T(1569415565) / 1073741824uL;
  221. static const T root2 = (T(381566830) / 1073741824uL) / 1073741824uL;
  222. static const T root3 = ((T(111616537) / 1073741824uL) / 1073741824uL) / 1073741824uL;
  223. static const T root4 = (((T(503992070) / 1073741824uL) / 1073741824uL) / 1073741824uL) / 1073741824uL;
  224. static const T root5 = BOOST_MATH_BIG_CONSTANT(T, 113, 0.52112228569249997894452490385577338504019838794544e-36);
  225. static const T P[] = {
  226. BOOST_MATH_BIG_CONSTANT(T, 113, 0.25479851061131551526977464225335883769),
  227. BOOST_MATH_BIG_CONSTANT(T, 113, -0.18684290534374944114622235683619897417),
  228. BOOST_MATH_BIG_CONSTANT(T, 113, -0.80360876047931768958995775910991929922),
  229. BOOST_MATH_BIG_CONSTANT(T, 113, -0.67227342794829064330498117008564270136),
  230. BOOST_MATH_BIG_CONSTANT(T, 113, -0.26569010991230617151285010695543858005),
  231. BOOST_MATH_BIG_CONSTANT(T, 113, -0.05775672694575986971640757748003553385),
  232. BOOST_MATH_BIG_CONSTANT(T, 113, -0.0071432147823164975485922555833274240665),
  233. BOOST_MATH_BIG_CONSTANT(T, 113, -0.00048740753910766168912364555706064993274),
  234. BOOST_MATH_BIG_CONSTANT(T, 113, -0.16454996865214115723416538844975174761e-4),
  235. BOOST_MATH_BIG_CONSTANT(T, 113, -0.20327832297631728077731148515093164955e-6)
  236. };
  237. static const T Q[] = {
  238. BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
  239. BOOST_MATH_BIG_CONSTANT(T, 113, 2.6210924610812025425088411043163287646),
  240. BOOST_MATH_BIG_CONSTANT(T, 113, 2.6850757078559596612621337395886392594),
  241. BOOST_MATH_BIG_CONSTANT(T, 113, 1.4320913706209965531250495490639289418),
  242. BOOST_MATH_BIG_CONSTANT(T, 113, 0.4410872083455009362557012239501953402),
  243. BOOST_MATH_BIG_CONSTANT(T, 113, 0.081385727399251729505165509278152487225),
  244. BOOST_MATH_BIG_CONSTANT(T, 113, 0.0089478633066857163432104815183858149496),
  245. BOOST_MATH_BIG_CONSTANT(T, 113, 0.00055861622855066424871506755481997374154),
  246. BOOST_MATH_BIG_CONSTANT(T, 113, 0.1760168552357342401304462967950178554e-4),
  247. BOOST_MATH_BIG_CONSTANT(T, 113, 0.20585454493572473724556649516040874384e-6),
  248. BOOST_MATH_BIG_CONSTANT(T, 113, -0.90745971844439990284514121823069162795e-11),
  249. BOOST_MATH_BIG_CONSTANT(T, 113, 0.48857673606545846774761343500033283272e-13),
  250. };
  251. // LCOV_EXCL_STOP
  252. T g = x - root1;
  253. g -= root2;
  254. g -= root3;
  255. g -= root4;
  256. g -= root5;
  257. T r = tools::evaluate_polynomial(P, T(x-1)) / tools::evaluate_polynomial(Q, T(x-1));
  258. T result = g * Y + g * r;
  259. return result;
  260. }
  261. //
  262. // 19-digit precision:
  263. //
  264. template <class T>
  265. T digamma_imp_1_2(T x, const boost::math::integral_constant<int, 64>*)
  266. {
  267. //
  268. // Now the approximation, we use the form:
  269. //
  270. // digamma(x) = (x - root) * (Y + R(x-1))
  271. //
  272. // Where root is the location of the positive root of digamma,
  273. // Y is a constant, and R is optimised for low absolute error
  274. // compared to Y.
  275. //
  276. // Max error found at 80-bit long double precision: 5.016e-20
  277. // Maximum Deviation Found (approximation error): 3.575e-20
  278. //
  279. // LCOV_EXCL_START
  280. static const float Y = 0.99558162689208984375F;
  281. static const T root1 = T(1569415565) / 1073741824uL;
  282. static const T root2 = (T(381566830) / 1073741824uL) / 1073741824uL;
  283. static const T root3 = BOOST_MATH_BIG_CONSTANT(T, 64, 0.9016312093258695918615325266959189453125e-19);
  284. static const T P[] = {
  285. BOOST_MATH_BIG_CONSTANT(T, 64, 0.254798510611315515235),
  286. BOOST_MATH_BIG_CONSTANT(T, 64, -0.314628554532916496608),
  287. BOOST_MATH_BIG_CONSTANT(T, 64, -0.665836341559876230295),
  288. BOOST_MATH_BIG_CONSTANT(T, 64, -0.314767657147375752913),
  289. BOOST_MATH_BIG_CONSTANT(T, 64, -0.0541156266153505273939),
  290. BOOST_MATH_BIG_CONSTANT(T, 64, -0.00289268368333918761452)
  291. };
  292. static const T Q[] = {
  293. BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
  294. BOOST_MATH_BIG_CONSTANT(T, 64, 2.1195759927055347547),
  295. BOOST_MATH_BIG_CONSTANT(T, 64, 1.54350554664961128724),
  296. BOOST_MATH_BIG_CONSTANT(T, 64, 0.486986018231042975162),
  297. BOOST_MATH_BIG_CONSTANT(T, 64, 0.0660481487173569812846),
  298. BOOST_MATH_BIG_CONSTANT(T, 64, 0.00298999662592323990972),
  299. BOOST_MATH_BIG_CONSTANT(T, 64, -0.165079794012604905639e-5),
  300. BOOST_MATH_BIG_CONSTANT(T, 64, 0.317940243105952177571e-7)
  301. };
  302. // LCOV_EXCL_STOP
  303. T g = x - root1;
  304. g -= root2;
  305. g -= root3;
  306. T r = tools::evaluate_polynomial(P, T(x-1)) / tools::evaluate_polynomial(Q, T(x-1));
  307. T result = g * Y + g * r;
  308. return result;
  309. }
  310. #endif
  311. //
  312. // 18-digit precision:
  313. //
  314. template <class T>
  315. BOOST_MATH_GPU_ENABLED T digamma_imp_1_2(T x, const boost::math::integral_constant<int, 53>*)
  316. {
  317. //
  318. // Now the approximation, we use the form:
  319. //
  320. // digamma(x) = (x - root) * (Y + R(x-1))
  321. //
  322. // Where root is the location of the positive root of digamma,
  323. // Y is a constant, and R is optimised for low absolute error
  324. // compared to Y.
  325. //
  326. // Maximum Deviation Found: 1.466e-18
  327. // At double precision, max error found: 2.452e-17
  328. //
  329. // LCOV_EXCL_START
  330. BOOST_MATH_STATIC const float Y = 0.99558162689208984F;
  331. BOOST_MATH_STATIC const T root1 = T(1569415565) / 1073741824uL;
  332. BOOST_MATH_STATIC const T root2 = (T(381566830) / 1073741824uL) / 1073741824uL;
  333. BOOST_MATH_STATIC const T root3 = BOOST_MATH_BIG_CONSTANT(T, 53, 0.9016312093258695918615325266959189453125e-19);
  334. BOOST_MATH_STATIC const T P[] = {
  335. BOOST_MATH_BIG_CONSTANT(T, 53, 0.25479851061131551),
  336. BOOST_MATH_BIG_CONSTANT(T, 53, -0.32555031186804491),
  337. BOOST_MATH_BIG_CONSTANT(T, 53, -0.65031853770896507),
  338. BOOST_MATH_BIG_CONSTANT(T, 53, -0.28919126444774784),
  339. BOOST_MATH_BIG_CONSTANT(T, 53, -0.045251321448739056),
  340. BOOST_MATH_BIG_CONSTANT(T, 53, -0.0020713321167745952)
  341. };
  342. BOOST_MATH_STATIC const T Q[] = {
  343. BOOST_MATH_BIG_CONSTANT(T, 53, 1.0),
  344. BOOST_MATH_BIG_CONSTANT(T, 53, 2.0767117023730469),
  345. BOOST_MATH_BIG_CONSTANT(T, 53, 1.4606242909763515),
  346. BOOST_MATH_BIG_CONSTANT(T, 53, 0.43593529692665969),
  347. BOOST_MATH_BIG_CONSTANT(T, 53, 0.054151797245674225),
  348. BOOST_MATH_BIG_CONSTANT(T, 53, 0.0021284987017821144),
  349. BOOST_MATH_BIG_CONSTANT(T, 53, -0.55789841321675513e-6)
  350. };
  351. // LCOV_EXCL_STOP
  352. T g = x - root1;
  353. g -= root2;
  354. g -= root3;
  355. T r = tools::evaluate_polynomial(P, T(x-1)) / tools::evaluate_polynomial(Q, T(x-1));
  356. T result = g * Y + g * r;
  357. return result;
  358. }
  359. //
  360. // 9-digit precision:
  361. //
  362. template <class T>
  363. BOOST_MATH_GPU_ENABLED inline T digamma_imp_1_2(T x, const boost::math::integral_constant<int, 24>*)
  364. {
  365. //
  366. // Now the approximation, we use the form:
  367. //
  368. // digamma(x) = (x - root) * (Y + R(x-1))
  369. //
  370. // Where root is the location of the positive root of digamma,
  371. // Y is a constant, and R is optimised for low absolute error
  372. // compared to Y.
  373. //
  374. // Maximum Deviation Found: 3.388e-010
  375. // At float precision, max error found: 2.008725e-008
  376. //
  377. // LCOV_EXCL_START
  378. BOOST_MATH_STATIC const float Y = 0.99558162689208984f;
  379. BOOST_MATH_STATIC const T root = 1532632.0f / 1048576;
  380. BOOST_MATH_STATIC const T root_minor = static_cast<T>(0.3700660185912626595423257213284682051735604e-6L);
  381. BOOST_MATH_STATIC const T P[] = {
  382. 0.25479851023250261e0f,
  383. -0.44981331915268368e0f,
  384. -0.43916936919946835e0f,
  385. -0.61041765350579073e-1f
  386. };
  387. BOOST_MATH_STATIC const T Q[] = {
  388. 0.1e1f,
  389. 0.15890202430554952e1f,
  390. 0.65341249856146947e0f,
  391. 0.63851690523355715e-1f
  392. };
  393. // LCOV_EXCL_STOP
  394. T g = x - root;
  395. g -= root_minor;
  396. T r = tools::evaluate_polynomial(P, T(x-1)) / tools::evaluate_polynomial(Q, T(x-1));
  397. T result = g * Y + g * r;
  398. return result;
  399. }
  400. template <class T, class Tag, class Policy>
  401. BOOST_MATH_GPU_ENABLED T digamma_imp(T x, const Tag* t, const Policy& pol)
  402. {
  403. //
  404. // This handles reflection of negative arguments, and all our
  405. // error handling, then forwards to the T-specific approximation.
  406. //
  407. BOOST_MATH_STD_USING // ADL of std functions.
  408. T result = 0;
  409. //
  410. // Check for negative arguments and use reflection:
  411. //
  412. if(x <= -1)
  413. {
  414. // Reflect:
  415. x = 1 - x;
  416. // Argument reduction for tan:
  417. T remainder = x - floor(x);
  418. // Shift to negative if > 0.5:
  419. if(remainder > T(0.5))
  420. {
  421. remainder -= 1;
  422. }
  423. //
  424. // check for evaluation at a negative pole:
  425. //
  426. if(remainder == 0)
  427. {
  428. return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", nullptr, (1-x), pol);
  429. }
  430. result = constants::pi<T>() / tan(constants::pi<T>() * remainder);
  431. }
  432. if(x == 0)
  433. return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", nullptr, x, pol);
  434. //
  435. // If we're above the lower-limit for the
  436. // asymptotic expansion then use it:
  437. //
  438. #ifndef BOOST_MATH_HAS_NVRTC
  439. if(x >= digamma_large_lim(t))
  440. {
  441. result += digamma_imp_large(x, t);
  442. }
  443. else
  444. #endif
  445. {
  446. //
  447. // If x > 2 reduce to the interval [1,2]:
  448. //
  449. while(x > 2)
  450. {
  451. x -= 1;
  452. result += 1/x;
  453. }
  454. //
  455. // If x < 1 use recurrence to shift to > 1:
  456. //
  457. while(x < 1)
  458. {
  459. result -= 1/x;
  460. x += 1;
  461. }
  462. result += digamma_imp_1_2(x, t);
  463. }
  464. return result;
  465. }
  466. #ifndef BOOST_MATH_HAS_NVRTC
  467. // LCOV_EXCL_START
  468. template <class T, class Policy>
  469. T digamma_imp(T x, const boost::math::integral_constant<int, 0>* t, const Policy& pol)
  470. {
  471. //
  472. // This handles reflection of negative arguments, and all our
  473. // error handling, then forwards to the T-specific approximation.
  474. //
  475. // This is covered by our real_concept tests, but these are disabled for
  476. // code coverage runs for performance reasons.
  477. //
  478. BOOST_MATH_STD_USING // ADL of std functions.
  479. T result = 0;
  480. //
  481. // Check for negative arguments and use reflection:
  482. //
  483. if(x <= -1)
  484. {
  485. // Reflect:
  486. x = 1 - x;
  487. // Argument reduction for tan:
  488. T remainder = x - floor(x);
  489. // Shift to negative if > 0.5:
  490. if(remainder > T(0.5))
  491. {
  492. remainder -= 1;
  493. }
  494. //
  495. // check for evaluation at a negative pole:
  496. //
  497. if(remainder == 0)
  498. {
  499. return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", nullptr, (1 - x), pol);
  500. }
  501. result = constants::pi<T>() / tan(constants::pi<T>() * remainder);
  502. }
  503. if(x == 0)
  504. return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", nullptr, x, pol);
  505. //
  506. // If we're above the lower-limit for the
  507. // asymptotic expansion then use it, the
  508. // limit is a linear interpolation with
  509. // limit = 10 at 50 bit precision and
  510. // limit = 250 at 1000 bit precision.
  511. //
  512. int lim = 10 + ((tools::digits<T>() - 50) * 240L) / 950;
  513. T two_x = ldexp(x, 1);
  514. if(x >= lim)
  515. {
  516. result += digamma_imp_large(x, pol, t);
  517. }
  518. else if(floor(x) == x)
  519. {
  520. //
  521. // Special case for integer arguments, see
  522. // http://functions.wolfram.com/06.14.03.0001.01
  523. //
  524. result = -constants::euler<T, Policy>();
  525. T val = 1;
  526. while(val < x)
  527. {
  528. result += 1 / val;
  529. val += 1;
  530. }
  531. }
  532. else if(floor(two_x) == two_x)
  533. {
  534. //
  535. // Special case for half integer arguments, see:
  536. // http://functions.wolfram.com/06.14.03.0007.01
  537. //
  538. result = -2 * constants::ln_two<T, Policy>() - constants::euler<T, Policy>();
  539. int n = itrunc(x);
  540. if(n)
  541. {
  542. for(int k = 1; k < n; ++k)
  543. result += 1 / T(k);
  544. for(int k = n; k <= 2 * n - 1; ++k)
  545. result += 2 / T(k);
  546. }
  547. }
  548. else
  549. {
  550. //
  551. // Rescale so we can use the asymptotic expansion:
  552. //
  553. while(x < lim)
  554. {
  555. result -= 1 / x;
  556. x += 1;
  557. }
  558. result += digamma_imp_large(x, pol, t);
  559. }
  560. return result;
  561. }
  562. // LCOV_EXCL_STOP
  563. #endif
  564. } // namespace detail
  565. template <class T, class Policy>
  566. BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
  567. digamma(T x, const Policy&)
  568. {
  569. typedef typename tools::promote_args<T>::type result_type;
  570. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  571. typedef typename policies::precision<T, Policy>::type precision_type;
  572. typedef boost::math::integral_constant<int,
  573. (precision_type::value <= 0) || (precision_type::value > 113) ? 0 :
  574. precision_type::value <= 24 ? 24 :
  575. precision_type::value <= 53 ? 53 :
  576. precision_type::value <= 64 ? 64 :
  577. precision_type::value <= 113 ? 113 : 0 > tag_type;
  578. typedef typename policies::normalise<
  579. Policy,
  580. policies::promote_float<false>,
  581. policies::promote_double<false>,
  582. policies::discrete_quantile<>,
  583. policies::assert_undefined<> >::type forwarding_policy;
  584. return policies::checked_narrowing_cast<result_type, Policy>(detail::digamma_imp(static_cast<value_type>(x), static_cast<const tag_type*>(nullptr), forwarding_policy()), "boost::math::digamma<%1%>(%1%)");
  585. }
  586. template <class T>
  587. BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
  588. digamma(T x)
  589. {
  590. return digamma(x, policies::policy<>());
  591. }
  592. } // namespace math
  593. } // namespace boost
  594. #ifdef _MSC_VER
  595. #pragma warning(pop)
  596. #endif
  597. #endif