OpenLibm/slatec/cpsi.f
Viral B. Shah c977aa998f Add Makefile.extras to build libopenlibm-extras.
Replace amos with slatec
2012-12-31 16:37:05 -05:00

110 lines
3.5 KiB
Fortran

*DECK CPSI
COMPLEX FUNCTION CPSI (ZIN)
C***BEGIN PROLOGUE CPSI
C***PURPOSE Compute the Psi (or Digamma) function.
C***LIBRARY SLATEC (FNLIB)
C***CATEGORY C7C
C***TYPE COMPLEX (PSI-S, DPSI-D, CPSI-C)
C***KEYWORDS DIGAMMA FUNCTION, FNLIB, PSI FUNCTION, SPECIAL FUNCTIONS
C***AUTHOR Fullerton, W., (LANL)
C***DESCRIPTION
C
C PSI(X) calculates the psi (or digamma) function of X. PSI(X)
C is the logarithmic derivative of the gamma function of X.
C
C***REFERENCES (NONE)
C***ROUTINES CALLED CCOT, R1MACH, XERMSG
C***REVISION HISTORY (YYMMDD)
C 780501 DATE WRITTEN
C 890531 Changed all specific intrinsics to generic. (WRB)
C 890531 REVISION DATE from Version 3.2
C 891214 Prologue converted to Version 4.0 format. (BAB)
C 900315 CALLs to XERROR changed to CALLs to XERMSG. (THJ)
C 900727 Added EXTERNAL statement. (WRB)
C***END PROLOGUE CPSI
COMPLEX ZIN, Z, Z2INV, CORR, CCOT
DIMENSION BERN(13)
LOGICAL FIRST
EXTERNAL CCOT
SAVE BERN, PI, NTERM, BOUND, DXREL, RMIN, RBIG, FIRST
DATA BERN( 1) / .8333333333 3333333 E-1 /
DATA BERN( 2) / -.8333333333 3333333 E-2 /
DATA BERN( 3) / .3968253968 2539683 E-2 /
DATA BERN( 4) / -.4166666666 6666667 E-2 /
DATA BERN( 5) / .7575757575 7575758 E-2 /
DATA BERN( 6) / -.2109279609 2796093 E-1 /
DATA BERN( 7) / .8333333333 3333333 E-1 /
DATA BERN( 8) / -.4432598039 2156863 E0 /
DATA BERN( 9) / .3053954330 2701197 E1 /
DATA BERN(10) / -.2645621212 1212121 E2 /
DATA BERN(11) / .2814601449 2753623 E3 /
DATA BERN(12) / -.3454885393 7728938 E4 /
DATA BERN(13) / .5482758333 3333333 E5 /
DATA PI / 3.141592653 589793 E0 /
DATA FIRST /.TRUE./
C***FIRST EXECUTABLE STATEMENT CPSI
IF (FIRST) THEN
NTERM = -0.30*LOG(R1MACH(3))
C MAYBE BOUND = N*(0.1*EPS)**(-1/(2*N-1)) / (PI*EXP(1))
BOUND = 0.1171*NTERM*(0.1*R1MACH(3))**(-1.0/(2*NTERM-1))
DXREL = SQRT(R1MACH(4))
RMIN = EXP (MAX (LOG(R1MACH(1)), -LOG(R1MACH(2))) + 0.011 )
RBIG = 1.0/R1MACH(3)
ENDIF
FIRST = .FALSE.
C
Z = ZIN
X = REAL(Z)
Y = AIMAG(Z)
IF (Y.LT.0.0) Z = CONJG(Z)
C
CORR = (0.0, 0.0)
CABSZ = ABS(Z)
IF (X.GE.0.0 .AND. CABSZ.GT.BOUND) GO TO 50
IF (X.LT.0.0 .AND. ABS(Y).GT.BOUND) GO TO 50
C
IF (CABSZ.LT.BOUND) GO TO 20
C
C USE THE REFLECTION FORMULA FOR REAL(Z) NEGATIVE, ABS(Z) LARGE, AND
C ABS(AIMAG(Y)) SMALL.
C
CORR = -PI*CCOT(PI*Z)
Z = 1.0 - Z
GO TO 50
C
C USE THE RECURSION RELATION FOR ABS(Z) SMALL.
C
20 IF (CABSZ .LT. RMIN) CALL XERMSG ('SLATEC', 'CPSI',
+ 'CPSI CALLED WITH Z SO NEAR 0 THAT CPSI OVERFLOWS', 2, 2)
C
IF (X.GE.(-0.5) .OR. ABS(Y).GT.DXREL) GO TO 30
IF (ABS((Z-AINT(X-0.5))/X) .LT. DXREL) CALL XERMSG ('SLATEC',
+ 'CPSI',
+ 'ANSWER LT HALF PRECISION BECAUSE Z TOO NEAR NEGATIVE INTEGER',
+ 1, 1)
IF (Y .EQ. 0.0 .AND. X .EQ. AINT(X)) CALL XERMSG ('SLATEC',
+ 'CPSI', 'Z IS A NEGATIVE INTEGER', 3, 2)
C
30 N = SQRT(BOUND**2-Y**2) - X + 1.0
DO 40 I=1,N
CORR = CORR - 1.0/Z
Z = Z + 1.0
40 CONTINUE
C
C NOW EVALUATE THE ASYMPTOTIC SERIES FOR SUITABLY LARGE Z.
C
50 IF (CABSZ.GT.RBIG) CPSI = LOG(Z) + CORR
IF (CABSZ.GT.RBIG) GO TO 70
C
CPSI = (0.0, 0.0)
Z2INV = 1.0/Z**2
DO 60 I=1,NTERM
NDX = NTERM + 1 - I
CPSI = BERN(NDX) + Z2INV*CPSI
60 CONTINUE
CPSI = LOG(Z) - 0.5/Z - CPSI*Z2INV + CORR
C
70 IF (Y.LT.0.0) CPSI = CONJG(CPSI)
C
RETURN
END