non_central_t.hpp 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325
  1. // boost\math\distributions\non_central_t.hpp
  2. // Copyright John Maddock 2008.
  3. // Use, modification and distribution are subject to the
  4. // Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP
  8. #define BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP
  9. #include <boost/math/distributions/fwd.hpp>
  10. #include <boost/math/distributions/non_central_beta.hpp> // for nc beta
  11. #include <boost/math/distributions/normal.hpp> // for normal CDF and quantile
  12. #include <boost/math/distributions/students_t.hpp>
  13. #include <boost/math/distributions/detail/generic_quantile.hpp> // quantile
  14. #include <boost/math/special_functions/trunc.hpp>
  15. #include <boost/math/special_functions/detail/hypergeometric_series.hpp>
  16. #include <boost/math/quadrature/exp_sinh.hpp>
  17. namespace boost
  18. {
  19. namespace math
  20. {
  21. template <class RealType, class Policy>
  22. class non_central_t_distribution;
  23. namespace detail{
  24. template <class T, class Policy>
  25. T non_central_t2_p(T v, T delta, T x, T y, const Policy& pol, T init_val)
  26. {
  27. BOOST_MATH_STD_USING
  28. //
  29. // Variables come first:
  30. //
  31. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  32. T errtol = policies::get_epsilon<T, Policy>();
  33. T d2 = delta * delta / 2;
  34. //
  35. // k is the starting point for iteration, and is the
  36. // maximum of the poisson weighting term, we don't
  37. // ever allow k == 0 as this can lead to catastrophic
  38. // cancellation errors later (test case is v = 1621286869049072.3
  39. // delta = 0.16212868690490723, x = 0.86987415482475994).
  40. //
  41. long long k = lltrunc(d2);
  42. T pois;
  43. if(k == 0) k = 1;
  44. // Starting Poisson weight:
  45. pois = gamma_p_derivative(T(k+1), d2, pol)
  46. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  47. * delta / constants::root_two<T>();
  48. if(pois == 0)
  49. return init_val;
  50. T xterm, beta;
  51. // Recurrence & starting beta terms:
  52. beta = x < y
  53. ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, false, true, &xterm)
  54. : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, true, true, &xterm);
  55. while (fabs(beta * pois) < tools::min_value<T>())
  56. {
  57. if ((k == 0) || (pois == 0))
  58. return init_val;
  59. k /= 2;
  60. pois = gamma_p_derivative(T(k + 1), d2, pol)
  61. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  62. * delta / constants::root_two<T>();
  63. beta = x < y
  64. ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, false, true, &xterm)
  65. : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, true, true, &xterm);
  66. }
  67. xterm *= y / (v / 2 + k);
  68. T poisf(pois), betaf(beta), xtermf(xterm);
  69. T sum = init_val;
  70. if((xterm == 0) && (beta == 0))
  71. return init_val;
  72. //
  73. // Backwards recursion first, this is the stable
  74. // direction for recursion:
  75. //
  76. std::uintmax_t count = 0;
  77. T last_term = 0;
  78. for(auto i = k; i >= 0; --i)
  79. {
  80. T term = beta * pois;
  81. sum += term;
  82. // Don't terminate on first term in case we "fixed" k above:
  83. if(((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol) || (v == 2 && i == 0))
  84. break;
  85. last_term = term;
  86. pois *= (i + 0.5f) / d2;
  87. beta += xterm;
  88. xterm *= (i) / (x * (v / 2 + i - 1));
  89. ++count;
  90. }
  91. last_term = 0;
  92. for(auto i = k + 1; ; ++i)
  93. {
  94. poisf *= d2 / (i + 0.5f);
  95. xtermf *= (x * (v / 2 + i - 1)) / (i);
  96. betaf -= xtermf;
  97. T term = poisf * betaf;
  98. sum += term;
  99. if((fabs(last_term) >= fabs(term)) && (fabs(term/sum) < errtol))
  100. break;
  101. last_term = term;
  102. ++count;
  103. if(count > max_iter)
  104. {
  105. return policies::raise_evaluation_error("cdf(non_central_t_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
  106. }
  107. }
  108. return sum;
  109. }
  110. template <class T, class Policy>
  111. T non_central_t2_q(T v, T delta, T x, T y, const Policy& pol, T init_val)
  112. {
  113. BOOST_MATH_STD_USING
  114. //
  115. // Variables come first:
  116. //
  117. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  118. T errtol = boost::math::policies::get_epsilon<T, Policy>();
  119. T d2 = delta * delta / 2;
  120. //
  121. // k is the starting point for iteration, and is the
  122. // maximum of the poisson weighting term, we don't allow
  123. // k == 0 as this can cause catastrophic cancellation errors
  124. // (test case is v = 561908036470413.25, delta = 0.056190803647041321,
  125. // x = 1.6155232703966216):
  126. //
  127. long long k = lltrunc(d2);
  128. if(k == 0) k = 1;
  129. // Starting Poisson weight:
  130. T pois;
  131. if((k < static_cast<long long>(max_factorial<T>::value)) && (d2 < tools::log_max_value<T>()) && (log(d2) * k < tools::log_max_value<T>()))
  132. {
  133. //
  134. // For small k we can optimise this calculation by using
  135. // a simpler reduced formula:
  136. //
  137. pois = exp(-d2);
  138. pois *= pow(d2, static_cast<T>(k));
  139. pois /= boost::math::tgamma(T(k + 1 + 0.5), pol);
  140. pois *= delta / constants::root_two<T>();
  141. }
  142. else
  143. {
  144. pois = gamma_p_derivative(T(k+1), d2, pol)
  145. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  146. * delta / constants::root_two<T>();
  147. }
  148. if(pois == 0)
  149. return init_val;
  150. // Recurance term:
  151. T xterm;
  152. T beta;
  153. // Starting beta term:
  154. if(k != 0)
  155. {
  156. beta = x < y
  157. ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, true, true, &xterm)
  158. : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, false, true, &xterm);
  159. xterm *= y / (v / 2 + k);
  160. }
  161. else
  162. {
  163. beta = pow(y, v / 2);
  164. xterm = beta;
  165. }
  166. T poisf(pois), betaf(beta), xtermf(xterm);
  167. T sum = init_val;
  168. if((xterm == 0) && (beta == 0))
  169. return init_val;
  170. //
  171. // Fused forward and backwards recursion:
  172. //
  173. std::uintmax_t count = 0;
  174. T last_term = 0;
  175. for(auto i = k + 1, j = k; ; ++i, --j)
  176. {
  177. poisf *= d2 / (i + 0.5f);
  178. xtermf *= (x * (v / 2 + i - 1)) / (i);
  179. betaf += xtermf;
  180. T term = poisf * betaf;
  181. if(j >= 0)
  182. {
  183. term += beta * pois;
  184. pois *= (j + 0.5f) / d2;
  185. beta -= xterm;
  186. if(!(v == 2 && j == 0))
  187. xterm *= (j) / (x * (v / 2 + j - 1));
  188. }
  189. sum += term;
  190. // Don't terminate on first term in case we "fixed" the value of k above:
  191. if((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol)
  192. break;
  193. last_term = term;
  194. if(count > max_iter)
  195. {
  196. return policies::raise_evaluation_error("cdf(non_central_t_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
  197. }
  198. ++count;
  199. }
  200. return sum;
  201. }
  202. template <class T, class Policy>
  203. T non_central_t_cdf(T v, T delta, T t, bool invert, const Policy& pol)
  204. {
  205. BOOST_MATH_STD_USING
  206. if ((boost::math::isinf)(v))
  207. { // Infinite degrees of freedom, so use normal distribution located at delta.
  208. normal_distribution<T, Policy> n(delta, 1);
  209. return cdf(n, t);
  210. }
  211. //
  212. // Otherwise, for t < 0 we have to use the reflection formula:
  213. if(t < 0)
  214. {
  215. t = -t;
  216. delta = -delta;
  217. invert = !invert;
  218. }
  219. if(fabs(delta / (4 * v)) < policies::get_epsilon<T, Policy>())
  220. {
  221. // Approximate with a Student's T centred on delta,
  222. // the crossover point is based on eq 2.6 from
  223. // "A Comparison of Approximations To Percentiles of the
  224. // Noncentral t-Distribution". H. Sahai and M. M. Ojeda,
  225. // Revista Investigacion Operacional Vol 21, No 2, 2000.
  226. // Original sources referenced in the above are:
  227. // "Some Approximations to the Percentage Points of the Noncentral
  228. // t-Distribution". C. van Eeden. International Statistical Review, 29, 4-31.
  229. // "Continuous Univariate Distributions". N.L. Johnson, S. Kotz and
  230. // N. Balkrishnan. 1995. John Wiley and Sons New York.
  231. T result = cdf(students_t_distribution<T, Policy>(v), t - delta);
  232. return invert ? 1 - result : result;
  233. }
  234. //
  235. // x and y are the corresponding random
  236. // variables for the noncentral beta distribution,
  237. // with y = 1 - x:
  238. //
  239. T x = t * t / (v + t * t);
  240. T y = v / (v + t * t);
  241. T d2 = delta * delta;
  242. T a = 0.5f;
  243. T b = v / 2;
  244. T c = a + b + d2 / 2;
  245. //
  246. // Crossover point for calculating p or q is the same
  247. // as for the noncentral beta:
  248. //
  249. T cross = 1 - (b / c) * (1 + d2 / (2 * c * c));
  250. T result;
  251. if(x < cross)
  252. {
  253. //
  254. // Calculate p:
  255. //
  256. if(x != 0)
  257. {
  258. result = non_central_beta_p(a, b, d2, x, y, pol);
  259. result = non_central_t2_p(v, delta, x, y, pol, result);
  260. result /= 2;
  261. }
  262. else
  263. result = 0;
  264. if (invert)
  265. {
  266. result = cdf(complement(boost::math::normal_distribution<T, Policy>(), -delta)) - result;
  267. invert = false;
  268. }
  269. else
  270. result += cdf(boost::math::normal_distribution<T, Policy>(), -delta);
  271. }
  272. else
  273. {
  274. //
  275. // Calculate q:
  276. //
  277. invert = !invert;
  278. if(x != 0)
  279. {
  280. result = non_central_beta_q(a, b, d2, x, y, pol);
  281. result = non_central_t2_q(v, delta, x, y, pol, result);
  282. result /= 2;
  283. }
  284. else // x == 0
  285. result = cdf(complement(boost::math::normal_distribution<T, Policy>(), -delta));
  286. }
  287. if(invert)
  288. result = 1 - result;
  289. return result;
  290. }
  291. template <class T, class Policy>
  292. T non_central_t_quantile(const char* function, T v, T delta, T p, T q, const Policy&)
  293. {
  294. BOOST_MATH_STD_USING
  295. // static const char* function = "quantile(non_central_t_distribution<%1%>, %1%)";
  296. // now passed as function
  297. typedef typename policies::evaluation<T, Policy>::type value_type;
  298. typedef typename policies::normalise<
  299. Policy,
  300. policies::promote_float<false>,
  301. policies::promote_double<false>,
  302. policies::discrete_quantile<>,
  303. policies::assert_undefined<> >::type forwarding_policy;
  304. T r;
  305. if(!detail::check_df_gt0_to_inf(
  306. function,
  307. v, &r, Policy())
  308. ||
  309. !detail::check_non_centrality(
  310. function,
  311. static_cast<T>(delta * delta),
  312. &r,
  313. Policy())
  314. ||
  315. !detail::check_probability(
  316. function,
  317. p,
  318. &r,
  319. Policy()))
  320. return r;
  321. value_type guess = 0;
  322. if ( ((boost::math::isinf)(v)) || (v > 1 / boost::math::tools::epsilon<T>()) )
  323. { // Infinite or very large degrees of freedom, so use normal distribution located at delta.
  324. normal_distribution<T, Policy> n(delta, 1);
  325. if (p < q)
  326. {
  327. return quantile(n, p);
  328. }
  329. else
  330. {
  331. return quantile(complement(n, q));
  332. }
  333. }
  334. else if(v > 3)
  335. { // Use normal distribution to calculate guess.
  336. value_type mean = (v > 1 / policies::get_epsilon<T, Policy>()) ? delta : delta * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, T(0.5f));
  337. value_type var = (v > 1 / policies::get_epsilon<T, Policy>()) ? value_type(1) : (((delta * delta + 1) * v) / (v - 2) - mean * mean);
  338. if(p < q)
  339. guess = quantile(normal_distribution<value_type, forwarding_policy>(mean, var), p);
  340. else
  341. guess = quantile(complement(normal_distribution<value_type, forwarding_policy>(mean, var), q));
  342. }
  343. //
  344. // We *must* get the sign of the initial guess correct,
  345. // or our root-finder will fail, so double check it now:
  346. //
  347. value_type pzero = non_central_t_cdf(
  348. static_cast<value_type>(v),
  349. static_cast<value_type>(delta),
  350. static_cast<value_type>(0),
  351. !(p < q),
  352. forwarding_policy());
  353. int s;
  354. if(p < q)
  355. s = boost::math::sign(p - pzero);
  356. else
  357. s = boost::math::sign(pzero - q);
  358. if(s != boost::math::sign(guess))
  359. {
  360. guess = static_cast<T>(s);
  361. }
  362. value_type result = detail::generic_quantile(
  363. non_central_t_distribution<value_type, forwarding_policy>(v, delta),
  364. (p < q ? p : q),
  365. guess,
  366. (p >= q),
  367. function);
  368. return policies::checked_narrowing_cast<T, forwarding_policy>(
  369. result,
  370. function);
  371. }
  372. template <class T, class Policy>
  373. T non_central_t_pdf_integral(T x, T v, T mu, const Policy& pol)
  374. {
  375. BOOST_MATH_STD_USING
  376. boost::math::quadrature::exp_sinh<T, Policy> integrator;
  377. T integral = pow(v, v / 2) * exp(-v * mu * mu / (2 * (x * x + v)));
  378. if (integral != 0)
  379. {
  380. integral *= integrator.integrate([&x, v, mu](T y)
  381. {
  382. T p;
  383. if (v * log(y) < tools::log_max_value<T>())
  384. p = pow(y, v) * exp(boost::math::pow<2>((y - mu * x / sqrt(x * x + v))) / -2);
  385. else
  386. p = exp(log(y) * v + boost::math::pow<2>((y - mu * x / sqrt(x * x + v))) / -2);
  387. return p;
  388. });
  389. }
  390. integral /= boost::math::constants::root_pi<T>() * boost::math::tgamma(v / 2, pol) * pow(T(2), (v - 1) / 2) * pow(x * x + v, (v + 1) / 2);
  391. return integral;
  392. }
  393. template <class T, class Policy>
  394. T non_central_t_pdf_hypergeometric(T x, T v, T mu, const Policy& pol)
  395. {
  396. BOOST_MATH_STD_USING
  397. long long scale = 0;
  398. const char* function = "non central T PDF";
  399. //
  400. // We only call this routine when we know that the series form of 1F1 is cheap to evaluate,
  401. // so no need to call the whole 1F1 function, just the series will do:
  402. //
  403. T Av = hypergeometric_1F1_generic_series(static_cast<T>((v + 1) / 2), boost::math::constants::half<T>(), static_cast<T>(mu * mu * x * x / (2 * (x * x + v))), pol, scale, function);
  404. Av = ldexp(Av, static_cast<int>(scale));
  405. scale = 0;
  406. T Bv = hypergeometric_1F1_generic_series(static_cast<T>(v / 2 + T(1)), static_cast<T>(T(3) / 2), static_cast<T>(mu * mu * x * x / (2 * (x * x + v))), pol, scale, function);
  407. Bv = ldexp(Bv, static_cast<int>(scale));
  408. Bv *= boost::math::tgamma_delta_ratio(v / 2 + T(1), -constants::half<T>(), pol);
  409. Bv *= boost::math::constants::root_two<T>() * mu * x / sqrt(x * x + v);
  410. T tolerance = tools::root_epsilon<T>() * Av * 4;
  411. Av += Bv;
  412. if (Av < tolerance)
  413. {
  414. // More than half the digits have cancelled, fall back to the integral method:
  415. return non_central_t_pdf_integral(x, v, mu, pol);
  416. }
  417. Av *= exp(-mu * mu / 2) * pow(1 + x * x / v, -(v + 1) / 2) * boost::math::tgamma_delta_ratio(v / 2 + constants::half<T>(), -constants::half<T>(), pol);
  418. Av /= sqrt(v) * boost::math::constants::root_pi<T>();
  419. return Av;
  420. }
  421. template <class T, class Policy>
  422. T non_central_t2_pdf(T n, T delta, T x, T y, const Policy& pol, T init_val)
  423. {
  424. BOOST_MATH_STD_USING
  425. //
  426. // Variables come first:
  427. //
  428. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  429. T errtol = boost::math::policies::get_epsilon<T, Policy>();
  430. T d2 = delta * delta / 2;
  431. //
  432. // k is the starting point for iteration, and is the
  433. // maximum of the poisson weighting term:
  434. //
  435. long long k = lltrunc(d2);
  436. T pois, xterm;
  437. if(k == 0)
  438. k = 1;
  439. // Starting Poisson weight:
  440. pois = gamma_p_derivative(T(k+1), d2, pol)
  441. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  442. * delta / constants::root_two<T>();
  443. BOOST_MATH_INSTRUMENT_VARIABLE(pois);
  444. // Starting beta term:
  445. xterm = x < y
  446. ? ibeta_derivative(T(k + 1), n / 2, x, pol)
  447. : ibeta_derivative(n / 2, T(k + 1), y, pol);
  448. BOOST_MATH_INSTRUMENT_VARIABLE(xterm);
  449. while (fabs(xterm * pois) < tools::min_value<T>())
  450. {
  451. if (k == 0)
  452. return init_val;
  453. k /= 2;
  454. pois = gamma_p_derivative(T(k + 1), d2, pol)
  455. * tgamma_delta_ratio(T(k + 1), T(0.5f))
  456. * delta / constants::root_two<T>();
  457. BOOST_MATH_INSTRUMENT_VARIABLE(pois);
  458. // Starting beta term:
  459. xterm = x < y
  460. ? ibeta_derivative(T(k + 1), n / 2, x, pol)
  461. : ibeta_derivative(n / 2, T(k + 1), y, pol);
  462. BOOST_MATH_INSTRUMENT_VARIABLE(xterm);
  463. }
  464. T poisf(pois), xtermf(xterm);
  465. T sum = init_val;
  466. //
  467. // Backwards recursion first, this is the stable
  468. // direction for recursion:
  469. //
  470. std::uintmax_t count = 0;
  471. T old_ratio = 1; // arbitrary "large" value
  472. for(auto i = k; i >= 0; --i)
  473. {
  474. T term = xterm * pois;
  475. sum += term;
  476. BOOST_MATH_INSTRUMENT_VARIABLE(sum);
  477. T ratio = fabs(term / sum);
  478. if(((ratio < errtol) && (i != k) && (ratio < old_ratio)) || (term == 0))
  479. break;
  480. old_ratio = ratio;
  481. pois *= (i + 0.5f) / d2;
  482. xterm *= (i) / (x * (n / 2 + i));
  483. ++count;
  484. if(count > max_iter)
  485. {
  486. return policies::raise_evaluation_error("pdf(non_central_t_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
  487. }
  488. }
  489. BOOST_MATH_INSTRUMENT_VARIABLE(sum);
  490. old_ratio = 0;
  491. for(auto i = k + 1; ; ++i)
  492. {
  493. poisf *= d2 / (i + 0.5f);
  494. xtermf *= (x * (n / 2 + i)) / (i);
  495. T term = poisf * xtermf;
  496. sum += term;
  497. T ratio = fabs(term / sum);
  498. if(((ratio < errtol) && (ratio < old_ratio)) || (term == 0))
  499. break;
  500. ++count;
  501. old_ratio = ratio;
  502. if(count > max_iter)
  503. {
  504. return policies::raise_evaluation_error("pdf(non_central_t_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
  505. }
  506. }
  507. BOOST_MATH_INSTRUMENT_VARIABLE(sum);
  508. return sum;
  509. }
  510. template <class T, class Policy>
  511. T non_central_t_pdf(T n, T delta, T t, const Policy& pol)
  512. {
  513. BOOST_MATH_STD_USING
  514. if ((boost::math::isinf)(n))
  515. { // Infinite degrees of freedom, so use normal distribution located at delta.
  516. normal_distribution<T, Policy> norm(delta, 1);
  517. return pdf(norm, t);
  518. }
  519. if(t * t < tools::epsilon<T>())
  520. {
  521. //
  522. // Handle this as a special case, using the formula
  523. // from Weisstein, Eric W.
  524. // "Noncentral Student's t-Distribution."
  525. // From MathWorld--A Wolfram Web Resource.
  526. // http://mathworld.wolfram.com/NoncentralStudentst-Distribution.html
  527. //
  528. // The formula is simplified thanks to the relation
  529. // 1F1(a,b,0) = 1.
  530. //
  531. return tgamma_delta_ratio(n / 2 + 0.5f, T(0.5f))
  532. * sqrt(n / constants::pi<T>())
  533. * exp(-delta * delta / 2) / 2;
  534. }
  535. if(fabs(delta / (4 * n)) < policies::get_epsilon<T, Policy>())
  536. {
  537. // Approximate with a Student's T centred on delta,
  538. // the crossover point is based on eq 2.6 from
  539. // "A Comparison of Approximations To Percentiles of the
  540. // Noncentral t-Distribution". H. Sahai and M. M. Ojeda,
  541. // Revista Investigacion Operacional Vol 21, No 2, 2000.
  542. // Original sources referenced in the above are:
  543. // "Some Approximations to the Percentage Points of the Noncentral
  544. // t-Distribution". C. van Eeden. International Statistical Review, 29, 4-31.
  545. // "Continuous Univariate Distributions". N.L. Johnson, S. Kotz and
  546. // N. Balkrishnan. 1995. John Wiley and Sons New York.
  547. return pdf(students_t_distribution<T, Policy>(n), t - delta);
  548. }
  549. //
  550. // Figure out if the hypergeometric formula will be efficient or not,
  551. // based on where the summit of the series.
  552. //
  553. T a = (n + 1) / 2;
  554. T x = delta * delta * t * t / (2 * (t * t + n));
  555. T summit = (sqrt(x * (4 * a + x)) + x) / 2;
  556. if (summit < 40)
  557. return non_central_t_pdf_hypergeometric(t, n, delta, pol);
  558. //
  559. // Otherwise, for t < 0 we have to use the reflection formula:
  560. //
  561. if (t < 0)
  562. {
  563. t = -t;
  564. delta = -delta;
  565. }
  566. //
  567. // x and y are the corresponding random
  568. // variables for the noncentral beta distribution,
  569. // with y = 1 - x:
  570. //
  571. x = t * t / (n + t * t);
  572. T y = n / (n + t * t);
  573. a = 0.5f;
  574. T b = n / 2;
  575. T d2 = delta * delta;
  576. //
  577. // Calculate pdf:
  578. //
  579. T dt = n * t / (n * n + 2 * n * t * t + t * t * t * t);
  580. BOOST_MATH_INSTRUMENT_VARIABLE(dt);
  581. T result = non_central_beta_pdf(a, b, d2, x, y, pol);
  582. BOOST_MATH_INSTRUMENT_VARIABLE(result);
  583. T tol = tools::root_epsilon<T>() * result;
  584. result = non_central_t2_pdf(n, delta, x, y, pol, result);
  585. BOOST_MATH_INSTRUMENT_VARIABLE(result);
  586. result *= dt;
  587. if (result <= tol)
  588. {
  589. // More than half the digits in the result have cancelled,
  590. // Try direct integration... super slow but reliable as far as we can tell...
  591. if (delta < 0)
  592. {
  593. // reflect back:
  594. delta = -delta;
  595. t = -t;
  596. }
  597. result = non_central_t_pdf_integral(t, n, delta, pol);
  598. }
  599. return result;
  600. }
  601. template <class T, class Policy>
  602. T mean(T v, T delta, const Policy& pol)
  603. {
  604. if ((boost::math::isinf)(v))
  605. {
  606. return delta;
  607. }
  608. BOOST_MATH_STD_USING
  609. if (v > 1 / boost::math::tools::epsilon<T>() )
  610. {
  611. //normal_distribution<T, Policy> n(delta, 1);
  612. //return boost::math::mean(n);
  613. return delta;
  614. }
  615. else
  616. {
  617. return delta * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, T(0.5f), pol);
  618. }
  619. // Other moments use mean so using normal distribution is propagated.
  620. }
  621. template <class T, class Policy>
  622. T variance(T v, T delta, const Policy& pol)
  623. {
  624. if ((boost::math::isinf)(v))
  625. {
  626. return 1;
  627. }
  628. if (delta == 0)
  629. { // == Student's t
  630. return v / (v - 2);
  631. }
  632. T result = ((delta * delta + 1) * v) / (v - 2);
  633. T m = mean(v, delta, pol);
  634. result -= m * m;
  635. return result;
  636. }
  637. template <class T, class Policy>
  638. T skewness(T v, T delta, const Policy& pol)
  639. {
  640. BOOST_MATH_STD_USING
  641. if ((boost::math::isinf)(v))
  642. {
  643. return 0;
  644. }
  645. if(delta == 0)
  646. { // == Student's t
  647. return 0;
  648. }
  649. T mean = boost::math::detail::mean(v, delta, pol);
  650. T l2 = delta * delta;
  651. T var = ((l2 + 1) * v) / (v - 2) - mean * mean;
  652. T result = -2 * var;
  653. result += v * (l2 + 2 * v - 3) / ((v - 3) * (v - 2));
  654. result *= mean;
  655. result /= pow(var, T(1.5f));
  656. return result;
  657. }
  658. template <class T, class Policy>
  659. T kurtosis_excess(T v, T delta, const Policy& pol)
  660. {
  661. BOOST_MATH_STD_USING
  662. if ((boost::math::isinf)(v))
  663. {
  664. return 1;
  665. }
  666. if (delta == 0)
  667. { // == Student's t
  668. return 1;
  669. }
  670. T mean = boost::math::detail::mean(v, delta, pol);
  671. T l2 = delta * delta;
  672. T var = ((l2 + 1) * v) / (v - 2) - mean * mean;
  673. T result = -3 * var;
  674. result += v * (l2 * (v + 1) + 3 * (3 * v - 5)) / ((v - 3) * (v - 2));
  675. result *= -mean * mean;
  676. result += v * v * (l2 * l2 + 6 * l2 + 3) / ((v - 4) * (v - 2));
  677. result /= var * var;
  678. result -= static_cast<T>(3);
  679. return result;
  680. }
  681. #if 0
  682. //
  683. // This code is disabled, since there can be multiple answers to the
  684. // question, and it's not clear how to find the "right" one.
  685. //
  686. template <class RealType, class Policy>
  687. struct t_degrees_of_freedom_finder
  688. {
  689. t_degrees_of_freedom_finder(
  690. RealType delta_, RealType x_, RealType p_, bool c)
  691. : delta(delta_), x(x_), p(p_), comp(c) {}
  692. RealType operator()(const RealType& v)
  693. {
  694. non_central_t_distribution<RealType, Policy> d(v, delta);
  695. return comp ?
  696. p - cdf(complement(d, x))
  697. : cdf(d, x) - p;
  698. }
  699. private:
  700. RealType delta;
  701. RealType x;
  702. RealType p;
  703. bool comp;
  704. };
  705. template <class RealType, class Policy>
  706. inline RealType find_t_degrees_of_freedom(
  707. RealType delta, RealType x, RealType p, RealType q, const Policy& pol)
  708. {
  709. const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
  710. if((p == 0) || (q == 0))
  711. {
  712. //
  713. // Can't a thing if one of p and q is zero:
  714. //
  715. return policies::raise_evaluation_error<RealType>(function, "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%", // LCOV_EXCL_LINE
  716. RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
  717. }
  718. t_degrees_of_freedom_finder<RealType, Policy> f(delta, x, p < q ? p : q, p < q ? false : true);
  719. tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
  720. std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
  721. //
  722. // Pick an initial guess:
  723. //
  724. RealType guess = 200;
  725. std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
  726. f, guess, RealType(2), false, tol, max_iter, pol);
  727. RealType result = ir.first + (ir.second - ir.first) / 2;
  728. if(max_iter >= policies::get_max_root_iterations<Policy>())
  729. {
  730. return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
  731. " or there is no answer to problem. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE
  732. }
  733. return result;
  734. }
  735. template <class RealType, class Policy>
  736. struct t_non_centrality_finder
  737. {
  738. t_non_centrality_finder(
  739. RealType v_, RealType x_, RealType p_, bool c)
  740. : v(v_), x(x_), p(p_), comp(c) {}
  741. RealType operator()(const RealType& delta)
  742. {
  743. non_central_t_distribution<RealType, Policy> d(v, delta);
  744. return comp ?
  745. p - cdf(complement(d, x))
  746. : cdf(d, x) - p;
  747. }
  748. private:
  749. RealType v;
  750. RealType x;
  751. RealType p;
  752. bool comp;
  753. };
  754. template <class RealType, class Policy>
  755. inline RealType find_t_non_centrality(
  756. RealType v, RealType x, RealType p, RealType q, const Policy& pol)
  757. {
  758. const char* function = "non_central_t<%1%>::find_t_non_centrality";
  759. if((p == 0) || (q == 0))
  760. {
  761. //
  762. // Can't do a thing if one of p and q is zero:
  763. //
  764. return policies::raise_evaluation_error<RealType>(function, "Can't find non-centrality parameter when the probability is 0 or 1, only possible answer is %1%", // LCOV_EXCL_LINE
  765. RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
  766. }
  767. t_non_centrality_finder<RealType, Policy> f(v, x, p < q ? p : q, p < q ? false : true);
  768. tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
  769. std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
  770. //
  771. // Pick an initial guess that we know is the right side of
  772. // zero:
  773. //
  774. RealType guess;
  775. if(f(0) < 0)
  776. guess = 1;
  777. else
  778. guess = -1;
  779. std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
  780. f, guess, RealType(2), false, tol, max_iter, pol);
  781. RealType result = ir.first + (ir.second - ir.first) / 2;
  782. if(max_iter >= policies::get_max_root_iterations<Policy>())
  783. {
  784. return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
  785. " or there is no answer to problem. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE
  786. }
  787. return result;
  788. }
  789. #endif
  790. } // namespace detail ======================================================================
  791. template <class RealType = double, class Policy = policies::policy<> >
  792. class non_central_t_distribution
  793. {
  794. public:
  795. typedef RealType value_type;
  796. typedef Policy policy_type;
  797. non_central_t_distribution(RealType v_, RealType lambda) : v(v_), ncp(lambda)
  798. {
  799. const char* function = "boost::math::non_central_t_distribution<%1%>::non_central_t_distribution(%1%,%1%)";
  800. RealType r;
  801. detail::check_df_gt0_to_inf(
  802. function,
  803. v, &r, Policy());
  804. detail::check_non_centrality(
  805. function,
  806. static_cast<value_type>(lambda * lambda),
  807. &r,
  808. Policy());
  809. } // non_central_t_distribution constructor.
  810. RealType degrees_of_freedom() const
  811. { // Private data getter function.
  812. return v;
  813. }
  814. RealType non_centrality() const
  815. { // Private data getter function.
  816. return ncp;
  817. }
  818. #if 0
  819. //
  820. // This code is disabled, since there can be multiple answers to the
  821. // question, and it's not clear how to find the "right" one.
  822. //
  823. static RealType find_degrees_of_freedom(RealType delta, RealType x, RealType p)
  824. {
  825. const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
  826. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  827. typedef typename policies::normalise<
  828. Policy,
  829. policies::promote_float<false>,
  830. policies::promote_double<false>,
  831. policies::discrete_quantile<>,
  832. policies::assert_undefined<> >::type forwarding_policy;
  833. value_type result = detail::find_t_degrees_of_freedom(
  834. static_cast<value_type>(delta),
  835. static_cast<value_type>(x),
  836. static_cast<value_type>(p),
  837. static_cast<value_type>(1-p),
  838. forwarding_policy());
  839. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  840. result,
  841. function);
  842. }
  843. template <class A, class B, class C>
  844. static RealType find_degrees_of_freedom(const complemented3_type<A,B,C>& c)
  845. {
  846. const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
  847. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  848. typedef typename policies::normalise<
  849. Policy,
  850. policies::promote_float<false>,
  851. policies::promote_double<false>,
  852. policies::discrete_quantile<>,
  853. policies::assert_undefined<> >::type forwarding_policy;
  854. value_type result = detail::find_t_degrees_of_freedom(
  855. static_cast<value_type>(c.dist),
  856. static_cast<value_type>(c.param1),
  857. static_cast<value_type>(1-c.param2),
  858. static_cast<value_type>(c.param2),
  859. forwarding_policy());
  860. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  861. result,
  862. function);
  863. }
  864. static RealType find_non_centrality(RealType v, RealType x, RealType p)
  865. {
  866. const char* function = "non_central_t<%1%>::find_t_non_centrality";
  867. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  868. typedef typename policies::normalise<
  869. Policy,
  870. policies::promote_float<false>,
  871. policies::promote_double<false>,
  872. policies::discrete_quantile<>,
  873. policies::assert_undefined<> >::type forwarding_policy;
  874. value_type result = detail::find_t_non_centrality(
  875. static_cast<value_type>(v),
  876. static_cast<value_type>(x),
  877. static_cast<value_type>(p),
  878. static_cast<value_type>(1-p),
  879. forwarding_policy());
  880. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  881. result,
  882. function);
  883. }
  884. template <class A, class B, class C>
  885. static RealType find_non_centrality(const complemented3_type<A,B,C>& c)
  886. {
  887. const char* function = "non_central_t<%1%>::find_t_non_centrality";
  888. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  889. typedef typename policies::normalise<
  890. Policy,
  891. policies::promote_float<false>,
  892. policies::promote_double<false>,
  893. policies::discrete_quantile<>,
  894. policies::assert_undefined<> >::type forwarding_policy;
  895. value_type result = detail::find_t_non_centrality(
  896. static_cast<value_type>(c.dist),
  897. static_cast<value_type>(c.param1),
  898. static_cast<value_type>(1-c.param2),
  899. static_cast<value_type>(c.param2),
  900. forwarding_policy());
  901. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  902. result,
  903. function);
  904. }
  905. #endif
  906. private:
  907. // Data member, initialized by constructor.
  908. RealType v; // degrees of freedom
  909. RealType ncp; // non-centrality parameter
  910. }; // template <class RealType, class Policy> class non_central_t_distribution
  911. typedef non_central_t_distribution<double> non_central_t; // Reserved name of type double.
  912. #ifdef __cpp_deduction_guides
  913. template <class RealType>
  914. non_central_t_distribution(RealType,RealType)->non_central_t_distribution<typename boost::math::tools::promote_args<RealType>::type>;
  915. #endif
  916. // Non-member functions to give properties of the distribution.
  917. template <class RealType, class Policy>
  918. inline const std::pair<RealType, RealType> range(const non_central_t_distribution<RealType, Policy>& /* dist */)
  919. { // Range of permissible values for random variable k.
  920. using boost::math::tools::max_value;
  921. return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
  922. }
  923. template <class RealType, class Policy>
  924. inline const std::pair<RealType, RealType> support(const non_central_t_distribution<RealType, Policy>& /* dist */)
  925. { // Range of supported values for random variable k.
  926. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  927. using boost::math::tools::max_value;
  928. return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
  929. }
  930. template <class RealType, class Policy>
  931. inline RealType mode(const non_central_t_distribution<RealType, Policy>& dist)
  932. { // mode.
  933. static const char* function = "mode(non_central_t_distribution<%1%> const&)";
  934. RealType v = dist.degrees_of_freedom();
  935. RealType l = dist.non_centrality();
  936. RealType r;
  937. if(!detail::check_df_gt0_to_inf(
  938. function,
  939. v, &r, Policy())
  940. ||
  941. !detail::check_non_centrality(
  942. function,
  943. static_cast<RealType>(l * l),
  944. &r,
  945. Policy()))
  946. return static_cast<RealType>(r);
  947. BOOST_MATH_STD_USING
  948. RealType m = v < 3 ? 0 : detail::mean(v, l, Policy());
  949. RealType var = v < 4 ? 1 : detail::variance(v, l, Policy());
  950. return detail::generic_find_mode(
  951. dist,
  952. m,
  953. function,
  954. sqrt(var));
  955. }
  956. template <class RealType, class Policy>
  957. inline RealType mean(const non_central_t_distribution<RealType, Policy>& dist)
  958. {
  959. BOOST_MATH_STD_USING
  960. const char* function = "mean(const non_central_t_distribution<%1%>&)";
  961. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  962. typedef typename policies::normalise<
  963. Policy,
  964. policies::promote_float<false>,
  965. policies::promote_double<false>,
  966. policies::discrete_quantile<>,
  967. policies::assert_undefined<> >::type forwarding_policy;
  968. RealType v = dist.degrees_of_freedom();
  969. RealType l = dist.non_centrality();
  970. RealType r;
  971. if(!detail::check_df_gt0_to_inf(
  972. function,
  973. v, &r, Policy())
  974. ||
  975. !detail::check_non_centrality(
  976. function,
  977. static_cast<RealType>(l * l),
  978. &r,
  979. Policy()))
  980. return static_cast<RealType>(r);
  981. if(v <= 1)
  982. return policies::raise_domain_error<RealType>(
  983. function,
  984. "The non-central t distribution has no defined mean for degrees of freedom <= 1: got v=%1%.", v, Policy());
  985. // return l * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, RealType(0.5f));
  986. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  987. detail::mean(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
  988. } // mean
  989. template <class RealType, class Policy>
  990. inline RealType variance(const non_central_t_distribution<RealType, Policy>& dist)
  991. { // variance.
  992. const char* function = "variance(const non_central_t_distribution<%1%>&)";
  993. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  994. typedef typename policies::normalise<
  995. Policy,
  996. policies::promote_float<false>,
  997. policies::promote_double<false>,
  998. policies::discrete_quantile<>,
  999. policies::assert_undefined<> >::type forwarding_policy;
  1000. BOOST_MATH_STD_USING
  1001. RealType v = dist.degrees_of_freedom();
  1002. RealType l = dist.non_centrality();
  1003. RealType r;
  1004. if(!detail::check_df_gt0_to_inf(
  1005. function,
  1006. v, &r, Policy())
  1007. ||
  1008. !detail::check_non_centrality(
  1009. function,
  1010. static_cast<RealType>(l * l),
  1011. &r,
  1012. Policy()))
  1013. return static_cast<RealType>(r);
  1014. if(v <= 2)
  1015. return policies::raise_domain_error<RealType>(
  1016. function,
  1017. "The non-central t distribution has no defined variance for degrees of freedom <= 2: got v=%1%.", v, Policy());
  1018. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1019. detail::variance(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
  1020. }
  1021. // RealType standard_deviation(const non_central_t_distribution<RealType, Policy>& dist)
  1022. // standard_deviation provided by derived accessors.
  1023. template <class RealType, class Policy>
  1024. inline RealType skewness(const non_central_t_distribution<RealType, Policy>& dist)
  1025. { // skewness = sqrt(l).
  1026. const char* function = "skewness(const non_central_t_distribution<%1%>&)";
  1027. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1028. typedef typename policies::normalise<
  1029. Policy,
  1030. policies::promote_float<false>,
  1031. policies::promote_double<false>,
  1032. policies::discrete_quantile<>,
  1033. policies::assert_undefined<> >::type forwarding_policy;
  1034. RealType v = dist.degrees_of_freedom();
  1035. RealType l = dist.non_centrality();
  1036. RealType r;
  1037. if(!detail::check_df_gt0_to_inf(
  1038. function,
  1039. v, &r, Policy())
  1040. ||
  1041. !detail::check_non_centrality(
  1042. function,
  1043. static_cast<RealType>(l * l),
  1044. &r,
  1045. Policy()))
  1046. return static_cast<RealType>(r);
  1047. if(v <= 3)
  1048. return policies::raise_domain_error<RealType>(
  1049. function,
  1050. "The non-central t distribution has no defined skewness for degrees of freedom <= 3: got v=%1%.", v, Policy());;
  1051. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1052. detail::skewness(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
  1053. }
  1054. template <class RealType, class Policy>
  1055. inline RealType kurtosis_excess(const non_central_t_distribution<RealType, Policy>& dist)
  1056. {
  1057. const char* function = "kurtosis_excess(const non_central_t_distribution<%1%>&)";
  1058. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1059. typedef typename policies::normalise<
  1060. Policy,
  1061. policies::promote_float<false>,
  1062. policies::promote_double<false>,
  1063. policies::discrete_quantile<>,
  1064. policies::assert_undefined<> >::type forwarding_policy;
  1065. RealType v = dist.degrees_of_freedom();
  1066. RealType l = dist.non_centrality();
  1067. RealType r;
  1068. if(!detail::check_df_gt0_to_inf(
  1069. function,
  1070. v, &r, Policy())
  1071. ||
  1072. !detail::check_non_centrality(
  1073. function,
  1074. static_cast<RealType>(l * l),
  1075. &r,
  1076. Policy()))
  1077. return static_cast<RealType>(r);
  1078. if(v <= 4)
  1079. return policies::raise_domain_error<RealType>(
  1080. function,
  1081. "The non-central t distribution has no defined kurtosis for degrees of freedom <= 4: got v=%1%.", v, Policy());;
  1082. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1083. detail::kurtosis_excess(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
  1084. } // kurtosis_excess
  1085. template <class RealType, class Policy>
  1086. inline RealType kurtosis(const non_central_t_distribution<RealType, Policy>& dist)
  1087. {
  1088. return kurtosis_excess(dist) + 3;
  1089. }
  1090. template <class RealType, class Policy>
  1091. inline RealType pdf(const non_central_t_distribution<RealType, Policy>& dist, const RealType& t)
  1092. { // Probability Density/Mass Function.
  1093. const char* function = "pdf(non_central_t_distribution<%1%>, %1%)";
  1094. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1095. typedef typename policies::normalise<
  1096. Policy,
  1097. policies::promote_float<false>,
  1098. policies::promote_double<false>,
  1099. policies::discrete_quantile<>,
  1100. policies::assert_undefined<> >::type forwarding_policy;
  1101. RealType v = dist.degrees_of_freedom();
  1102. RealType l = dist.non_centrality();
  1103. RealType r;
  1104. if(!detail::check_df_gt0_to_inf(
  1105. function,
  1106. v, &r, Policy())
  1107. ||
  1108. !detail::check_non_centrality(
  1109. function,
  1110. static_cast<RealType>(l * l), // we need l^2 to be countable.
  1111. &r,
  1112. Policy())
  1113. ||
  1114. !detail::check_x(
  1115. function,
  1116. t,
  1117. &r,
  1118. Policy()))
  1119. return static_cast<RealType>(r);
  1120. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1121. detail::non_central_t_pdf(static_cast<value_type>(v),
  1122. static_cast<value_type>(l),
  1123. static_cast<value_type>(t),
  1124. Policy()),
  1125. function);
  1126. } // pdf
  1127. template <class RealType, class Policy>
  1128. RealType cdf(const non_central_t_distribution<RealType, Policy>& dist, const RealType& x)
  1129. {
  1130. const char* function = "boost::math::cdf(non_central_t_distribution<%1%>&, %1%)";
  1131. // was const char* function = "boost::math::non_central_t_distribution<%1%>::cdf(%1%)";
  1132. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1133. typedef typename policies::normalise<
  1134. Policy,
  1135. policies::promote_float<false>,
  1136. policies::promote_double<false>,
  1137. policies::discrete_quantile<>,
  1138. policies::assert_undefined<> >::type forwarding_policy;
  1139. RealType v = dist.degrees_of_freedom();
  1140. RealType l = dist.non_centrality();
  1141. RealType r;
  1142. if(!detail::check_df_gt0_to_inf(
  1143. function,
  1144. v, &r, Policy())
  1145. ||
  1146. !detail::check_non_centrality(
  1147. function,
  1148. static_cast<RealType>(l * l),
  1149. &r,
  1150. Policy())
  1151. ||
  1152. !detail::check_x(
  1153. function,
  1154. x,
  1155. &r,
  1156. Policy()))
  1157. return static_cast<RealType>(r);
  1158. if ((boost::math::isinf)(v))
  1159. { // Infinite degrees of freedom, so use normal distribution located at delta.
  1160. normal_distribution<RealType, Policy> n(l, 1);
  1161. cdf(n, x);
  1162. //return cdf(normal_distribution<RealType, Policy>(l, 1), x);
  1163. }
  1164. if(l == 0)
  1165. { // NO non-centrality, so use Student's t instead.
  1166. return cdf(students_t_distribution<RealType, Policy>(v), x);
  1167. }
  1168. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1169. detail::non_central_t_cdf(
  1170. static_cast<value_type>(v),
  1171. static_cast<value_type>(l),
  1172. static_cast<value_type>(x),
  1173. false, Policy()),
  1174. function);
  1175. } // cdf
  1176. template <class RealType, class Policy>
  1177. RealType cdf(const complemented2_type<non_central_t_distribution<RealType, Policy>, RealType>& c)
  1178. { // Complemented Cumulative Distribution Function
  1179. // was const char* function = "boost::math::non_central_t_distribution<%1%>::cdf(%1%)";
  1180. const char* function = "boost::math::cdf(const complement(non_central_t_distribution<%1%>&), %1%)";
  1181. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  1182. typedef typename policies::normalise<
  1183. Policy,
  1184. policies::promote_float<false>,
  1185. policies::promote_double<false>,
  1186. policies::discrete_quantile<>,
  1187. policies::assert_undefined<> >::type forwarding_policy;
  1188. non_central_t_distribution<RealType, Policy> const& dist = c.dist;
  1189. RealType x = c.param;
  1190. RealType v = dist.degrees_of_freedom();
  1191. RealType l = dist.non_centrality(); // aka delta
  1192. RealType r;
  1193. if(!detail::check_df_gt0_to_inf(
  1194. function,
  1195. v, &r, Policy())
  1196. ||
  1197. !detail::check_non_centrality(
  1198. function,
  1199. static_cast<RealType>(l * l),
  1200. &r,
  1201. Policy())
  1202. ||
  1203. !detail::check_x(
  1204. function,
  1205. x,
  1206. &r,
  1207. Policy()))
  1208. return static_cast<RealType>(r);
  1209. if ((boost::math::isinf)(v))
  1210. { // Infinite degrees of freedom, so use normal distribution located at delta.
  1211. normal_distribution<RealType, Policy> n(l, 1);
  1212. return cdf(complement(n, x));
  1213. }
  1214. if(l == 0)
  1215. { // zero non-centrality so use Student's t distribution.
  1216. return cdf(complement(students_t_distribution<RealType, Policy>(v), x));
  1217. }
  1218. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  1219. detail::non_central_t_cdf(
  1220. static_cast<value_type>(v),
  1221. static_cast<value_type>(l),
  1222. static_cast<value_type>(x),
  1223. true, Policy()),
  1224. function);
  1225. } // ccdf
  1226. template <class RealType, class Policy>
  1227. inline RealType quantile(const non_central_t_distribution<RealType, Policy>& dist, const RealType& p)
  1228. { // Quantile (or Percent Point) function.
  1229. static const char* function = "quantile(const non_central_t_distribution<%1%>, %1%)";
  1230. RealType v = dist.degrees_of_freedom();
  1231. RealType l = dist.non_centrality();
  1232. return detail::non_central_t_quantile(function, v, l, p, RealType(1-p), Policy());
  1233. } // quantile
  1234. template <class RealType, class Policy>
  1235. inline RealType quantile(const complemented2_type<non_central_t_distribution<RealType, Policy>, RealType>& c)
  1236. { // Quantile (or Percent Point) function.
  1237. static const char* function = "quantile(const complement(non_central_t_distribution<%1%>, %1%))";
  1238. non_central_t_distribution<RealType, Policy> const& dist = c.dist;
  1239. RealType q = c.param;
  1240. RealType v = dist.degrees_of_freedom();
  1241. RealType l = dist.non_centrality();
  1242. return detail::non_central_t_quantile(function, v, l, RealType(1-q), q, Policy());
  1243. } // quantile complement.
  1244. } // namespace math
  1245. } // namespace boost
  1246. // This include must be at the end, *after* the accessors
  1247. // for this distribution have been defined, in order to
  1248. // keep compilers that support two-phase lookup happy.
  1249. #include <boost/math/distributions/detail/derived_accessors.hpp>
  1250. #endif // BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP