Special.cs 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421
  1. namespace VisualMath.Accord.Math
  2. {
  3. using System;
  4. /// <summary>
  5. /// Set of special mathematic functions.
  6. /// </summary>
  7. /// <remarks>
  8. /// References:
  9. /// <list type="bullet">
  10. /// <item><description>
  11. /// Numerical Recipes in C, 2nd Edition (1992)
  12. /// </description></item>
  13. /// <item><description>
  14. /// Cephes Math Library, http://www.netlib.org/cephes/
  15. /// </description></item>
  16. /// </list>
  17. /// </remarks>
  18. public static class Special
  19. {
  20. #region Constants
  21. /// <summary>Double-precision machine roundoff error.</summary>
  22. /// <remarks>This value is actually different from Double.Epsilon.</remarks>
  23. public const double DoubleEpsilon = 1.11022302462515654042E-16;
  24. /// <summary>Single-precision machine roundoff error.</summary>
  25. /// <remarks>This value is actually different from Single.Epsilon.</remarks>
  26. public const float SingleEpsilon = 1.1920929E-07f;
  27. /// <summary>Maximum log on the machine.</summary>
  28. public const double LogMax = 7.09782712893383996732E2;
  29. /// <summary>Minimum log on the machine.</summary>
  30. public const double LogMin = -7.451332191019412076235E2;
  31. /// <summary>Maximum gamma on the machine.</summary>
  32. public const double GammaMax = 171.624376956302725;
  33. /// <summary>Log of number PI.</summary>
  34. public const double LogPI = 1.14472988584940017414;
  35. /// <summary>Square root of number PI.</summary>
  36. public const double SqrtPI = 2.50662827463100050242E0;
  37. /// <summary>Square root of 2.</summary>
  38. public const double Sqrt2 = 1.4142135623730950488016887;
  39. /// <summary>Half square root of 2.</summary>
  40. public const double SqrtH = 7.07106781186547524401E-1;
  41. #endregion
  42. /// <summary>
  43. /// Gamma function of the specified value.
  44. /// </summary>
  45. public static double Gamma(double x)
  46. {
  47. double[] P = {
  48. 1.60119522476751861407E-4,
  49. 1.19135147006586384913E-3,
  50. 1.04213797561761569935E-2,
  51. 4.76367800457137231464E-2,
  52. 2.07448227648435975150E-1,
  53. 4.94214826801497100753E-1,
  54. 9.99999999999999996796E-1
  55. };
  56. double[] Q = {
  57. -2.31581873324120129819E-5,
  58. 5.39605580493303397842E-4,
  59. -4.45641913851797240494E-3,
  60. 1.18139785222060435552E-2,
  61. 3.58236398605498653373E-2,
  62. -2.34591795718243348568E-1,
  63. 7.14304917030273074085E-2,
  64. 1.00000000000000000320E0
  65. };
  66. double p, z;
  67. double q = System.Math.Abs(x);
  68. if (q > 33.0)
  69. {
  70. if (x < 0.0)
  71. {
  72. p = System.Math.Floor(q);
  73. if (p == q)
  74. throw new OverflowException();
  75. z = q - p;
  76. if (z > 0.5)
  77. {
  78. p += 1.0;
  79. z = q - p;
  80. }
  81. z = q * System.Math.Sin(System.Math.PI * z);
  82. if (z == 0.0)
  83. throw new OverflowException();
  84. z = System.Math.Abs(z);
  85. z = System.Math.PI / (z * Stirf(q));
  86. return -z;
  87. }
  88. else
  89. {
  90. return Stirf(x);
  91. }
  92. }
  93. z = 1.0;
  94. while (x >= 3.0)
  95. {
  96. x -= 1.0;
  97. z *= x;
  98. }
  99. while (x < 0.0)
  100. {
  101. if (x == 0.0)
  102. {
  103. throw new ArithmeticException();
  104. }
  105. else if (x > -1.0E-9)
  106. {
  107. return (z / ((1.0 + 0.5772156649015329 * x) * x));
  108. }
  109. z /= x;
  110. x += 1.0;
  111. }
  112. while (x < 2.0)
  113. {
  114. if (x == 0.0)
  115. {
  116. throw new ArithmeticException();
  117. }
  118. else if (x < 1.0E-9)
  119. {
  120. return (z / ((1.0 + 0.5772156649015329 * x) * x));
  121. }
  122. z /= x;
  123. x += 1.0;
  124. }
  125. if ((x == 2.0) || (x == 3.0)) return z;
  126. x -= 2.0;
  127. p = Polevl(x, P, 6);
  128. q = Polevl(x, Q, 7);
  129. return z * p / q;
  130. }
  131. /// <summary>
  132. /// Regularized Gamma function (P)
  133. /// </summary>
  134. public static double Rgamma(double a, double z)
  135. {
  136. return Igam(a, z) / Gamma(a);
  137. }
  138. /// <summary>
  139. /// Digamma function.
  140. /// </summary>
  141. public static double Digamma(double x)
  142. {
  143. double s = 0;
  144. double w = 0;
  145. double y = 0;
  146. double z = 0;
  147. double nz = 0;
  148. bool negative = false;
  149. if (x <= 0.0)
  150. {
  151. negative = true;
  152. double q = x;
  153. double p = (int)System.Math.Floor(q);
  154. if (p == q)
  155. throw new OverflowException("Function computation resulted in arithmetic overflow.");
  156. nz = q - p;
  157. if (nz != 0.5)
  158. {
  159. if (nz > 0.5)
  160. {
  161. p = p + 1.0;
  162. nz = q - p;
  163. }
  164. nz = System.Math.PI / System.Math.Tan(System.Math.PI * nz);
  165. }
  166. else
  167. {
  168. nz = 0.0;
  169. }
  170. x = 1.0 - x;
  171. }
  172. if (x <= 10.0 & x == System.Math.Floor(x))
  173. {
  174. y = 0.0;
  175. int n = (int)System.Math.Floor(x);
  176. for (int i = 1; i <= n - 1; i++)
  177. {
  178. w = i;
  179. y = y + 1.0 / w;
  180. }
  181. y = y - 0.57721566490153286061;
  182. }
  183. else
  184. {
  185. s = x;
  186. w = 0.0;
  187. while (s < 10.0)
  188. {
  189. w = w + 1.0 / s;
  190. s = s + 1.0;
  191. }
  192. if (s < 1.0E17)
  193. {
  194. z = 1.0 / (s * s);
  195. double polv = 8.33333333333333333333E-2;
  196. polv = polv * z - 2.10927960927960927961E-2;
  197. polv = polv * z + 7.57575757575757575758E-3;
  198. polv = polv * z - 4.16666666666666666667E-3;
  199. polv = polv * z + 3.96825396825396825397E-3;
  200. polv = polv * z - 8.33333333333333333333E-3;
  201. polv = polv * z + 8.33333333333333333333E-2;
  202. y = z * polv;
  203. }
  204. else
  205. {
  206. y = 0.0;
  207. }
  208. y = System.Math.Log(s) - 0.5 / s - y - w;
  209. }
  210. if (negative == true)
  211. {
  212. y = y - nz;
  213. }
  214. return y;
  215. }
  216. /// <summary>
  217. /// Gamma function as computed by Stirling's formula.
  218. /// </summary>
  219. public static double Stirf(double x)
  220. {
  221. double[] STIR = {
  222. 7.87311395793093628397E-4,
  223. -2.29549961613378126380E-4,
  224. -2.68132617805781232825E-3,
  225. 3.47222221605458667310E-3,
  226. 8.33333333333482257126E-2,
  227. };
  228. double MAXSTIR = 143.01608;
  229. double w = 1.0 / x;
  230. double y = System.Math.Exp(x);
  231. w = 1.0 + w * Polevl(w, STIR, 4);
  232. if (x > MAXSTIR)
  233. {
  234. double v = System.Math.Pow(x, 0.5 * x - 0.25);
  235. y = v * (v / y);
  236. }
  237. else
  238. {
  239. y = System.Math.Pow(x, x - 0.5) / y;
  240. }
  241. y = SqrtPI * y * w;
  242. return y;
  243. }
  244. /// <summary>
  245. /// Complemented incomplete gamma function.
  246. /// </summary>
  247. public static double Igamc(double a, double x)
  248. {
  249. double big = 4.503599627370496e15;
  250. double biginv = 2.22044604925031308085e-16;
  251. double ans, ax, c, yc, r, t, y, z;
  252. double pk, pkm1, pkm2, qk, qkm1, qkm2;
  253. if (x <= 0 || a <= 0) return 1.0;
  254. if (x < 1.0 || x < a) return 1.0 - Igam(a, x);
  255. ax = a * System.Math.Log(x) - x - Lgamma(a);
  256. if (ax < -LogMax) return 0.0;
  257. ax = System.Math.Exp(ax);
  258. /* continued fraction */
  259. y = 1.0 - a;
  260. z = x + y + 1.0;
  261. c = 0.0;
  262. pkm2 = 1.0;
  263. qkm2 = x;
  264. pkm1 = x + 1.0;
  265. qkm1 = z * x;
  266. ans = pkm1 / qkm1;
  267. do
  268. {
  269. c += 1.0;
  270. y += 1.0;
  271. z += 2.0;
  272. yc = y * c;
  273. pk = pkm1 * z - pkm2 * yc;
  274. qk = qkm1 * z - qkm2 * yc;
  275. if (qk != 0)
  276. {
  277. r = pk / qk;
  278. t = System.Math.Abs((ans - r) / r);
  279. ans = r;
  280. }
  281. else
  282. t = 1.0;
  283. pkm2 = pkm1;
  284. pkm1 = pk;
  285. qkm2 = qkm1;
  286. qkm1 = qk;
  287. if (System.Math.Abs(pk) > big)
  288. {
  289. pkm2 *= biginv;
  290. pkm1 *= biginv;
  291. qkm2 *= biginv;
  292. qkm1 *= biginv;
  293. }
  294. } while (t > DoubleEpsilon);
  295. return ans * ax;
  296. }
  297. /// <summary>
  298. /// Incomplete gamma function.
  299. /// </summary>
  300. public static double Igam(double a, double x)
  301. {
  302. double ans, ax, c, r;
  303. if (x <= 0 || a <= 0) return 0.0;
  304. if (x > 1.0 && x > a) return 1.0 - Igamc(a, x);
  305. ax = a * System.Math.Log(x) - x - Lgamma(a);
  306. if (ax < -LogMax) return (0.0);
  307. ax = System.Math.Exp(ax);
  308. r = a;
  309. c = 1.0;
  310. ans = 1.0;
  311. do
  312. {
  313. r += 1.0;
  314. c *= x / r;
  315. ans += c;
  316. } while (c / ans > DoubleEpsilon);
  317. return (ans * ax / a);
  318. }
  319. /// <summary>
  320. /// Chi-square function (left hand tail).
  321. /// </summary>
  322. /// <remarks>
  323. /// Returns the area under the left hand tail (from 0 to x)
  324. /// of the Chi square probability density function with
  325. /// df degrees of freedom.
  326. /// </remarks>
  327. /// <param name="df">degrees of freedom</param>
  328. /// <param name="x">double value</param>
  329. /// <returns></returns>
  330. public static double ChiSq(double df, double x)
  331. {
  332. if (x < 0.0 || df < 1.0) return 0.0;
  333. return Igam(df / 2.0, x / 2.0);
  334. }
  335. /// <summary>
  336. /// Chi-square function (right hand tail).
  337. /// </summary>
  338. /// <remarks>
  339. /// Returns the area under the right hand tail (from x to
  340. /// infinity) of the Chi square probability density function
  341. /// with df degrees of freedom:
  342. /// </remarks>
  343. /// <param name="df">degrees of freedom</param>
  344. /// <param name="x">double value</param>
  345. /// <returns></returns>
  346. public static double ChiSqc(double df, double x)
  347. {
  348. if (x < 0.0 || df < 1.0) return 0.0;
  349. return Igamc(df / 2.0, x / 2.0);
  350. }
  351. /// <summary>
  352. /// Sum of the first k terms of the Poisson distribution.
  353. /// </summary>
  354. /// <param name="k">number of terms</param>
  355. /// <param name="x">double value</param>
  356. /// <returns></returns>
  357. public static double Poisson(int k, double x)
  358. {
  359. if (k < 0 || x < 0) return 0.0;
  360. return Igamc((double)(k + 1), x);
  361. }
  362. /// <summary>
  363. /// Sum of the terms k+1 to infinity of the Poisson distribution.
  364. /// </summary>
  365. /// <param name="k">start</param>
  366. /// <param name="x">double value</param>
  367. /// <returns></returns>
  368. public static double Poissonc(int k, double x)
  369. {
  370. if (k < 0 || x < 0) return 0.0;
  371. return Igam((double)(k + 1), x);
  372. }
  373. /// <summary>
  374. /// Area under the Gaussian probability density function,
  375. /// integrated from minus infinity to the given value.
  376. /// </summary>
  377. /// <returns>
  378. /// The area under the Gaussian p.d.f. integrated
  379. /// from minus infinity to the given value.
  380. /// </returns>
  381. public static double Normal(double value)
  382. {
  383. double x, y, z;
  384. x = value * SqrtH;
  385. z = System.Math.Abs(x);
  386. if (z < SqrtH) y = 0.5 + 0.5 * Erf(x);
  387. else
  388. {
  389. y = 0.5 * Erfc(z);
  390. if (x > 0) y = 1.0 - y;
  391. }
  392. return y;
  393. }
  394. /// <summary>
  395. /// Complementary error function of the specified value.
  396. /// </summary>
  397. /// <remarks>
  398. /// http://mathworld.wolfram.com/Erfc.html
  399. /// </remarks>
  400. public static double Erfc(double value)
  401. {
  402. double x, y, z, p, q;
  403. double[] P = {
  404. 2.46196981473530512524E-10,
  405. 5.64189564831068821977E-1,
  406. 7.46321056442269912687E0,
  407. 4.86371970985681366614E1,
  408. 1.96520832956077098242E2,
  409. 5.26445194995477358631E2,
  410. 9.34528527171957607540E2,
  411. 1.02755188689515710272E3,
  412. 5.57535335369399327526E2
  413. };
  414. double[] Q = {
  415. //1.0
  416. 1.32281951154744992508E1,
  417. 8.67072140885989742329E1,
  418. 3.54937778887819891062E2,
  419. 9.75708501743205489753E2,
  420. 1.82390916687909736289E3,
  421. 2.24633760818710981792E3,
  422. 1.65666309194161350182E3,
  423. 5.57535340817727675546E2
  424. };
  425. double[] R = {
  426. 5.64189583547755073984E-1,
  427. 1.27536670759978104416E0,
  428. 5.01905042251180477414E0,
  429. 6.16021097993053585195E0,
  430. 7.40974269950448939160E0,
  431. 2.97886665372100240670E0
  432. };
  433. double[] S = {
  434. //1.00000000000000000000E0,
  435. 2.26052863220117276590E0,
  436. 9.39603524938001434673E0,
  437. 1.20489539808096656605E1,
  438. 1.70814450747565897222E1,
  439. 9.60896809063285878198E0,
  440. 3.36907645100081516050E0
  441. };
  442. if (value < 0.0) x = -value;
  443. else x = value;
  444. if (x < 1.0) return 1.0 - Erf(value);
  445. z = -value * value;
  446. if (z < -LogMax)
  447. {
  448. if (value < 0) return (2.0);
  449. else return (0.0);
  450. }
  451. z = System.Math.Exp(z);
  452. if (x < 8.0)
  453. {
  454. p = Polevl(x, P, 8);
  455. q = P1evl(x, Q, 8);
  456. }
  457. else
  458. {
  459. p = Polevl(x, R, 5);
  460. q = P1evl(x, S, 6);
  461. }
  462. y = (z * p) / q;
  463. if (value < 0) y = 2.0 - y;
  464. if (y == 0.0)
  465. {
  466. if (value < 0) return 2.0;
  467. else return (0.0);
  468. }
  469. return y;
  470. }
  471. /// <summary>
  472. /// Error function of the specified value.
  473. /// </summary>
  474. public static double Erf(double x)
  475. {
  476. double y, z;
  477. double[] T = {
  478. 9.60497373987051638749E0,
  479. 9.00260197203842689217E1,
  480. 2.23200534594684319226E3,
  481. 7.00332514112805075473E3,
  482. 5.55923013010394962768E4
  483. };
  484. double[] U = {
  485. //1.00000000000000000000E0,
  486. 3.35617141647503099647E1,
  487. 5.21357949780152679795E2,
  488. 4.59432382970980127987E3,
  489. 2.26290000613890934246E4,
  490. 4.92673942608635921086E4
  491. };
  492. if (System.Math.Abs(x) > 1.0)
  493. return (1.0 - Erfc(x));
  494. z = x * x;
  495. y = x * Polevl(z, T, 4) / P1evl(z, U, 5);
  496. return y;
  497. }
  498. /// <summary>
  499. /// Natural logarithm of gamma function.
  500. /// </summary>
  501. /// <param name="x"></param>
  502. /// <returns></returns>
  503. public static double Lgamma(double x)
  504. {
  505. double p, q, w, z;
  506. double[] A = {
  507. 8.11614167470508450300E-4,
  508. -5.95061904284301438324E-4,
  509. 7.93650340457716943945E-4,
  510. -2.77777777730099687205E-3,
  511. 8.33333333333331927722E-2
  512. };
  513. double[] B = {
  514. -1.37825152569120859100E3,
  515. -3.88016315134637840924E4,
  516. -3.31612992738871184744E5,
  517. -1.16237097492762307383E6,
  518. -1.72173700820839662146E6,
  519. -8.53555664245765465627E5
  520. };
  521. double[] C = {
  522. /* 1.00000000000000000000E0, */
  523. -3.51815701436523470549E2,
  524. -1.70642106651881159223E4,
  525. -2.20528590553854454839E5,
  526. -1.13933444367982507207E6,
  527. -2.53252307177582951285E6,
  528. -2.01889141433532773231E6
  529. };
  530. if (x < -34.0)
  531. {
  532. q = -x;
  533. w = Lgamma(q);
  534. p = System.Math.Floor(q);
  535. if (p == q)
  536. throw new OverflowException("lgamma");
  537. z = q - p;
  538. if (z > 0.5)
  539. {
  540. p += 1.0;
  541. z = p - q;
  542. }
  543. z = q * System.Math.Sin(System.Math.PI * z);
  544. if (z == 0.0)
  545. throw new OverflowException("lgamma");
  546. z = LogPI - System.Math.Log(z) - w;
  547. return z;
  548. }
  549. if (x < 13.0)
  550. {
  551. z = 1.0;
  552. while (x >= 3.0)
  553. {
  554. x -= 1.0;
  555. z *= x;
  556. }
  557. while (x < 2.0)
  558. {
  559. if (x == 0.0)
  560. throw new OverflowException("lgamma");
  561. z /= x;
  562. x += 1.0;
  563. }
  564. if (z < 0.0) z = -z;
  565. if (x == 2.0) return System.Math.Log(z);
  566. x -= 2.0;
  567. p = x * Polevl(x, B, 5) / P1evl(x, C, 6);
  568. return (System.Math.Log(z) + p);
  569. }
  570. if (x > 2.556348e305)
  571. throw new OverflowException("lgamma");
  572. q = (x - 0.5) * System.Math.Log(x) - x + 0.91893853320467274178;
  573. if (x > 1.0e8) return (q);
  574. p = 1.0 / (x * x);
  575. if (x >= 1000.0)
  576. q += ((7.9365079365079365079365e-4 * p
  577. - 2.7777777777777777777778e-3) * p
  578. + 0.0833333333333333333333) / x;
  579. else
  580. q += Polevl(p, A, 4) / x;
  581. return q;
  582. }
  583. /// <summary>
  584. /// Incomplete beta function evaluated from zero to xx.
  585. /// </summary>
  586. public static double Ibeta(double aa, double bb, double xx)
  587. {
  588. double a, b, t, x, xc, w, y;
  589. bool flag;
  590. if (aa <= 0.0)
  591. throw new ArgumentOutOfRangeException("aa", "domain error");
  592. if (bb <= 0.0)
  593. throw new ArgumentOutOfRangeException("bb", "domain error");
  594. if ((xx <= 0.0) || (xx >= 1.0))
  595. {
  596. if (xx == 0.0) return 0.0;
  597. if (xx == 1.0) return 1.0;
  598. throw new ArgumentOutOfRangeException("xx", "domain error");
  599. }
  600. flag = false;
  601. if ((bb * xx) <= 1.0 && xx <= 0.95)
  602. {
  603. t = PowerSeries(aa, bb, xx);
  604. return t;
  605. }
  606. w = 1.0 - xx;
  607. if (xx > (aa / (aa + bb)))
  608. {
  609. flag = true;
  610. a = bb;
  611. b = aa;
  612. xc = xx;
  613. x = w;
  614. }
  615. else
  616. {
  617. a = aa;
  618. b = bb;
  619. xc = w;
  620. x = xx;
  621. }
  622. if (flag && (b * x) <= 1.0 && x <= 0.95)
  623. {
  624. t = PowerSeries(a, b, x);
  625. if (t <= DoubleEpsilon) t = 1.0 - DoubleEpsilon;
  626. else t = 1.0 - t;
  627. return t;
  628. }
  629. y = x * (a + b - 2.0) - (a - 1.0);
  630. if (y < 0.0)
  631. w = Incbcf(a, b, x);
  632. else
  633. w = Incbd(a, b, x) / xc;
  634. y = a * System.Math.Log(x);
  635. t = b * System.Math.Log(xc);
  636. if ((a + b) < GammaMax && System.Math.Abs(y) < LogMax && System.Math.Abs(t) < LogMax)
  637. {
  638. t = System.Math.Pow(xc, b);
  639. t *= System.Math.Pow(x, a);
  640. t /= a;
  641. t *= w;
  642. t *= Gamma(a + b) / (Gamma(a) * Gamma(b));
  643. if (flag)
  644. {
  645. if (t <= DoubleEpsilon) t = 1.0 - DoubleEpsilon;
  646. else t = 1.0 - t;
  647. }
  648. return t;
  649. }
  650. y += t + Lgamma(a + b) - Lgamma(a) - Lgamma(b);
  651. y += System.Math.Log(w / a);
  652. if (y < LogMin)
  653. t = 0.0;
  654. else
  655. t = System.Math.Exp(y);
  656. if (flag)
  657. {
  658. if (t <= DoubleEpsilon) t = 1.0 - DoubleEpsilon;
  659. else t = 1.0 - t;
  660. }
  661. return t;
  662. }
  663. /// <summary>
  664. /// Continued fraction expansion #1 for incomplete beta integral.
  665. /// </summary>
  666. public static double Incbcf(double a, double b, double x)
  667. {
  668. double xk, pk, pkm1, pkm2, qk, qkm1, qkm2;
  669. double k1, k2, k3, k4, k5, k6, k7, k8;
  670. double r, t, ans, thresh;
  671. int n;
  672. double big = 4.503599627370496e15;
  673. double biginv = 2.22044604925031308085e-16;
  674. k1 = a;
  675. k2 = a + b;
  676. k3 = a;
  677. k4 = a + 1.0;
  678. k5 = 1.0;
  679. k6 = b - 1.0;
  680. k7 = k4;
  681. k8 = a + 2.0;
  682. pkm2 = 0.0;
  683. qkm2 = 1.0;
  684. pkm1 = 1.0;
  685. qkm1 = 1.0;
  686. ans = 1.0;
  687. r = 1.0;
  688. n = 0;
  689. thresh = 3.0 * DoubleEpsilon;
  690. do
  691. {
  692. xk = -(x * k1 * k2) / (k3 * k4);
  693. pk = pkm1 + pkm2 * xk;
  694. qk = qkm1 + qkm2 * xk;
  695. pkm2 = pkm1;
  696. pkm1 = pk;
  697. qkm2 = qkm1;
  698. qkm1 = qk;
  699. xk = (x * k5 * k6) / (k7 * k8);
  700. pk = pkm1 + pkm2 * xk;
  701. qk = qkm1 + qkm2 * xk;
  702. pkm2 = pkm1;
  703. pkm1 = pk;
  704. qkm2 = qkm1;
  705. qkm1 = qk;
  706. if (qk != 0) r = pk / qk;
  707. if (r != 0)
  708. {
  709. t = System.Math.Abs((ans - r) / r);
  710. ans = r;
  711. }
  712. else
  713. t = 1.0;
  714. if (t < thresh) return ans;
  715. k1 += 1.0;
  716. k2 += 1.0;
  717. k3 += 2.0;
  718. k4 += 2.0;
  719. k5 += 1.0;
  720. k6 -= 1.0;
  721. k7 += 2.0;
  722. k8 += 2.0;
  723. if ((System.Math.Abs(qk) + System.Math.Abs(pk)) > big)
  724. {
  725. pkm2 *= biginv;
  726. pkm1 *= biginv;
  727. qkm2 *= biginv;
  728. qkm1 *= biginv;
  729. }
  730. if ((System.Math.Abs(qk) < biginv) || (System.Math.Abs(pk) < biginv))
  731. {
  732. pkm2 *= big;
  733. pkm1 *= big;
  734. qkm2 *= big;
  735. qkm1 *= big;
  736. }
  737. } while (++n < 300);
  738. return ans;
  739. }
  740. /// <summary>
  741. /// Continued fraction expansion #2 for incomplete beta integral.
  742. /// </summary>
  743. public static double Incbd(double a, double b, double x)
  744. {
  745. double xk, pk, pkm1, pkm2, qk, qkm1, qkm2;
  746. double k1, k2, k3, k4, k5, k6, k7, k8;
  747. double r, t, ans, z, thresh;
  748. int n;
  749. double big = 4.503599627370496e15;
  750. double biginv = 2.22044604925031308085e-16;
  751. k1 = a;
  752. k2 = b - 1.0;
  753. k3 = a;
  754. k4 = a + 1.0;
  755. k5 = 1.0;
  756. k6 = a + b;
  757. k7 = a + 1.0;
  758. ;
  759. k8 = a + 2.0;
  760. pkm2 = 0.0;
  761. qkm2 = 1.0;
  762. pkm1 = 1.0;
  763. qkm1 = 1.0;
  764. z = x / (1.0 - x);
  765. ans = 1.0;
  766. r = 1.0;
  767. n = 0;
  768. thresh = 3.0 * DoubleEpsilon;
  769. do
  770. {
  771. xk = -(z * k1 * k2) / (k3 * k4);
  772. pk = pkm1 + pkm2 * xk;
  773. qk = qkm1 + qkm2 * xk;
  774. pkm2 = pkm1;
  775. pkm1 = pk;
  776. qkm2 = qkm1;
  777. qkm1 = qk;
  778. xk = (z * k5 * k6) / (k7 * k8);
  779. pk = pkm1 + pkm2 * xk;
  780. qk = qkm1 + qkm2 * xk;
  781. pkm2 = pkm1;
  782. pkm1 = pk;
  783. qkm2 = qkm1;
  784. qkm1 = qk;
  785. if (qk != 0) r = pk / qk;
  786. if (r != 0)
  787. {
  788. t = System.Math.Abs((ans - r) / r);
  789. ans = r;
  790. }
  791. else
  792. t = 1.0;
  793. if (t < thresh) return ans;
  794. k1 += 1.0;
  795. k2 -= 1.0;
  796. k3 += 2.0;
  797. k4 += 2.0;
  798. k5 += 1.0;
  799. k6 += 1.0;
  800. k7 += 2.0;
  801. k8 += 2.0;
  802. if ((System.Math.Abs(qk) + System.Math.Abs(pk)) > big)
  803. {
  804. pkm2 *= biginv;
  805. pkm1 *= biginv;
  806. qkm2 *= biginv;
  807. qkm1 *= biginv;
  808. }
  809. if ((System.Math.Abs(qk) < biginv) || (System.Math.Abs(pk) < biginv))
  810. {
  811. pkm2 *= big;
  812. pkm1 *= big;
  813. qkm2 *= big;
  814. qkm1 *= big;
  815. }
  816. } while (++n < 300);
  817. return ans;
  818. }
  819. /// <summary>
  820. /// Power series for incomplete beta integral. Use when b*x
  821. /// is small and x not too close to 1.
  822. /// </summary>
  823. public static double PowerSeries(double a, double b, double x)
  824. {
  825. double s, t, u, v, n, t1, z, ai;
  826. ai = 1.0 / a;
  827. u = (1.0 - b) * x;
  828. v = u / (a + 1.0);
  829. t1 = v;
  830. t = u;
  831. n = 2.0;
  832. s = 0.0;
  833. z = DoubleEpsilon * ai;
  834. while (System.Math.Abs(v) > z)
  835. {
  836. u = (n - b) * x / n;
  837. t *= u;
  838. v = t / (a + n);
  839. s += v;
  840. n += 1.0;
  841. }
  842. s += t1;
  843. s += ai;
  844. u = a * System.Math.Log(x);
  845. if ((a + b) < GammaMax && System.Math.Abs(u) < LogMax)
  846. {
  847. t = Gamma(a + b) / (Gamma(a) * Gamma(b));
  848. s = s * t * System.Math.Pow(x, a);
  849. }
  850. else
  851. {
  852. t = Lgamma(a + b) - Lgamma(a) - Lgamma(b) + u + System.Math.Log(s);
  853. if (t < LogMin) s = 0.0;
  854. else s = System.Math.Exp(t);
  855. }
  856. return s;
  857. }
  858. /// <summary>
  859. /// Evaluates polynomial of degree N
  860. /// </summary>
  861. public static double Polevl(double x, double[] coef, int n)
  862. {
  863. double ans;
  864. ans = coef[0];
  865. for (int i = 1; i <= n; i++)
  866. ans = ans * x + coef[i];
  867. return ans;
  868. }
  869. /// <summary>
  870. /// Evaluates polynomial of degree N with assumption that coef[N] = 1.0
  871. /// </summary>
  872. public static double P1evl(double x, double[] coef, int n)
  873. {
  874. double ans;
  875. ans = x + coef[0];
  876. for (int i = 1; i < n; i++)
  877. ans = ans * x + coef[i];
  878. return ans;
  879. }
  880. /// <summary>
  881. /// Returns the Bessel function of order 0 of the specified number.
  882. /// </summary>
  883. public static double BesselJ0(double x)
  884. {
  885. double ax;
  886. if ((ax = System.Math.Abs(x)) < 8.0)
  887. {
  888. double y = x * x;
  889. double ans1 = 57568490574.0 + y * (-13362590354.0 + y * (651619640.7
  890. + y * (-11214424.18 + y * (77392.33017 + y * (-184.9052456)))));
  891. double ans2 = 57568490411.0 + y * (1029532985.0 + y * (9494680.718
  892. + y * (59272.64853 + y * (267.8532712 + y * 1.0))));
  893. return ans1 / ans2;
  894. }
  895. else
  896. {
  897. double z = 8.0 / ax;
  898. double y = z * z;
  899. double xx = ax - 0.785398164;
  900. double ans1 = 1.0 + y * (-0.1098628627e-2 + y * (0.2734510407e-4
  901. + y * (-0.2073370639e-5 + y * 0.2093887211e-6)));
  902. double ans2 = -0.1562499995e-1 + y * (0.1430488765e-3
  903. + y * (-0.6911147651e-5 + y * (0.7621095161e-6
  904. - y * 0.934935152e-7)));
  905. return System.Math.Sqrt(0.636619772 / ax) *
  906. (System.Math.Cos(xx) * ans1 - z * System.Math.Sin(xx) * ans2);
  907. }
  908. }
  909. /// <summary>
  910. /// Returns the Bessel function of order 1 of the specified number.
  911. /// </summary>
  912. public static double BesselJ(double x)
  913. {
  914. double ax;
  915. double y;
  916. double ans1, ans2;
  917. if ((ax = System.Math.Abs(x)) < 8.0)
  918. {
  919. y = x * x;
  920. ans1 = x * (72362614232.0 + y * (-7895059235.0 + y * (242396853.1
  921. + y * (-2972611.439 + y * (15704.48260 + y * (-30.16036606))))));
  922. ans2 = 144725228442.0 + y * (2300535178.0 + y * (18583304.74
  923. + y * (99447.43394 + y * (376.9991397 + y * 1.0))));
  924. return ans1 / ans2;
  925. }
  926. else
  927. {
  928. double z = 8.0 / ax;
  929. double xx = ax - 2.356194491;
  930. y = z * z;
  931. ans1 = 1.0 + y * (0.183105e-2 + y * (-0.3516396496e-4
  932. + y * (0.2457520174e-5 + y * (-0.240337019e-6))));
  933. ans2 = 0.04687499995 + y * (-0.2002690873e-3
  934. + y * (0.8449199096e-5 + y * (-0.88228987e-6
  935. + y * 0.105787412e-6)));
  936. double ans = System.Math.Sqrt(0.636619772 / ax) *
  937. (System.Math.Cos(xx) * ans1 - z * System.Math.Sin(xx) * ans2);
  938. if (x < 0.0) ans = -ans;
  939. return ans;
  940. }
  941. }
  942. /// <summary>
  943. /// Returns the Bessel function of order n of the specified number.
  944. /// </summary>
  945. public static double BesselJ(int n, double x)
  946. {
  947. int j, m;
  948. double ax, bj, bjm, bjp, sum, tox, ans;
  949. bool jsum;
  950. double ACC = 40.0;
  951. double BIGNO = 1.0e+10;
  952. double BIGNI = 1.0e-10;
  953. if (n == 0) return BesselJ0(x);
  954. if (n == 1) return BesselJ(x);
  955. ax = System.Math.Abs(x);
  956. if (ax == 0.0) return 0.0;
  957. else if (ax > (double)n)
  958. {
  959. tox = 2.0 / ax;
  960. bjm = BesselJ0(ax);
  961. bj = BesselJ(ax);
  962. for (j = 1; j < n; j++)
  963. {
  964. bjp = j * tox * bj - bjm;
  965. bjm = bj;
  966. bj = bjp;
  967. }
  968. ans = bj;
  969. }
  970. else
  971. {
  972. tox = 2.0 / ax;
  973. m = 2 * ((n + (int)System.Math.Sqrt(ACC * n)) / 2);
  974. jsum = false;
  975. bjp = ans = sum = 0.0;
  976. bj = 1.0;
  977. for (j = m; j > 0; j--)
  978. {
  979. bjm = j * tox * bj - bjp;
  980. bjp = bj;
  981. bj = bjm;
  982. if (System.Math.Abs(bj) > BIGNO)
  983. {
  984. bj *= BIGNI;
  985. bjp *= BIGNI;
  986. ans *= BIGNI;
  987. sum *= BIGNI;
  988. }
  989. if (jsum) sum += bj;
  990. jsum = !jsum;
  991. if (j == n) ans = bjp;
  992. }
  993. sum = 2.0 * sum - bj;
  994. ans /= sum;
  995. }
  996. return x < 0.0 && n % 2 == 1 ? -ans : ans;
  997. }
  998. /// <summary>
  999. /// Returns the Bessel function of the second kind, of order 0 of the specified number.
  1000. /// </summary>
  1001. public static double BesselY0(double x)
  1002. {
  1003. if (x < 8.0)
  1004. {
  1005. double y = x * x;
  1006. double ans1 = -2957821389.0 + y * (7062834065.0 + y * (-512359803.6
  1007. + y * (10879881.29 + y * (-86327.92757 + y * 228.4622733))));
  1008. double ans2 = 40076544269.0 + y * (745249964.8 + y * (7189466.438
  1009. + y * (47447.26470 + y * (226.1030244 + y * 1.0))));
  1010. return (ans1 / ans2) + 0.636619772 * BesselJ0(x) * System.Math.Log(x);
  1011. }
  1012. else
  1013. {
  1014. double z = 8.0 / x;
  1015. double y = z * z;
  1016. double xx = x - 0.785398164;
  1017. double ans1 = 1.0 + y * (-0.1098628627e-2 + y * (0.2734510407e-4
  1018. + y * (-0.2073370639e-5 + y * 0.2093887211e-6)));
  1019. double ans2 = -0.1562499995e-1 + y * (0.1430488765e-3
  1020. + y * (-0.6911147651e-5 + y * (0.7621095161e-6
  1021. + y * (-0.934945152e-7))));
  1022. return System.Math.Sqrt(0.636619772 / x) *
  1023. (System.Math.Sin(xx) * ans1 + z * System.Math.Cos(xx) * ans2);
  1024. }
  1025. }
  1026. /// <summary>
  1027. /// Returns the Bessel function of the second kind, of order 1 of the specified number.
  1028. /// </summary>
  1029. public static double BesselY(double x)
  1030. {
  1031. if (x < 8.0)
  1032. {
  1033. double y = x * x;
  1034. double ans1 = x * (-0.4900604943e13 + y * (0.1275274390e13
  1035. + y * (-0.5153438139e11 + y * (0.7349264551e9
  1036. + y * (-0.4237922726e7 + y * 0.8511937935e4)))));
  1037. double ans2 = 0.2499580570e14 + y * (0.4244419664e12
  1038. + y * (0.3733650367e10 + y * (0.2245904002e8
  1039. + y * (0.1020426050e6 + y * (0.3549632885e3 + y)))));
  1040. return (ans1 / ans2) + 0.636619772 * (BesselJ(x) * System.Math.Log(x) - 1.0 / x);
  1041. }
  1042. else
  1043. {
  1044. double z = 8.0 / x;
  1045. double y = z * z;
  1046. double xx = x - 2.356194491;
  1047. double ans1 = 1.0 + y * (0.183105e-2 + y * (-0.3516396496e-4
  1048. + y * (0.2457520174e-5 + y * (-0.240337019e-6))));
  1049. double ans2 = 0.04687499995 + y * (-0.2002690873e-3
  1050. + y * (0.8449199096e-5 + y * (-0.88228987e-6
  1051. + y * 0.105787412e-6)));
  1052. return System.Math.Sqrt(0.636619772 / x) *
  1053. (System.Math.Sin(xx) * ans1 + z * System.Math.Cos(xx) * ans2);
  1054. }
  1055. }
  1056. /// <summary>
  1057. /// Returns the Bessel function of the second kind, of order n of the specified number.
  1058. /// </summary>
  1059. public static double BesselY(int n, double x)
  1060. {
  1061. double by, bym, byp, tox;
  1062. if (n == 0) return BesselY0(x);
  1063. if (n == 1) return BesselY(x);
  1064. tox = 2.0 / x;
  1065. by = BesselY(x);
  1066. bym = BesselY0(x);
  1067. for (int j = 1; j < n; j++)
  1068. {
  1069. byp = j * tox * by - bym;
  1070. bym = by;
  1071. by = byp;
  1072. }
  1073. return by;
  1074. }
  1075. /// <summary>
  1076. /// Computes the Basic Spline of order n
  1077. /// </summary>
  1078. public static double BSpline(int n, double x)
  1079. {
  1080. // ftp://ftp.esat.kuleuven.ac.be/pub/SISTA/hamers/PhD_bhamers.pdf
  1081. // http://sepwww.stanford.edu/public/docs/sep105/sergey2/paper_html/node5.html
  1082. double a = 1.0 / Special.Factorial(n);
  1083. double c;
  1084. bool positive = true;
  1085. for (int k = 0; k <= n + 1; k++)
  1086. {
  1087. c = Binomial(n + 1, k) * Tools.TruncatedPower(x + (n + 1.0) / 2.0 - k, n);
  1088. a += positive ? c : -c;
  1089. positive = !positive;
  1090. }
  1091. return a;
  1092. }
  1093. /// <summary>
  1094. /// Computes the Binomial Coefficients C(n,k).
  1095. /// </summary>
  1096. public static double Binomial(int n, int k)
  1097. {
  1098. return Math.Floor(0.5 + Math.Exp(Lfactorial(n) - Lfactorial(k) - Lfactorial(n - k)));
  1099. }
  1100. /// <summary>
  1101. /// Returns the log factorial of a number (ln(n!))
  1102. /// </summary>
  1103. public static double Lfactorial(int n)
  1104. {
  1105. if (lnfcache == null)
  1106. lnfcache = new double[101];
  1107. if (n < 0)
  1108. {
  1109. // Factorial is not defined for negative numbers.
  1110. throw new ArgumentException("Argument cannot be negative.", "n");
  1111. }
  1112. if (n <= 1)
  1113. {
  1114. // Factorial for n between 0 and 1 is 1, so log(factorial(n)) is 0.
  1115. return 0.0;
  1116. }
  1117. if (n <= 100)
  1118. {
  1119. // Compute the factorial using ln(gamma(n)) approximation, using the cache
  1120. // if the value has been previously computed.
  1121. return (lnfcache[n] > 0) ? lnfcache[n] : (lnfcache[n] = Lgamma(n + 1.0));
  1122. }
  1123. else
  1124. {
  1125. // Just compute the factorial using ln(gamma(n)) approximation.
  1126. return Lgamma(n + 1.0);
  1127. }
  1128. }
  1129. /// <summary>
  1130. /// Computes log(1+x) without losing precision for small values of x.
  1131. /// </summary>
  1132. /// <remarks>
  1133. /// References:
  1134. /// - http://www.johndcook.com/csharp_log_one_plus_x.html
  1135. /// </remarks>
  1136. public static double Log1p(double x)
  1137. {
  1138. if (x <= -1.0)
  1139. return Double.NaN;
  1140. if (Math.Abs(x) > 1e-4)
  1141. return Math.Log(1.0 + x);
  1142. // Use Taylor approx. log(1 + x) = x - x^2/2 with error roughly x^3/3
  1143. // Since |x| < 10^-4, |x|^3 < 10^-12, relative error less than 10^-8
  1144. return (-0.5 * x + 1.0) * x;
  1145. }
  1146. /// <summary>
  1147. /// Compute exp(x) - 1 without loss of precision for small values of x.
  1148. /// </summary>
  1149. /// <remarks>
  1150. /// References:
  1151. /// - http://www.johndcook.com/cpp_expm1.html
  1152. /// </remarks>
  1153. public static double Expm1(double x)
  1154. {
  1155. if (Math.Abs(x) < 1e-5)
  1156. return x + 0.5 * x * x;
  1157. else
  1158. return Math.Exp(x) - 1.0;
  1159. }
  1160. /// <summary>
  1161. /// Computes the factorial of a number (n!)
  1162. /// </summary>
  1163. public static double Factorial(int n)
  1164. {
  1165. if (fcache == null)
  1166. {
  1167. // Initialize factorial cache
  1168. fcache = new double[33];
  1169. fcache[0] = 1; fcache[1] = 1;
  1170. fcache[2] = 2; fcache[3] = 6;
  1171. fcache[4] = 24; ftop = 4;
  1172. }
  1173. if (n < 0)
  1174. {
  1175. // Factorial is not defined for negative numbers
  1176. throw new ArgumentException("Argument can not be negative", "n");
  1177. }
  1178. if (n > 32)
  1179. {
  1180. // Return Gamma approximation using exp(gammaln(n+1)),
  1181. // which for some reason is faster than gamma(n+1).
  1182. return Math.Exp(Lgamma(n + 1.0));
  1183. }
  1184. else
  1185. {
  1186. // Compute in the standard way, but use the
  1187. // factorial cache to speed up computations.
  1188. while (ftop < n)
  1189. {
  1190. int j = ftop++;
  1191. fcache[ftop] = fcache[j] * ftop;
  1192. }
  1193. return fcache[n];
  1194. }
  1195. }
  1196. /// <summary>
  1197. /// Estimates unit roundoff in quantities of size x.
  1198. /// </summary>
  1199. /// <remarks>
  1200. /// This is a port of the epslon function from EISPACK.
  1201. /// </remarks>
  1202. public static double Epslon(double x)
  1203. {
  1204. double a, b, c, eps;
  1205. a = 1.3333333333333333;
  1206. L10:
  1207. b = a - 1.0;
  1208. c = b + b + b;
  1209. eps = System.Math.Abs(c - 1.0);
  1210. if (eps == 0.0) goto L10;
  1211. return eps * System.Math.Abs(x);
  1212. }
  1213. /// <summary>
  1214. /// Returns A with the sign of B.
  1215. /// </summary>
  1216. /// <remarks>
  1217. /// This is a port of the sign transfer function from EISPACK.
  1218. /// </remarks>
  1219. /// <returns>If B > 0 then the result is ABS(A), else it is -ABS(A).</returns>
  1220. public static double Sign(double a, double b)
  1221. {
  1222. double x;
  1223. x = (a >= 0 ? a : -a);
  1224. return (b >= 0 ? x : -x);
  1225. }
  1226. // factorial function caches
  1227. private static int ftop;
  1228. private static double[] fcache;
  1229. private static double[] lnfcache;
  1230. }
  1231. }