在 Fortran 中查找复根
Finding complex root in Fortran
我发现了一些资源,其中建议使用算法来确定一般分析函数(无多项式)中的复根。例如。 “Muller 求解非线性方程的 Fortran 程序
方法”,由 I. Barrodale 和 K. B. Wilson 编写。不幸的是,该代码仅以 pdf 格式提供,并且转换为 ASCII 非常麻烦……还有 Henning Bach,第 121 卷,第 12 期,第 675-678 页,1969 年 12 月. 它在 ASCII 中可用。字母 1 工作正常但对我的目的来说相当慢。在 Fortran 中是否有计算复数根的标准例程?
谢谢 :)
对于那些有兴趣的人。我从 I. Barrodale 和 K. B. Wilson 那里拿了一张。由于这篇文章是免费在线阅读的,所以我想 post 这里的代码。这是迄今为止我发现的最快和最可靠的。要使用它,请定义一个子程序 calcf(x,f)。 f 是 x 的函数值。 x 和 f 是复数。
了解更多信息 -> http://www.sciencedirect.com/science/article/pii/0771050X78900414
这是双精度版本:
SUBROUTINE ROOTS(KNOWN,NMORE,KM,REALRT,EP1,EP2,GUESS,MAXITS,RTS,NFOUND, FNV, IFAIL)
COMPLEX*16 RTS(KM), FNV(KM), X1, X2, X3, F1, F2, F3, &
X21, X32, F21, F32, F31, F321, B, XNEW, FNEW, DENOM, &
FSAVE, CSQRT, RADICL, RT, DIF, CSTEP, FSLAST
REAL*8 EP1, EP2, ONE, HUNDRD, TWO, FOUR, HALF, STEP, &
ZERO, EP1DEF, EP2DEF
INTEGER GUESS
LOGICAL REALRT
DATA IZERO,IONE,ITWO,ITHREE,ZERO,HALF,ONE,TWO,FOUR,HUNDRD,ITSDEF,EP1DEF,EP2DEF &
/0,1,2,3,0.0d0,0.5d0,1.0d0,2.0d0,4.0d0,100.0d0,100,0.5d-5,1.0d-6/
EP1 = AMAX1(EP1,EP1DEF)
EP2 = AMAX1(EP2,EP2DEF)
MAXITS = MIN0(MAXITS,ITSDEF)
IFAIL = IZERO
NFOUND = IZERO
IF (KNOWN.LT.IONE) GO TO 30
DO 10 I=1,KNOWN
II = I
CALL CALCF(RTS(I), FNV(I))
IF (ABS(FNV(II)).GE.EP2) GO TO 20
10 CONTINUE
20 IFAIL =IONE
GUESS = GUESS + KNOWN - II +IONE
NMORE = NMORE + KNOWN - II +IONE
KNOWN = II - IONE
30 CONTINUE
LOOP1 = KNOWN +IONE
LOOP2 = KNOWN + NMORE
IF (LOOP1.GT.LOOP2 .OR. LOOP1.LT.IONE) GO TO 180
IF (GUESS-NMORE) 40, 70, 60
40 ILO = GUESS + IONE
DO 50 I=ILO,LOOP2
RTS(I) = ZERO
50 CONTINUE
GO TO 70
60 CONTINUE
GUESS = NMORE
70 CONTINUE
STEP = HALF
DO 160 NEW=LOOP1,LOOP2
KOUNT = ITHREE
NEWM1 = NEW - IONE
RT = RTS(NEW)
X1 = RT - STEP
X2 = RT + STEP
X3 = RT
CALL CALCF(X1, F1)
CALL CALCF(X2, F2)
CALL CALCF(X3, F3)
FSLAST = F3
IF (NEW.GT.IONE) CALL TEST(X1, F1, FSAVE, RTS,NEWM1, EP2, KOUNT)
IF (NEW.GT.IONE) CALL TEST(X2, F2, FSAVE, RTS,NEWM1, EP2, KOUNT)
IF (NEW.GT.IONE) CALL TEST(X3, F3, FSLAST, RTS,NEWM1, EP2, KOUNT)
F21 = (F2-F1)/(X2-X1)
80 X32 = X3 - X2
F32 = (F3-F2)/X32
F321 = (F32-F21)/(X3-X1)
B = F32 + X32*F321
RADICL = B**ITWO - FOUR*F321*F3
IF (REALRT .AND. REAL(RADICL).LT.ZERO) RADICL = ZERO
RADICL = SQRT(RADICL)
IF (REAL(B)*REAL(RADICL)+AIMAG(B)*AIMAG(RADICL).LT.ZERO) RADICL = -RADICL
DENOM = B + RADICL
IF (ABS(DENOM).NE.ZERO) GO TO 100
IF (ABS(F3).GE.EP2) GO TO 90
XNEW = X3
GO TO 120
90 XNEW = X3 + X32
GO TO 120
100 CSTEP = TWO*F3/DENOM
IF (.NOT.REALRT .OR. ABS(F3).EQ.ZERO .OR. ABS(F32).EQ.ZERO) GO TO 110
CSTEP = F32/ABS(F32)*F3/ABS(F3)*ABS(CSTEP)
110 XNEW = X3 - CSTEP
120 CALL CALCF(XNEW, FNEW)
FSAVE = FNEW
IF (NEW.LE.IONE) GO TO 130
CALL TEST(XNEW, FNEW, FSAVE, RTS, NEWM1, EP2,KOUNT)
130 KOUNT = KOUNT +IONE
IF (KOUNT.GT.MAXITS) GO TO 170
DIF = XNEW - X3
IF (ABS(DIF).LT.EP1*ABS(XNEW)) GO TO 150
IF (ABS(FSAVE).LT.EP2) GO TO 150
IF (REALRT .OR. ABS(FSAVE).LT.HUNDRD*ABS(FSLAST)) GO TO 140
CSTEP = CSTEP*HALF
XNEW = XNEM + CSTEP
GO TO 120
140 X1 = X2
X2 = X3
X3 = XNEW
F1 = F2
F2 = F3
F3 = FNEW
FSLAST = FSAVE
F21 = F32
GO TO 80
150 CONTINUE
RTS(NEW) = XNEW
FNV(NEW) = FSAVE
NFOUND = NEW
160 CONTINUE
GO TO 190
170 CONTINUE
RTS(NEW) = XNEW
FNV(NEW) = FSAVE
IFAIL = ITHREE
GO TO 190
180 CONTINUE
IFAIL = ITWO
190 CONTINUE
RETURN
END
SUBROUTINE TEST(X, F, FSAVE, RTS, K, EPS, KOUNT)
COMPLEX*16 X, F, RTS(K), D, FSAVE
REAL*8 EPS!, CABS
DATA IONE, PERTB /1,0.01d0/
10 CONTINUE
DO 20 I=1,K
D = X - RTS(I)
IF (ABS(D).LE.EPS) GO TO 30
F = F/D
20 CONTINUE
GO TO 40
30 CONTINUE
X = X + PERTB
CALL CALCF(X, F)
FSAVE = F
KOUNT = KOUNT +IONE
GO TO 10
40 RETURN
END
我已经修改了 ROOTS 子例程,并针对 gfortran 对其进行了调整(例如,REALPART 和 IMAGPART 用于复杂变量)。还更正了 KELLEKAI 发布的源代码中的一个错误,即 XNEW = XNEM + CSTEP,显然应该是 XNEW = XNEW + CSTEP(这就是为什么 IMPLICIT NONE 更可取)。原始评论也包括在内。我测试了具有多个复根的非线性方程的子程序,它工作正常。
C source code from I. Barrodale and K. B. Wilson,
C "A Fortran program for solving a nonlinear equation by Muller's method"
C Journal of Computational and Applied Mathematics, vol. 4, no. 2, 1978
cccccCcccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxccCCCCCCCC
SUBROUTINE ROOTS(KNOWN, NMORE, KM, REALRT, EP1, EP2, ROO 10
& GUESS, MAXITS, RTS, NFOUND, FNV, IFAIL) ROO 20
C-----------------------------------------------------------------------
C The user must supply a subprogram as follows
C SUBROUTINE CALCF (X, F)
C where X and F are complex numbers, X is an independent variable
C and F is the corresponding function value.
C-----------------------------------------------------------------------
C
C This subroutine uses Muller's method to find roots (real or complex)
C of a general equation
C
C Description of parameters:
C
C KNOWN an INTEGER denoting the number of roots already known.
C If the function value for one of these "known" roots
C is not "small" the value of known is reset to the last
C index of a root with a small function value, and the
C remaining "known" roots are recalculated.
C NMORE an INTEGER denoting the number of roots to be found
C (i.e. in addition to those already known).
C NMORE is reset to account for the case when KNOWN is reset.
C KM an INTEGER used to define dimensions.
C KM must be set at least (KNOWN + NMORE)
C REALRT a LOGICAL variable with values as follows:
C .TRUE. indicates that only REAL roots are to be found
C (i.e. complex numbers with zero imaginary parts)
C .FALSE. indicates that complex roots are to be found
C EP1 a small positive real number denoting the "first"
C convergence criterion: if at the K-th stage the relative
C change in two successive approximations to a root is less
C than EP1, convergence is said to have taken place
C (i.e. the absolute value of (ROOT(K)-ROOT(K-1))/ROOT(K)
C is less than EP1 the convergence occurs). See below for
C minimum default values
C EP2 a small positive real number denoting the "second"
C convergence criterion: if at anu stage the absolute value
C of the function is less than EP2, convergence is said to
C have taken place. See below for minimum default values.
C EP2 is also used by SUBROUTINE TEST to determine if a
C current approximation is "close" to a root already identified
C GUESS an INTEGER denoting the number of roots for which the user
C is supplying estimates. GUESS is reset to account for the
C case when KNOWN is reset. Also, GUESS must not exceed NMORE.
C MAXITS an INTEGER denoting the maximum number of function calls
C allowed when finding any root. If MAXITS function evaluations
C are performed the subroutine "fails" and return control to
C the user. The roots already found and the last approximation
C to the root causing "failure" are stored in RTS. See below
C for maximum default values.
C RTS a COMPLEX vector of length at least KM:
C On entry if any roots are available they must be in
C positions 1 to KNOWN of RTS.
C On entry, if estimates of the roots to be found are known,
C (i.e. GUESS.GT.ZERO) they must be in positions
C (KNOWN+1) to (KNOWN + GUESS).
C On return the roots of the equation are stored in the first
C NFOUND positions. If "failure" due to MAXITS return, the
C (NFOUND+1) position of RTS contains the last approximation
C to the root which caused the "failure".
C NFOUND an INTEGER denoting the number of roots now known and
C stored in RTS.
C FNV a COMPLEX vector of length at least KM containing the
C function values associated with the vector RTS.
C IFAIL an integer exit code with values as follows:
C 0 indicates all roots were found as requested by the user
C 1 indicates (as above) all roots were found but in addition
C some of the input "known" roots were recalculated
C 2 if the input parameters KNOWN or NMORE satisfy the
C following: KNOWN.LT.0, NMORE.LT.1 control is returned
C immediately to the user
C 3 if MAXITS causes "failure" control is returned
C immediately to the user
cccccCcccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxccCCCCCCCC
INTEGER KNOWN, NMORE, KM, GUESS, MAXITS, NFOUND, IFAIL ROO 30
COMPLEX*16 RTS(KM), FNV(KM), X1, X2, X3, F1, F2, F3, ROO 40
& X21, X32, F21, F32, F31, F321, B, XNEW, FNEW, DENOM, ROO 50
& FSAVE, CSQRT, RADICL, RT, DIF, CSTEP, FSLAST ROO 60
REAL*8 EP1, EP2, ONE, HUNDRD, TWO, FOUR, HALF, STEP, ROO 70
& ZERO, EP1DEF, EP2DEF ROO 80
LOGICAL REALRT ROO 90
DATA IZERO, IONE, ITWO, ITHREE, ZERO, HALF, ONE, TWO, ROO 100
& FOUR, HUNDRD, ITSDEF, EP1DEF, EP2DEF ROO 110
& /0,1,2,3,0.0d0,0.5d0,1.0d0,2.0d0,4.0d0,100.0d0,100, ROO 120
& 0.5D-6,1.0D-7/ ROO 130
C
C Initialization
C Check for errors in the input and set default values if necessary
C
EP1 = DMAX1(EP1,EP1DEF)
EP2 = DMAX1(EP2,EP2DEF)
MAXITS = MIN0(MAXITS,ITSDEF)
IFAIL = IZERO
NFOUND = IZERO
IF (KNOWN.LT.IONE) GO TO 30
DO 10 I=1,KNOWN
II = I
CALL CALCF(RTS(I), FNV(I))
C no record is kept of the number of function evaluations
C used here to ckeck the list of known roots
IF (ABS(FNV(II)).GE.EP2) GO TO 20
10 CONTINUE
20 IFAIL =IONE
GUESS = GUESS + KNOWN - II +IONE
NMORE = NMORE + KNOWN - II +IONE
KNOWN = II - IONE
30 CONTINUE
LOOP1 = KNOWN +IONE
LOOP2 = KNOWN + NMORE
IF (LOOP1.GT.LOOP2 .OR. LOOP1.LT.IONE) GO TO 180
IF (GUESS-NMORE) 40, 70, 60
40 ILO = GUESS + IONE
DO 50 I=ILO,LOOP2
RTS(I) = ZERO
50 CONTINUE
GO TO 70
60 CONTINUE
GUESS = NMORE
70 CONTINUE
STEP = HALF
C
C try to find NMORE roots in this major loop
DO 160 NEW=LOOP1,LOOP2
KOUNT = ITHREE
NEWM1 = NEW - IONE
RT = RTS(NEW)
X1 = RT - STEP
X2 = RT + STEP
X3 = RT
C use first estimates
CALL CALCF(X1, F1)
CALL CALCF(X2, F2)
CALL CALCF(X3, F3)
FSLAST = F3
IF (NEW.GT.IONE)
& CALL TEST(X1, F1, FSAVE, RTS, NEWM1, EP2, KOUNT)
IF (NEW.GT.IONE)
& CALL TEST(X2, F2, FSAVE, RTS, NEWM1, EP2, KOUNT)
IF (NEW.GT.IONE)
& CALL TEST(X3, F3, FSLAST, RTS, NEWM1, EP2, KOUNT)
F21 = (F2-F1)/(X2-X1)
C find the roots of the quadratic
80 X32 = X3 - X2
F32 = (F3-F2)/X32
F321 = (F32-F21)/(X3-X1)
B = F32 + X32*F321
RADICL = B**ITWO - FOUR*F321*F3
IF (REALRT .AND. REALPART(RADICL) .LT. ZERO) RADICL = ZERO
RADICL = CDSQRT(RADICL)
IF (
& (REALPART(B)*REALPART(RADICL)+IMAGPART(B)*IMAGPART(RADICL)
& ) .LT. ZERO) RADICL = -RADICL
DENOM = B + RADICL
IF (ABS(DENOM).NE.ZERO) GO TO 100
IF (ABS(F3).GE.EP2) GO TO 90
XNEW = X3
GO TO 120
90 XNEW = X3 + X32
GO TO 120
100 CSTEP = TWO*F3/DENOM
IF (.NOT. REALRT .OR. ABS(F3) .EQ. ZERO .OR.
& ABS(F32) .EQ. ZERO) GO TO 110
CSTEP = F32/ABS(F32)*F3/ABS(F3)*ABS(CSTEP)
110 XNEW = X3 - CSTEP
120 CALL CALCF(XNEW, FNEW)
FSAVE = FNEW
IF (NEW.LE.IONE) GO TO 130
CALL TEST(XNEW, FNEW, FSAVE, RTS, NEWM1, EP2,KOUNT)
130 KOUNT = KOUNT +IONE
C test iterations, convergence and divergence
IF (KOUNT.GT.MAXITS) GO TO 170
DIF = XNEW - X3
IF (ABS(DIF).LT.EP1*ABS(XNEW)) GO TO 150
IF (ABS(FSAVE).LT.EP2) GO TO 150
IF (REALRT .OR. ABS(FSAVE) .LT. HUNDRD*ABS(FSLAST))
& GO TO 140
C divergence "fix"
CSTEP = CSTEP*HALF
XNEW = XNEW + CSTEP
GO TO 120
140 X1 = X2
X2 = X3
X3 = XNEW
F1 = F2
F2 = F3
F3 = FNEW
FSLAST = FSAVE
F21 = F32
GO TO 80
150 CONTINUE
C convergence to one more root
C (the number of function evaluations used in determining the current root
C is available at this stage; output the variable KOUNT if desired)
write(*,*) ' number function evaluations = ', KOUNT
RTS(NEW) = XNEW
FNV(NEW) = FSAVE
NFOUND = NEW
160 CONTINUE
GO TO 190
170 CONTINUE
C MAXITS reached
RTS(NEW) = XNEW
FNV(NEW) = FSAVE
IFAIL = ITHREE
GO TO 190
180 CONTINUE
IFAIL = ITWO
190 CONTINUE
RETURN
END SUBROUTINE ROOTS
cccccCcccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxccCCCCCCCC
SUBROUTINE TEST(X, F, FSAVE, RTS, K, EPS, KOUNT) TES 10
C
C This subroutine serves two purposes:
C 1. Deflation of the function is performed,
C i.e. if X is the current approximation to a root
C and RTS is a vector of roots already known, the
C deflated function value is
C F=(...((F.(X-RTS(1)))/(X-RTS(2)))/...)
C 2. If a current approximation to a root is "too close"
C to a root already known, X is perturbed away from
C the known root by 0.01. This device avoids division
C by (essentially) zero in the deflation process, but it
C does not prevent convergence to multiple zeros.
C
COMPLEX*16 X, F, RTS(K), D, FSAVE TES 20
REAL*8 EPS, PERTB TES 30
DATA IONE, PERTB /1, 0.01D0/ TES 40
10 CONTINUE TES 50
DO 20 I=1,K TES 60
D = X - RTS(I) TES 70
IF (ABS(D) .LE. EPS) GO TO 30 TES 80
F = F/D TES 90
20 CONTINUE TES 100
GO TO 40 TES 110
30 CONTINUE TES 120
X = X + PERTB TES 130
CALL CALCF(X, F) TES 140
FSAVE = F TES 150
KOUNT = KOUNT + IONE TES 160
GO TO 10 TES 170
40 RETURN TES 180
END SUBROUTINE TEST TES 190
我发现了一些资源,其中建议使用算法来确定一般分析函数(无多项式)中的复根。例如。 “Muller 求解非线性方程的 Fortran 程序 方法”,由 I. Barrodale 和 K. B. Wilson 编写。不幸的是,该代码仅以 pdf 格式提供,并且转换为 ASCII 非常麻烦……还有 Henning Bach,第 121 卷,第 12 期,第 675-678 页,1969 年 12 月. 它在 ASCII 中可用。字母 1 工作正常但对我的目的来说相当慢。在 Fortran 中是否有计算复数根的标准例程?
谢谢 :)
对于那些有兴趣的人。我从 I. Barrodale 和 K. B. Wilson 那里拿了一张。由于这篇文章是免费在线阅读的,所以我想 post 这里的代码。这是迄今为止我发现的最快和最可靠的。要使用它,请定义一个子程序 calcf(x,f)。 f 是 x 的函数值。 x 和 f 是复数。
了解更多信息 -> http://www.sciencedirect.com/science/article/pii/0771050X78900414
这是双精度版本:
SUBROUTINE ROOTS(KNOWN,NMORE,KM,REALRT,EP1,EP2,GUESS,MAXITS,RTS,NFOUND, FNV, IFAIL)
COMPLEX*16 RTS(KM), FNV(KM), X1, X2, X3, F1, F2, F3, &
X21, X32, F21, F32, F31, F321, B, XNEW, FNEW, DENOM, &
FSAVE, CSQRT, RADICL, RT, DIF, CSTEP, FSLAST
REAL*8 EP1, EP2, ONE, HUNDRD, TWO, FOUR, HALF, STEP, &
ZERO, EP1DEF, EP2DEF
INTEGER GUESS
LOGICAL REALRT
DATA IZERO,IONE,ITWO,ITHREE,ZERO,HALF,ONE,TWO,FOUR,HUNDRD,ITSDEF,EP1DEF,EP2DEF &
/0,1,2,3,0.0d0,0.5d0,1.0d0,2.0d0,4.0d0,100.0d0,100,0.5d-5,1.0d-6/
EP1 = AMAX1(EP1,EP1DEF)
EP2 = AMAX1(EP2,EP2DEF)
MAXITS = MIN0(MAXITS,ITSDEF)
IFAIL = IZERO
NFOUND = IZERO
IF (KNOWN.LT.IONE) GO TO 30
DO 10 I=1,KNOWN
II = I
CALL CALCF(RTS(I), FNV(I))
IF (ABS(FNV(II)).GE.EP2) GO TO 20
10 CONTINUE
20 IFAIL =IONE
GUESS = GUESS + KNOWN - II +IONE
NMORE = NMORE + KNOWN - II +IONE
KNOWN = II - IONE
30 CONTINUE
LOOP1 = KNOWN +IONE
LOOP2 = KNOWN + NMORE
IF (LOOP1.GT.LOOP2 .OR. LOOP1.LT.IONE) GO TO 180
IF (GUESS-NMORE) 40, 70, 60
40 ILO = GUESS + IONE
DO 50 I=ILO,LOOP2
RTS(I) = ZERO
50 CONTINUE
GO TO 70
60 CONTINUE
GUESS = NMORE
70 CONTINUE
STEP = HALF
DO 160 NEW=LOOP1,LOOP2
KOUNT = ITHREE
NEWM1 = NEW - IONE
RT = RTS(NEW)
X1 = RT - STEP
X2 = RT + STEP
X3 = RT
CALL CALCF(X1, F1)
CALL CALCF(X2, F2)
CALL CALCF(X3, F3)
FSLAST = F3
IF (NEW.GT.IONE) CALL TEST(X1, F1, FSAVE, RTS,NEWM1, EP2, KOUNT)
IF (NEW.GT.IONE) CALL TEST(X2, F2, FSAVE, RTS,NEWM1, EP2, KOUNT)
IF (NEW.GT.IONE) CALL TEST(X3, F3, FSLAST, RTS,NEWM1, EP2, KOUNT)
F21 = (F2-F1)/(X2-X1)
80 X32 = X3 - X2
F32 = (F3-F2)/X32
F321 = (F32-F21)/(X3-X1)
B = F32 + X32*F321
RADICL = B**ITWO - FOUR*F321*F3
IF (REALRT .AND. REAL(RADICL).LT.ZERO) RADICL = ZERO
RADICL = SQRT(RADICL)
IF (REAL(B)*REAL(RADICL)+AIMAG(B)*AIMAG(RADICL).LT.ZERO) RADICL = -RADICL
DENOM = B + RADICL
IF (ABS(DENOM).NE.ZERO) GO TO 100
IF (ABS(F3).GE.EP2) GO TO 90
XNEW = X3
GO TO 120
90 XNEW = X3 + X32
GO TO 120
100 CSTEP = TWO*F3/DENOM
IF (.NOT.REALRT .OR. ABS(F3).EQ.ZERO .OR. ABS(F32).EQ.ZERO) GO TO 110
CSTEP = F32/ABS(F32)*F3/ABS(F3)*ABS(CSTEP)
110 XNEW = X3 - CSTEP
120 CALL CALCF(XNEW, FNEW)
FSAVE = FNEW
IF (NEW.LE.IONE) GO TO 130
CALL TEST(XNEW, FNEW, FSAVE, RTS, NEWM1, EP2,KOUNT)
130 KOUNT = KOUNT +IONE
IF (KOUNT.GT.MAXITS) GO TO 170
DIF = XNEW - X3
IF (ABS(DIF).LT.EP1*ABS(XNEW)) GO TO 150
IF (ABS(FSAVE).LT.EP2) GO TO 150
IF (REALRT .OR. ABS(FSAVE).LT.HUNDRD*ABS(FSLAST)) GO TO 140
CSTEP = CSTEP*HALF
XNEW = XNEM + CSTEP
GO TO 120
140 X1 = X2
X2 = X3
X3 = XNEW
F1 = F2
F2 = F3
F3 = FNEW
FSLAST = FSAVE
F21 = F32
GO TO 80
150 CONTINUE
RTS(NEW) = XNEW
FNV(NEW) = FSAVE
NFOUND = NEW
160 CONTINUE
GO TO 190
170 CONTINUE
RTS(NEW) = XNEW
FNV(NEW) = FSAVE
IFAIL = ITHREE
GO TO 190
180 CONTINUE
IFAIL = ITWO
190 CONTINUE
RETURN
END
SUBROUTINE TEST(X, F, FSAVE, RTS, K, EPS, KOUNT)
COMPLEX*16 X, F, RTS(K), D, FSAVE
REAL*8 EPS!, CABS
DATA IONE, PERTB /1,0.01d0/
10 CONTINUE
DO 20 I=1,K
D = X - RTS(I)
IF (ABS(D).LE.EPS) GO TO 30
F = F/D
20 CONTINUE
GO TO 40
30 CONTINUE
X = X + PERTB
CALL CALCF(X, F)
FSAVE = F
KOUNT = KOUNT +IONE
GO TO 10
40 RETURN
END
我已经修改了 ROOTS 子例程,并针对 gfortran 对其进行了调整(例如,REALPART 和 IMAGPART 用于复杂变量)。还更正了 KELLEKAI 发布的源代码中的一个错误,即 XNEW = XNEM + CSTEP,显然应该是 XNEW = XNEW + CSTEP(这就是为什么 IMPLICIT NONE 更可取)。原始评论也包括在内。我测试了具有多个复根的非线性方程的子程序,它工作正常。
C source code from I. Barrodale and K. B. Wilson,
C "A Fortran program for solving a nonlinear equation by Muller's method"
C Journal of Computational and Applied Mathematics, vol. 4, no. 2, 1978
cccccCcccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxccCCCCCCCC
SUBROUTINE ROOTS(KNOWN, NMORE, KM, REALRT, EP1, EP2, ROO 10
& GUESS, MAXITS, RTS, NFOUND, FNV, IFAIL) ROO 20
C-----------------------------------------------------------------------
C The user must supply a subprogram as follows
C SUBROUTINE CALCF (X, F)
C where X and F are complex numbers, X is an independent variable
C and F is the corresponding function value.
C-----------------------------------------------------------------------
C
C This subroutine uses Muller's method to find roots (real or complex)
C of a general equation
C
C Description of parameters:
C
C KNOWN an INTEGER denoting the number of roots already known.
C If the function value for one of these "known" roots
C is not "small" the value of known is reset to the last
C index of a root with a small function value, and the
C remaining "known" roots are recalculated.
C NMORE an INTEGER denoting the number of roots to be found
C (i.e. in addition to those already known).
C NMORE is reset to account for the case when KNOWN is reset.
C KM an INTEGER used to define dimensions.
C KM must be set at least (KNOWN + NMORE)
C REALRT a LOGICAL variable with values as follows:
C .TRUE. indicates that only REAL roots are to be found
C (i.e. complex numbers with zero imaginary parts)
C .FALSE. indicates that complex roots are to be found
C EP1 a small positive real number denoting the "first"
C convergence criterion: if at the K-th stage the relative
C change in two successive approximations to a root is less
C than EP1, convergence is said to have taken place
C (i.e. the absolute value of (ROOT(K)-ROOT(K-1))/ROOT(K)
C is less than EP1 the convergence occurs). See below for
C minimum default values
C EP2 a small positive real number denoting the "second"
C convergence criterion: if at anu stage the absolute value
C of the function is less than EP2, convergence is said to
C have taken place. See below for minimum default values.
C EP2 is also used by SUBROUTINE TEST to determine if a
C current approximation is "close" to a root already identified
C GUESS an INTEGER denoting the number of roots for which the user
C is supplying estimates. GUESS is reset to account for the
C case when KNOWN is reset. Also, GUESS must not exceed NMORE.
C MAXITS an INTEGER denoting the maximum number of function calls
C allowed when finding any root. If MAXITS function evaluations
C are performed the subroutine "fails" and return control to
C the user. The roots already found and the last approximation
C to the root causing "failure" are stored in RTS. See below
C for maximum default values.
C RTS a COMPLEX vector of length at least KM:
C On entry if any roots are available they must be in
C positions 1 to KNOWN of RTS.
C On entry, if estimates of the roots to be found are known,
C (i.e. GUESS.GT.ZERO) they must be in positions
C (KNOWN+1) to (KNOWN + GUESS).
C On return the roots of the equation are stored in the first
C NFOUND positions. If "failure" due to MAXITS return, the
C (NFOUND+1) position of RTS contains the last approximation
C to the root which caused the "failure".
C NFOUND an INTEGER denoting the number of roots now known and
C stored in RTS.
C FNV a COMPLEX vector of length at least KM containing the
C function values associated with the vector RTS.
C IFAIL an integer exit code with values as follows:
C 0 indicates all roots were found as requested by the user
C 1 indicates (as above) all roots were found but in addition
C some of the input "known" roots were recalculated
C 2 if the input parameters KNOWN or NMORE satisfy the
C following: KNOWN.LT.0, NMORE.LT.1 control is returned
C immediately to the user
C 3 if MAXITS causes "failure" control is returned
C immediately to the user
cccccCcccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxccCCCCCCCC
INTEGER KNOWN, NMORE, KM, GUESS, MAXITS, NFOUND, IFAIL ROO 30
COMPLEX*16 RTS(KM), FNV(KM), X1, X2, X3, F1, F2, F3, ROO 40
& X21, X32, F21, F32, F31, F321, B, XNEW, FNEW, DENOM, ROO 50
& FSAVE, CSQRT, RADICL, RT, DIF, CSTEP, FSLAST ROO 60
REAL*8 EP1, EP2, ONE, HUNDRD, TWO, FOUR, HALF, STEP, ROO 70
& ZERO, EP1DEF, EP2DEF ROO 80
LOGICAL REALRT ROO 90
DATA IZERO, IONE, ITWO, ITHREE, ZERO, HALF, ONE, TWO, ROO 100
& FOUR, HUNDRD, ITSDEF, EP1DEF, EP2DEF ROO 110
& /0,1,2,3,0.0d0,0.5d0,1.0d0,2.0d0,4.0d0,100.0d0,100, ROO 120
& 0.5D-6,1.0D-7/ ROO 130
C
C Initialization
C Check for errors in the input and set default values if necessary
C
EP1 = DMAX1(EP1,EP1DEF)
EP2 = DMAX1(EP2,EP2DEF)
MAXITS = MIN0(MAXITS,ITSDEF)
IFAIL = IZERO
NFOUND = IZERO
IF (KNOWN.LT.IONE) GO TO 30
DO 10 I=1,KNOWN
II = I
CALL CALCF(RTS(I), FNV(I))
C no record is kept of the number of function evaluations
C used here to ckeck the list of known roots
IF (ABS(FNV(II)).GE.EP2) GO TO 20
10 CONTINUE
20 IFAIL =IONE
GUESS = GUESS + KNOWN - II +IONE
NMORE = NMORE + KNOWN - II +IONE
KNOWN = II - IONE
30 CONTINUE
LOOP1 = KNOWN +IONE
LOOP2 = KNOWN + NMORE
IF (LOOP1.GT.LOOP2 .OR. LOOP1.LT.IONE) GO TO 180
IF (GUESS-NMORE) 40, 70, 60
40 ILO = GUESS + IONE
DO 50 I=ILO,LOOP2
RTS(I) = ZERO
50 CONTINUE
GO TO 70
60 CONTINUE
GUESS = NMORE
70 CONTINUE
STEP = HALF
C
C try to find NMORE roots in this major loop
DO 160 NEW=LOOP1,LOOP2
KOUNT = ITHREE
NEWM1 = NEW - IONE
RT = RTS(NEW)
X1 = RT - STEP
X2 = RT + STEP
X3 = RT
C use first estimates
CALL CALCF(X1, F1)
CALL CALCF(X2, F2)
CALL CALCF(X3, F3)
FSLAST = F3
IF (NEW.GT.IONE)
& CALL TEST(X1, F1, FSAVE, RTS, NEWM1, EP2, KOUNT)
IF (NEW.GT.IONE)
& CALL TEST(X2, F2, FSAVE, RTS, NEWM1, EP2, KOUNT)
IF (NEW.GT.IONE)
& CALL TEST(X3, F3, FSLAST, RTS, NEWM1, EP2, KOUNT)
F21 = (F2-F1)/(X2-X1)
C find the roots of the quadratic
80 X32 = X3 - X2
F32 = (F3-F2)/X32
F321 = (F32-F21)/(X3-X1)
B = F32 + X32*F321
RADICL = B**ITWO - FOUR*F321*F3
IF (REALRT .AND. REALPART(RADICL) .LT. ZERO) RADICL = ZERO
RADICL = CDSQRT(RADICL)
IF (
& (REALPART(B)*REALPART(RADICL)+IMAGPART(B)*IMAGPART(RADICL)
& ) .LT. ZERO) RADICL = -RADICL
DENOM = B + RADICL
IF (ABS(DENOM).NE.ZERO) GO TO 100
IF (ABS(F3).GE.EP2) GO TO 90
XNEW = X3
GO TO 120
90 XNEW = X3 + X32
GO TO 120
100 CSTEP = TWO*F3/DENOM
IF (.NOT. REALRT .OR. ABS(F3) .EQ. ZERO .OR.
& ABS(F32) .EQ. ZERO) GO TO 110
CSTEP = F32/ABS(F32)*F3/ABS(F3)*ABS(CSTEP)
110 XNEW = X3 - CSTEP
120 CALL CALCF(XNEW, FNEW)
FSAVE = FNEW
IF (NEW.LE.IONE) GO TO 130
CALL TEST(XNEW, FNEW, FSAVE, RTS, NEWM1, EP2,KOUNT)
130 KOUNT = KOUNT +IONE
C test iterations, convergence and divergence
IF (KOUNT.GT.MAXITS) GO TO 170
DIF = XNEW - X3
IF (ABS(DIF).LT.EP1*ABS(XNEW)) GO TO 150
IF (ABS(FSAVE).LT.EP2) GO TO 150
IF (REALRT .OR. ABS(FSAVE) .LT. HUNDRD*ABS(FSLAST))
& GO TO 140
C divergence "fix"
CSTEP = CSTEP*HALF
XNEW = XNEW + CSTEP
GO TO 120
140 X1 = X2
X2 = X3
X3 = XNEW
F1 = F2
F2 = F3
F3 = FNEW
FSLAST = FSAVE
F21 = F32
GO TO 80
150 CONTINUE
C convergence to one more root
C (the number of function evaluations used in determining the current root
C is available at this stage; output the variable KOUNT if desired)
write(*,*) ' number function evaluations = ', KOUNT
RTS(NEW) = XNEW
FNV(NEW) = FSAVE
NFOUND = NEW
160 CONTINUE
GO TO 190
170 CONTINUE
C MAXITS reached
RTS(NEW) = XNEW
FNV(NEW) = FSAVE
IFAIL = ITHREE
GO TO 190
180 CONTINUE
IFAIL = ITWO
190 CONTINUE
RETURN
END SUBROUTINE ROOTS
cccccCcccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxcccccccccxccCCCCCCCC
SUBROUTINE TEST(X, F, FSAVE, RTS, K, EPS, KOUNT) TES 10
C
C This subroutine serves two purposes:
C 1. Deflation of the function is performed,
C i.e. if X is the current approximation to a root
C and RTS is a vector of roots already known, the
C deflated function value is
C F=(...((F.(X-RTS(1)))/(X-RTS(2)))/...)
C 2. If a current approximation to a root is "too close"
C to a root already known, X is perturbed away from
C the known root by 0.01. This device avoids division
C by (essentially) zero in the deflation process, but it
C does not prevent convergence to multiple zeros.
C
COMPLEX*16 X, F, RTS(K), D, FSAVE TES 20
REAL*8 EPS, PERTB TES 30
DATA IONE, PERTB /1, 0.01D0/ TES 40
10 CONTINUE TES 50
DO 20 I=1,K TES 60
D = X - RTS(I) TES 70
IF (ABS(D) .LE. EPS) GO TO 30 TES 80
F = F/D TES 90
20 CONTINUE TES 100
GO TO 40 TES 110
30 CONTINUE TES 120
X = X + PERTB TES 130
CALL CALCF(X, F) TES 140
FSAVE = F TES 150
KOUNT = KOUNT + IONE TES 160
GO TO 10 TES 170
40 RETURN TES 180
END SUBROUTINE TEST TES 190