Program Code for Calculation of Gamma Function


/********************************************************************************
*  This PL/1 subroutine calculates the Gamma function using a direct numerical 
*   integration (adaptive stepwise 16-point Gauss quadrature) of Euler's integral.
*
*   Γ(z)=0dt tz-1.e-t
*
*
*  Input parameters are:
*    KV: desired relative accuracy
*    XD: integration stepwidth (recommended =5)
*    Z: argument of gamma function (complex)
*
*  Output parameter is:
*    G: value of Gamma function (complex)
*
*   Note that this program uses extended accuracy because of the possibility
*   that the integrand oscillates rapidly and the integral becomes very small
*   as a result. Normal (double or single) accuracy may not produce correct
*   results in these cases.
*   Note also that this may not be the computationally most efficient method 
*   to calculate the Gamma function. Other methods may be much faster, but 
*   are not as flexible with regard to the desired accuracy for instance.
*
*   This program has worked well and correct for me in the past (using IBM PL/1 
*   compilers), but I can't guarantee this for all compilers, especially if the 
*   code is translated into a different language.
* 
*   If there are any problems, please let me know and I mention the issue here.
*   (for contact details see  http://www.plasmaphysics.org.uk/feedback.htm ).
*
*                                               Thomas Smid, April 2007
*****************************************************************************/

 GAMMA: PROCEDURE (KV,XD,Z,G) ; 
 DEFAULT RANGE(A:Z) COMPLEX FLOAT VALUE (DEC FLOAT(33)) ;
 DCL QG(16) INIT
 (9.894009349916499325961541735E-01, 2.71524594117540948517805725E-02,
 9.445750230732325760779884155E-01, 6.22535239386478928628438370E-02,
 8.656312023878317438804678977E-01, 9.51585116824927848099251076E-02,
 7.554044083550030338951011948E-01, 1.246289712555338720524762822E-01,
 6.178762444026437484466717640E-01, 1.495959888165767320815017305E-01,
 4.580167776572273863424194430E-01, 1.691565193950025381893120790E-01,
 2.816035507792589132304605015E-01, 1.826034150449235888667636680E-01,
 9.50125098376374401853193354E-02, 1.894506104550684962853967232E-01)
 REAL DEC FLOAT(33) ;
 DCL I REAL DEC FIXED(5,0) ;
 DCL (Z,G) COMPLEX DEC FLOAT(33) ;
 DCL (CONVGC,KV,RZ, JJ,XL,XU,XD,EIZ,PI2 INIT(3.141592653589793E00),IZ,
     QYMR,QYMI,GR,GI,CONVGCI,CONVGCR,QYR,QYI,DI,XL0) REAL DEC FLOAT(33) ;

 ON UNDERFLOW ; 
 IZ=ABS(IMAG(Z)) ; RZ=REAL(Z) ; 
 IF IZ>0 THEN EIZ=EXP(PI2/IZ); ELSE EIZ=1E10/KV ;
 QG=QG/2 ;

 XL0=MAX(RZ-1,1) ;  XU=XL0 ;
 XD=XD/(FLOOR(RZ/32)+1) ;

 G=0  ; 
 CONVGC=1 ; JJ=1 ;DI=1; 

 INT:
 DO WHILE(CONVGC>=KV) ;    /* Integration loop */
 IF DI=1 THEN DO ;   /* Integration into positive direction from real maximum  */
 XL=XU ;
 XU=XL+MIN(XL*EIZ-XL,XD) ;
 END ;
 ELSE DO ;   /* Integration into negative direction from real maximum  */
 XU=XL ;     
 XL=MAX(XU/EIZ,XU-XD) ; 
 END ;
 CALL DQG16 ;
 G=G+QY ;
 GR=REAL(G) ;  QYR=REAL(QY) ;
 GI=IMAG(G) ;  QYI=IMAG(QY) ;
 QYMR=ABS(GR)/JJ ;
 QYMI=ABS(GI)/JJ ;
 IF QYMR>0 THEN CONVGCR=ABS(QYR/QYMR);
 IF QYMI>0 THEN CONVGCI=ABS(QYI/QYMI);
 CONVGC=MAX(CONVGCR,CONVGCI) ;
 JJ=JJ+1 ;
 END ;

 IF DI=1 THEN DO ;   
 CONVGC=1 ; DI=-1 ; XL=XL0 ;
 GO TO INT ;   
 END ;


 /* Internal Subroutines */

 FCT:PROCEDURE(X) ;
 DCL X REAL DEC FLOAT(33) ;
 RETURN(X**(Z-1)*EXP(-X))   ;
 END FCT ;

 DQG16: PROCEDURE ;
 A=0.5*(XU+XL) ;
 B=XU-XL ;
 LY=0 ; 
 DO I=1 TO 15 BY 2 ;
 C=QG(I)*B ;
 LY=LY+QG(I+1)*(FCT(A+C)+FCT(A-C)) ;
 END ;
 QY=LY*B ;
 END DQG16 ;

 ENDE: END GAMMA ;	


Programs Home

Home