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

393 lines
11 KiB
Fortran

*DECK DBSKNU
SUBROUTINE DBSKNU (X, FNU, KODE, N, Y, NZ)
C***BEGIN PROLOGUE DBSKNU
C***SUBSIDIARY
C***PURPOSE Subsidiary to DBESK
C***LIBRARY SLATEC
C***TYPE DOUBLE PRECISION (BESKNU-S, DBSKNU-D)
C***AUTHOR Amos, D. E., (SNLA)
C***DESCRIPTION
C
C Abstract **** A DOUBLE PRECISION routine ****
C DBSKNU computes N member sequences of K Bessel functions
C K/SUB(FNU+I-1)/(X), I=1,N for non-negative orders FNU and
C positive X. Equations of the references are implemented on
C small orders DNU for K/SUB(DNU)/(X) and K/SUB(DNU+1)/(X).
C Forward recursion with the three term recursion relation
C generates higher orders FNU+I-1, I=1,...,N. The parameter
C KODE permits K/SUB(FNU+I-1)/(X) values or scaled values
C EXP(X)*K/SUB(FNU+I-1)/(X), I=1,N to be returned.
C
C To start the recursion FNU is normalized to the interval
C -0.5.LE.DNU.LT.0.5. A special form of the power series is
C implemented on 0.LT.X.LE.X1 while the Miller algorithm for the
C K Bessel function in terms of the confluent hypergeometric
C function U(FNU+0.5,2*FNU+1,X) is implemented on X1.LT.X.LE.X2.
C For X.GT.X2, the asymptotic expansion for large X is used.
C When FNU is a half odd integer, a special formula for
C DNU=-0.5 and DNU+1.0=0.5 is used to start the recursion.
C
C The maximum number of significant digits obtainable
C is the smaller of 14 and the number of digits carried in
C DOUBLE PRECISION arithmetic.
C
C DBSKNU assumes that a significant digit SINH function is
C available.
C
C Description of Arguments
C
C INPUT X,FNU are DOUBLE PRECISION
C X - X.GT.0.0D0
C FNU - Order of initial K function, FNU.GE.0.0D0
C N - Number of members of the sequence, N.GE.1
C KODE - A parameter to indicate the scaling option
C KODE= 1 returns
C Y(I)= K/SUB(FNU+I-1)/(X)
C I=1,...,N
C = 2 returns
C Y(I)=EXP(X)*K/SUB(FNU+I-1)/(X)
C I=1,...,N
C
C OUTPUT Y is DOUBLE PRECISION
C Y - A vector whose first N components contain values
C for the sequence
C Y(I)= K/SUB(FNU+I-1)/(X), I=1,...,N or
C Y(I)=EXP(X)*K/SUB(FNU+I-1)/(X), I=1,...,N
C depending on KODE
C NZ - Number of components set to zero due to
C underflow,
C NZ= 0 , normal return
C NZ.NE.0 , first NZ components of Y set to zero
C due to underflow, Y(I)=0.0D0,I=1,...,NZ
C
C Error Conditions
C Improper input arguments - a fatal error
C Overflow - a fatal error
C Underflow with KODE=1 - a non-fatal error (NZ.NE.0)
C
C***SEE ALSO DBESK
C***REFERENCES N. M. Temme, On the numerical evaluation of the modified
C Bessel function of the third kind, Journal of
C Computational Physics 19, (1975), pp. 324-337.
C***ROUTINES CALLED D1MACH, DGAMMA, I1MACH, XERMSG
C***REVISION HISTORY (YYMMDD)
C 790201 DATE WRITTEN
C 890531 Changed all specific intrinsics to generic. (WRB)
C 890911 Removed unnecessary intrinsics. (WRB)
C 891214 Prologue converted to Version 4.0 format. (BAB)
C 900315 CALLs to XERROR changed to CALLs to XERMSG. (THJ)
C 900326 Removed duplicate information from DESCRIPTION section.
C (WRB)
C 900328 Added TYPE section. (WRB)
C 900727 Added EXTERNAL statement. (WRB)
C 910408 Updated the AUTHOR and REFERENCES sections. (WRB)
C 920501 Reformatted the REFERENCES section. (WRB)
C***END PROLOGUE DBSKNU
C
INTEGER I, IFLAG, INU, J, K, KK, KODE, KODED, N, NN, NZ
INTEGER I1MACH
DOUBLE PRECISION A,AK,A1,A2,B,BK,CC,CK,COEF,CX,DK,DNU,DNU2,ELIM,
1 ETEST, EX, F, FC, FHS, FK, FKS, FLRX, FMU, FNU, G1, G2, P, PI,
2 PT, P1, P2, Q, RTHPI, RX, S, SMU, SQK, ST, S1, S2, TM, TOL, T1,
3 T2, X, X1, X2, Y
DIMENSION A(160), B(160), Y(*), CC(8)
DOUBLE PRECISION DGAMMA, D1MACH
EXTERNAL DGAMMA
SAVE X1, X2, PI, RTHPI, CC
DATA X1, X2 / 2.0D0, 17.0D0 /
DATA PI,RTHPI / 3.14159265358979D+00, 1.25331413731550D+00/
DATA CC(1), CC(2), CC(3), CC(4), CC(5), CC(6), CC(7), CC(8)
1 / 5.77215664901533D-01,-4.20026350340952D-02,
2-4.21977345555443D-02, 7.21894324666300D-03,-2.15241674114900D-04,
3-2.01348547807000D-05, 1.13302723200000D-06, 6.11609500000000D-09/
C***FIRST EXECUTABLE STATEMENT DBSKNU
KK = -I1MACH(15)
ELIM = 2.303D0*(KK*D1MACH(5)-3.0D0)
AK = D1MACH(3)
TOL = MAX(AK,1.0D-15)
IF (X.LE.0.0D0) GO TO 350
IF (FNU.LT.0.0D0) GO TO 360
IF (KODE.LT.1 .OR. KODE.GT.2) GO TO 370
IF (N.LT.1) GO TO 380
NZ = 0
IFLAG = 0
KODED = KODE
RX = 2.0D0/X
INU = INT(FNU+0.5D0)
DNU = FNU - INU
IF (ABS(DNU).EQ.0.5D0) GO TO 120
DNU2 = 0.0D0
IF (ABS(DNU).LT.TOL) GO TO 10
DNU2 = DNU*DNU
10 CONTINUE
IF (X.GT.X1) GO TO 120
C
C SERIES FOR X.LE.X1
C
A1 = 1.0D0 - DNU
A2 = 1.0D0 + DNU
T1 = 1.0D0/DGAMMA(A1)
T2 = 1.0D0/DGAMMA(A2)
IF (ABS(DNU).GT.0.1D0) GO TO 40
C SERIES FOR F0 TO RESOLVE INDETERMINACY FOR SMALL ABS(DNU)
S = CC(1)
AK = 1.0D0
DO 20 K=2,8
AK = AK*DNU2
TM = CC(K)*AK
S = S + TM
IF (ABS(TM).LT.TOL) GO TO 30
20 CONTINUE
30 G1 = -S
GO TO 50
40 CONTINUE
G1 = (T1-T2)/(DNU+DNU)
50 CONTINUE
G2 = (T1+T2)*0.5D0
SMU = 1.0D0
FC = 1.0D0
FLRX = LOG(RX)
FMU = DNU*FLRX
IF (DNU.EQ.0.0D0) GO TO 60
FC = DNU*PI
FC = FC/SIN(FC)
IF (FMU.NE.0.0D0) SMU = SINH(FMU)/FMU
60 CONTINUE
F = FC*(G1*COSH(FMU)+G2*FLRX*SMU)
FC = EXP(FMU)
P = 0.5D0*FC/T2
Q = 0.5D0/(FC*T1)
AK = 1.0D0
CK = 1.0D0
BK = 1.0D0
S1 = F
S2 = P
IF (INU.GT.0 .OR. N.GT.1) GO TO 90
IF (X.LT.TOL) GO TO 80
CX = X*X*0.25D0
70 CONTINUE
F = (AK*F+P+Q)/(BK-DNU2)
P = P/(AK-DNU)
Q = Q/(AK+DNU)
CK = CK*CX/AK
T1 = CK*F
S1 = S1 + T1
BK = BK + AK + AK + 1.0D0
AK = AK + 1.0D0
S = ABS(T1)/(1.0D0+ABS(S1))
IF (S.GT.TOL) GO TO 70
80 CONTINUE
Y(1) = S1
IF (KODED.EQ.1) RETURN
Y(1) = S1*EXP(X)
RETURN
90 CONTINUE
IF (X.LT.TOL) GO TO 110
CX = X*X*0.25D0
100 CONTINUE
F = (AK*F+P+Q)/(BK-DNU2)
P = P/(AK-DNU)
Q = Q/(AK+DNU)
CK = CK*CX/AK
T1 = CK*F
S1 = S1 + T1
T2 = CK*(P-AK*F)
S2 = S2 + T2
BK = BK + AK + AK + 1.0D0
AK = AK + 1.0D0
S = ABS(T1)/(1.0D0+ABS(S1)) + ABS(T2)/(1.0D0+ABS(S2))
IF (S.GT.TOL) GO TO 100
110 CONTINUE
S2 = S2*RX
IF (KODED.EQ.1) GO TO 170
F = EXP(X)
S1 = S1*F
S2 = S2*F
GO TO 170
120 CONTINUE
COEF = RTHPI/SQRT(X)
IF (KODED.EQ.2) GO TO 130
IF (X.GT.ELIM) GO TO 330
COEF = COEF*EXP(-X)
130 CONTINUE
IF (ABS(DNU).EQ.0.5D0) GO TO 340
IF (X.GT.X2) GO TO 280
C
C MILLER ALGORITHM FOR X1.LT.X.LE.X2
C
ETEST = COS(PI*DNU)/(PI*X*TOL)
FKS = 1.0D0
FHS = 0.25D0
FK = 0.0D0
CK = X + X + 2.0D0
P1 = 0.0D0
P2 = 1.0D0
K = 0
140 CONTINUE
K = K + 1
FK = FK + 1.0D0
AK = (FHS-DNU2)/(FKS+FK)
BK = CK/(FK+1.0D0)
PT = P2
P2 = BK*P2 - AK*P1
P1 = PT
A(K) = AK
B(K) = BK
CK = CK + 2.0D0
FKS = FKS + FK + FK + 1.0D0
FHS = FHS + FK + FK
IF (ETEST.GT.FK*P1) GO TO 140
KK = K
S = 1.0D0
P1 = 0.0D0
P2 = 1.0D0
DO 150 I=1,K
PT = P2
P2 = (B(KK)*P2-P1)/A(KK)
P1 = PT
S = S + P2
KK = KK - 1
150 CONTINUE
S1 = COEF*(P2/S)
IF (INU.GT.0 .OR. N.GT.1) GO TO 160
GO TO 200
160 CONTINUE
S2 = S1*(X+DNU+0.5D0-P1/P2)/X
C
C FORWARD RECURSION ON THE THREE TERM RECURSION RELATION
C
170 CONTINUE
CK = (DNU+DNU+2.0D0)/X
IF (N.EQ.1) INU = INU - 1
IF (INU.GT.0) GO TO 180
IF (N.GT.1) GO TO 200
S1 = S2
GO TO 200
180 CONTINUE
DO 190 I=1,INU
ST = S2
S2 = CK*S2 + S1
S1 = ST
CK = CK + RX
190 CONTINUE
IF (N.EQ.1) S1 = S2
200 CONTINUE
IF (IFLAG.EQ.1) GO TO 220
Y(1) = S1
IF (N.EQ.1) RETURN
Y(2) = S2
IF (N.EQ.2) RETURN
DO 210 I=3,N
Y(I) = CK*Y(I-1) + Y(I-2)
CK = CK + RX
210 CONTINUE
RETURN
C IFLAG=1 CASES
220 CONTINUE
S = -X + LOG(S1)
Y(1) = 0.0D0
NZ = 1
IF (S.LT.-ELIM) GO TO 230
Y(1) = EXP(S)
NZ = 0
230 CONTINUE
IF (N.EQ.1) RETURN
S = -X + LOG(S2)
Y(2) = 0.0D0
NZ = NZ + 1
IF (S.LT.-ELIM) GO TO 240
NZ = NZ - 1
Y(2) = EXP(S)
240 CONTINUE
IF (N.EQ.2) RETURN
KK = 2
IF (NZ.LT.2) GO TO 260
DO 250 I=3,N
KK = I
ST = S2
S2 = CK*S2 + S1
S1 = ST
CK = CK + RX
S = -X + LOG(S2)
NZ = NZ + 1
Y(I) = 0.0D0
IF (S.LT.-ELIM) GO TO 250
Y(I) = EXP(S)
NZ = NZ - 1
GO TO 260
250 CONTINUE
RETURN
260 CONTINUE
IF (KK.EQ.N) RETURN
S2 = S2*CK + S1
CK = CK + RX
KK = KK + 1
Y(KK) = EXP(-X+LOG(S2))
IF (KK.EQ.N) RETURN
KK = KK + 1
DO 270 I=KK,N
Y(I) = CK*Y(I-1) + Y(I-2)
CK = CK + RX
270 CONTINUE
RETURN
C
C ASYMPTOTIC EXPANSION FOR LARGE X, X.GT.X2
C
C IFLAG=0 MEANS NO UNDERFLOW OCCURRED
C IFLAG=1 MEANS AN UNDERFLOW OCCURRED- COMPUTATION PROCEEDS WITH
C KODED=2 AND A TEST FOR ON SCALE VALUES IS MADE DURING FORWARD
C RECURSION
280 CONTINUE
NN = 2
IF (INU.EQ.0 .AND. N.EQ.1) NN = 1
DNU2 = DNU + DNU
FMU = 0.0D0
IF (ABS(DNU2).LT.TOL) GO TO 290
FMU = DNU2*DNU2
290 CONTINUE
EX = X*8.0D0
S2 = 0.0D0
DO 320 K=1,NN
S1 = S2
S = 1.0D0
AK = 0.0D0
CK = 1.0D0
SQK = 1.0D0
DK = EX
DO 300 J=1,30
CK = CK*(FMU-SQK)/DK
S = S + CK
DK = DK + EX
AK = AK + 8.0D0
SQK = SQK + AK
IF (ABS(CK).LT.TOL) GO TO 310
300 CONTINUE
310 S2 = S*COEF
FMU = FMU + 8.0D0*DNU + 4.0D0
320 CONTINUE
IF (NN.GT.1) GO TO 170
S1 = S2
GO TO 200
330 CONTINUE
KODED = 2
IFLAG = 1
GO TO 120
C
C FNU=HALF ODD INTEGER CASE
C
340 CONTINUE
S1 = COEF
S2 = COEF
GO TO 170
C
C
350 CALL XERMSG ('SLATEC', 'DBSKNU', 'X NOT GREATER THAN ZERO', 2, 1)
RETURN
360 CALL XERMSG ('SLATEC', 'DBSKNU', 'FNU NOT ZERO OR POSITIVE', 2,
+ 1)
RETURN
370 CALL XERMSG ('SLATEC', 'DBSKNU', 'KODE NOT 1 OR 2', 2, 1)
RETURN
380 CALL XERMSG ('SLATEC', 'DBSKNU', 'N NOT GREATER THAN 0', 2, 1)
RETURN
END