non_central_t.hpp 47 KB

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