igamil.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /* igamil()
  2. *
  3. * Inverse of complemented imcomplete gamma integral
  4. *
  5. *
  6. *
  7. * SYNOPSIS:
  8. *
  9. * long double a, x, y, igamil();
  10. *
  11. * x = igamil( a, y );
  12. *
  13. *
  14. *
  15. * DESCRIPTION:
  16. *
  17. * Given y, the function finds x such that
  18. *
  19. * igamc( a, x ) = y.
  20. *
  21. * Starting with the approximate value
  22. *
  23. * 3
  24. * x = a t
  25. *
  26. * where
  27. *
  28. * t = 1 - d - ndtri(y) sqrt(d)
  29. *
  30. * and
  31. *
  32. * d = 1/9a,
  33. *
  34. * the routine performs up to 10 Newton iterations to find the
  35. * root of igamc(a,x) - y = 0.
  36. *
  37. *
  38. * ACCURACY:
  39. *
  40. * Tested for a ranging from 0.5 to 30 and x from 0 to 0.5.
  41. *
  42. * Relative error:
  43. * arithmetic domain # trials peak rms
  44. * DEC 0,0.5 3400 8.8e-16 1.3e-16
  45. * IEEE 0,0.5 10000 1.1e-14 1.0e-15
  46. *
  47. */
  48. /*
  49. Cephes Math Library Release 2.3: March, 1995
  50. Copyright 1984, 1995 by Stephen L. Moshier
  51. */
  52. #include <math.h>
  53. extern long double MACHEPL, MAXNUML, MAXLOGL, MINLOGL;
  54. #ifdef ANSIPROT
  55. extern long double ndtril ( long double );
  56. extern long double expl ( long double );
  57. extern long double fabsl ( long double );
  58. extern long double logl ( long double );
  59. extern long double sqrtl ( long double );
  60. extern long double lgaml ( long double );
  61. extern long double igamcl ( long double, long double );
  62. #else
  63. long double ndtril(), expl(), fabsl(), logl(), sqrtl(), lgaml();
  64. long double igamcl();
  65. #endif
  66. long double igamil( a, y0 )
  67. long double a, y0;
  68. {
  69. long double x0, x1, x, yl, yh, y, d, lgm, dithresh;
  70. int i, dir;
  71. /* bound the solution */
  72. x0 = MAXNUML;
  73. yl = 0.0L;
  74. x1 = 0.0L;
  75. yh = 1.0L;
  76. dithresh = 4.0 * MACHEPL;
  77. /* approximation to inverse function */
  78. d = 1.0L/(9.0L*a);
  79. y = ( 1.0L - d - ndtril(y0) * sqrtl(d) );
  80. x = a * y * y * y;
  81. lgm = lgaml(a);
  82. for( i=0; i<10; i++ )
  83. {
  84. if( x > x0 || x < x1 )
  85. goto ihalve;
  86. y = igamcl(a,x);
  87. if( y < yl || y > yh )
  88. goto ihalve;
  89. if( y < y0 )
  90. {
  91. x0 = x;
  92. yl = y;
  93. }
  94. else
  95. {
  96. x1 = x;
  97. yh = y;
  98. }
  99. /* compute the derivative of the function at this point */
  100. d = (a - 1.0L) * logl(x0) - x0 - lgm;
  101. if( d < -MAXLOGL )
  102. goto ihalve;
  103. d = -expl(d);
  104. /* compute the step to the next approximation of x */
  105. d = (y - y0)/d;
  106. x = x - d;
  107. if( i < 3 )
  108. continue;
  109. if( fabsl(d/x) < dithresh )
  110. goto done;
  111. }
  112. /* Resort to interval halving if Newton iteration did not converge. */
  113. ihalve:
  114. d = 0.0625L;
  115. if( x0 == MAXNUML )
  116. {
  117. if( x <= 0.0L )
  118. x = 1.0L;
  119. while( x0 == MAXNUML )
  120. {
  121. x = (1.0L + d) * x;
  122. y = igamcl( a, x );
  123. if( y < y0 )
  124. {
  125. x0 = x;
  126. yl = y;
  127. break;
  128. }
  129. d = d + d;
  130. }
  131. }
  132. d = 0.5L;
  133. dir = 0;
  134. for( i=0; i<400; i++ )
  135. {
  136. x = x1 + d * (x0 - x1);
  137. y = igamcl( a, x );
  138. lgm = (x0 - x1)/(x1 + x0);
  139. if( fabsl(lgm) < dithresh )
  140. break;
  141. lgm = (y - y0)/y0;
  142. if( fabsl(lgm) < dithresh )
  143. break;
  144. if( x <= 0.0L )
  145. break;
  146. if( y > y0 )
  147. {
  148. x1 = x;
  149. yh = y;
  150. if( dir < 0 )
  151. {
  152. dir = 0;
  153. d = 0.5L;
  154. }
  155. else if( dir > 1 )
  156. d = 0.5L * d + 0.5L;
  157. else
  158. d = (y0 - yl)/(yh - yl);
  159. dir += 1;
  160. }
  161. else
  162. {
  163. x0 = x;
  164. yl = y;
  165. if( dir > 0 )
  166. {
  167. dir = 0;
  168. d = 0.5L;
  169. }
  170. else if( dir < -1 )
  171. d = 0.5L * d;
  172. else
  173. d = (y0 - yl)/(yh - yl);
  174. dir -= 1;
  175. }
  176. }
  177. if( x == 0.0L )
  178. mtherr( "igamil", UNDERFLOW );
  179. done:
  180. return( x );
  181. }