Viewing contents of file '../idllib/contrib/meron/m_igamma.pro'
Function M_Igamma, x, a, eps, complementary = comp
;+
; NAME:
; M_IGAMMA
; VERSION:
; 3.0
; PURPOSE:
; Calculates the incomplete gamma function. Replacement for the IDL
; IGAMMA function which accepts only real input.
; CATEGORY:
; Mathematical function (general).
; CALLING SEQUENCE:
; Result = M_IGAMMA (X, A [,EPS ] [,/COMPLEMENTARY ])
; INPUTS:
; X
; Numeric, otherwise arbitrary.
; A
; Numeric scalar, non-complex, positive.
; OPTIONAL INPUT PARAMETERS:
; EPS
; Specifies precision level. Default is machine precision.
; KEYWORD PARAMETERS:
; /COMPLEMENTARY
; Switch. If set, 1 - IGAMMA(X) is returned.
; OUTPUTS:
; Returns the incomplete gamma function of x, unless /COMPLEMENTARY is
; set in which case returns 1 - the incomplete gamma function.
; OPTIONAL OUTPUT PARAMETERS:
; None.
; COMMON BLOCKS:
; None.
; SIDE EFFECTS:
; None.
; RESTRICTIONS:
; For reasons having to do with machine limits on sizes of numbers, the
; parameter A cannot be too big. The limit is roughly given by
;
; A < P + (Ln(2*P))/2
;
; Where P is the (natural) logarithm of the largest number the machine
; can process. The limit is machine dependent.
;
; Also, for values of X with large negative real part the calculation
; cannot converge and the result is replaced with a very large number
; (machine limit). A warning is displayed in this case.
; PROCEDURE:
; Uses series expansion for small ABS(X) and continued fraction
; expansion for larger values. Calls CAST, CONFRAC, DEFAULT, ISNUM,
; M_ABS, M_LNGAMMA, and TOLER, from MIDL.
; MODIFICATION HISTORY:
; Created 15-MAR-1996 by Mati Meron.
; Modified 20-SEP-1998 by Mati Meron. Underflow filtering added.
;-
on_error, 1
sinf = machar(double=Isnum(x,/double,typ=typ))
teps = Default(eps,Toler(x),/dtype)
compf = keyword_set(comp)
lp = alog(2d)*sinf.maxexp
ln = alog(2d)*sinf.minexp
philim = !dpi/2
if a le 0 then message, 'A must be greater then 0!'
if (a + 1)*(alog(a + 1) - cos(philim)) - M_lngamma(a + 2) ge lp then $
message, 'A value of A = ' + string(a, form = '(f8.4)') + ' is too big!'
da = double(a)
bound = (da + 1) > sqrt(-alog(teps) > 1)
dx = dcomplex(x)
ddx = double(dx)
res = 0*dx
sran = long(res)
tem = dx + bound
dum = where(M_abs(tem) le 2*bound, ndum)
if ndum gt 0 then sran(dum) = 1
lran = long(res)
tem = (da - 1)*alog(M_abs(dx) > 1) - ddx - M_lngamma(da)
dum = where(tem gt ln and tem lt lp, ndum)
if ndum gt 0 then lran(dum) = 1
phas = 0*ddx
dum = where(M_imaginary(dx) ne 0, ndum)
if ndum ne 0 then phas(dum) = atan(dx(dum))
dum = where(dx eq 0, ndum)
if ndum gt 0 and compf then res(dum) = 1
dum = where (sran and lran and dx ne 0, ndum)
if ndum gt 0 then begin
tex = dx(dum)
tres = exp(da*alog(tex) - tex - M_lngamma(da + 1))
tem = tres
ltem = lindgen(ndum)
ntem = ndum
n = 0l
while ntem gt 0 do begin
n = n + 1
tem = tem*tex(ltem)/(da + n)
tres(ltem) = tres(ltem) + tem
em = M_abs(tex(ltem)/(da + n + 1))
lltem = where(M_abs(tem*em*(1+em)) gt teps*M_abs(tres(ltem)), ntem)
if ntem gt 0 then begin
ltem = ltem(lltem)
tem = tem(lltem)
endif
endwhile
if compf then res(dum) = 1 - tres else res(dum) = tres
endif
dum = where(not sran and lran, ndum)
if ndum gt 0 then begin
len = ceil (-alog(teps)*(4/sqrt(da + 1) > sqrt(da + 1)/4))
alist = double([1l,1 + lindgen(len)/2])
tlist = 1l + 2*lindgen(len/2)
alist(tlist) = alist(tlist) - da
blist = dblarr(len + 1, 2)
blist(tlist,0) = 1
blist([0, tlist + 1],1) = 1
tex = dx(dum)
tres = exp((da - 1)*alog(tex) - tex - M_lngamma(da))* $
(tex*Confrac(alist,blist,tex,eps = teps, /rel))
if compf then res(dum) = tres else res(dum) = 1 - tres
endif
dum = where(not sran and not lran and M_abs(phas) le philim, ndum)
if ndum gt 0 then if compf then res(dum) = 0 else res(dum) = 1
dum = where(not sran and not lran and M_abs(phas) gt philim, ndum)
if ndum gt 0 then begin
message, 'Cannot calculate for large negative values,', /continue
message, 'replacing with machine maximum = ' + $
string (sinf.xmax, form = '(e14.7)'), /continue
res(dum) = sinf.xmax
endif
return, Cast(res,4,typ,/fix)
end