gsl_cdf__gammainv.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /* cdf/gammainv.c
  2. *
  3. * Copyright (C) 2003, 2007 Brian Gough
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. #include "gsl__config.h"
  20. #include <math.h>
  21. #include "gsl_cdf.h"
  22. #include "gsl_math.h"
  23. #include "gsl_randist.h"
  24. #include "gsl_sf_gamma.h"
  25. #include <stdio.h>
  26. double
  27. gsl_cdf_gamma_Pinv (const double P, const double a, const double b)
  28. {
  29. double x;
  30. if (P == 1.0)
  31. {
  32. return GSL_POSINF;
  33. }
  34. else if (P == 0.0)
  35. {
  36. return 0.0;
  37. }
  38. /* Consider, small, large and intermediate cases separately. The
  39. boundaries at 0.05 and 0.95 have not been optimised, but seem ok
  40. for an initial approximation. */
  41. if (P < 0.05)
  42. {
  43. double x0 = exp ((gsl_sf_lngamma (a) + log (P)) / a);
  44. x = x0;
  45. }
  46. else if (P > 0.95)
  47. {
  48. double x0 = -log1p (-P) + gsl_sf_lngamma (a);
  49. x = x0;
  50. }
  51. else
  52. {
  53. double xg = gsl_cdf_ugaussian_Pinv (P);
  54. double x0 = (xg < -sqrt (a)) ? a : sqrt (a) * xg + a;
  55. x = x0;
  56. }
  57. /* Use Lagrange's interpolation for E(x)/phi(x0) to work backwards
  58. to an improved value of x (Abramowitz & Stegun, 3.6.6)
  59. where E(x)=P-integ(phi(u),u,x0,x) and phi(u) is the pdf.
  60. */
  61. {
  62. double lambda, dP, phi;
  63. unsigned int n = 0;
  64. start:
  65. dP = P - gsl_cdf_gamma_P (x, a, 1.0);
  66. phi = gsl_ran_gamma_pdf (x, a, 1.0);
  67. if (dP == 0.0 || n++ > 32)
  68. goto end;
  69. lambda = dP / GSL_MAX (2 * fabs (dP / x), phi);
  70. {
  71. double step0 = lambda;
  72. double step1 = -((a - 1) / x - 1) * lambda * lambda / 4.0;
  73. double step = step0;
  74. if (fabs (step1) < fabs (step0))
  75. step += step1;
  76. if (x + step > 0)
  77. x += step;
  78. else
  79. {
  80. x /= 2.0;
  81. }
  82. if (fabs (step0) > 1e-10 * x)
  83. goto start;
  84. }
  85. end:
  86. if (fabs(dP) > GSL_SQRT_DBL_EPSILON * P)
  87. {
  88. GSL_ERROR_VAL("inverse failed to converge", GSL_EFAILED, GSL_NAN);
  89. }
  90. return b * x;
  91. }
  92. }
  93. double
  94. gsl_cdf_gamma_Qinv (const double Q, const double a, const double b)
  95. {
  96. double x;
  97. if (Q == 1.0)
  98. {
  99. return 0.0;
  100. }
  101. else if (Q == 0.0)
  102. {
  103. return GSL_POSINF;
  104. }
  105. /* Consider, small, large and intermediate cases separately. The
  106. boundaries at 0.05 and 0.95 have not been optimised, but seem ok
  107. for an initial approximation. */
  108. if (Q < 0.05)
  109. {
  110. double x0 = -log (Q) + gsl_sf_lngamma (a);
  111. x = x0;
  112. }
  113. else if (Q > 0.95)
  114. {
  115. double x0 = exp ((gsl_sf_lngamma (a) + log1p (-Q)) / a);
  116. x = x0;
  117. }
  118. else
  119. {
  120. double xg = gsl_cdf_ugaussian_Qinv (Q);
  121. double x0 = (xg < -sqrt (a)) ? a : sqrt (a) * xg + a;
  122. x = x0;
  123. }
  124. /* Use Lagrange's interpolation for E(x)/phi(x0) to work backwards
  125. to an improved value of x (Abramowitz & Stegun, 3.6.6)
  126. where E(x)=P-integ(phi(u),u,x0,x) and phi(u) is the pdf.
  127. */
  128. {
  129. double lambda, dQ, phi;
  130. unsigned int n = 0;
  131. start:
  132. dQ = Q - gsl_cdf_gamma_Q (x, a, 1.0);
  133. phi = gsl_ran_gamma_pdf (x, a, 1.0);
  134. if (dQ == 0.0 || n++ > 32)
  135. goto end;
  136. lambda = -dQ / GSL_MAX (2 * fabs (dQ / x), phi);
  137. {
  138. double step0 = lambda;
  139. double step1 = -((a - 1) / x - 1) * lambda * lambda / 4.0;
  140. double step = step0;
  141. if (fabs (step1) < fabs (step0))
  142. step += step1;
  143. if (x + step > 0)
  144. x += step;
  145. else
  146. {
  147. x /= 2.0;
  148. }
  149. if (fabs (step0) > 1e-10 * x)
  150. goto start;
  151. }
  152. }
  153. end:
  154. return b * x;
  155. }