C ***QUARTIC************************************************25.03.98 C Solution of a quartic equation: ! dd(0)+dd(1)*z+dd(2)*z**2+dd(3)*z**3+dd(4)*z**4=0 C ref.: J. E. Hacke, Amer. Math. Monthly, Vol. 48, 327-328, (1941) C NO WARRANTY, ALWAYS TEST THIS SUBROUTINE AFTER DOWNLOADING C ****************************************************************** C dd(0:4) (i) vector containing the polynomial coefficients C sol(1:4) (o) results, real part C soli(1:4) (o) results, imaginary part C Nsol (o) number of real solutions C ================================================================== subroutine quartic(dd,sol,soli,Nsol) implicit double precision (a-h,o-z) dimension dd(0:4),sol(4),soli(4) dimension AA(0:3),z(3) C Nsol = 0 a = dd(4) b = dd(3) c = dd(2) d = dd(1) e = dd(0) C if (dd(4).eq.0.0d+0) then write(*,*)'ERROR: NOT A QUARTIC EQUATION' return endif C p=-(3.0d0/8.0d0)*(b/a)*(b/a)+c/a q =(b/a)*(b/a)*(b/a)/8.0d0-(b/a)*(c/a)/2.0d0+d/a r =(-3.0d0/256.0d0)*(b/a)*(b/a)*(b/a)*(b/a)+ & (b/a)*(b/a)*(c/a)/16.0d0-(b/a)*(d/a)/4.0d0+ & e/a ! ! solve cubic resolvent AA(3) = 8.0d0 AA(2) = -4.0d0*p AA(1) = -8.0d0*r AA(0) = 4.0d0*p*r - q*q call cubic(AA,z,ncube) C zsol = -1.0d99 do 5 i=1,ncube zsol = dmax1(zsol,z(i)) 5 continue z(1) = zsol xK2 = 2.0d0 * z(1) - p xK = dsqrt(xK2) C----------------------------------------------- if (xK.eq.0.0d0) then xL2 = z(1)*z(1) - r if (xL2.lt.0.0d0) then write(*,*)'Sorry, no solution' return endif xL = dsqrt(xL2) else xL = q/(2.0d0 * xK) endif C----------------------------------------------- sqp = xK2 - 4.0d0*(z(1) + xL) sqm = xK2 - 4.0d0*(z(1) - xL) C do 10 i=1,4 soli(i) = 0.0d0 10 continue if (sqp.ge.0.0d0 .and. sqm.ge.0.0d0) then sol(1) = 0.5d+0*( xK + dsqrt(sqp)) sol(2) = 0.5d+0*( xK - dsqrt(sqp)) sol(3) = 0.5d+0*(-xK + dsqrt(sqm)) sol(4) = 0.5d+0*(-xK - dsqrt(sqm)) Nsol = 4 else if (sqp.ge.0.d+0 .and. sqm.lt.0.d+0) then sol(1) = 0.5d+0*(xK + dsqrt(sqp)) sol(2) = 0.5d+0*(xK - dsqrt(sqp)) sol(3) = -0.5d+0*xK sol(4) = -0.5d+0*xK soli(3) = dsqrt(-0.25d+0 * sqm) soli(4) = -dsqrt(-0.25d+0 * sqm) Nsol = 2 else if (sqp.lt.0.d+0 .and. sqm.ge.0.d+0) then sol(1) = 0.5d+0*(-xK + dsqrt(sqm)) sol(2) = 0.5d+0*(-xK - dsqrt(sqm)) sol(3) = 0.5d+0*xK sol(4) = 0.5d+0*xK soli(3) = dsqrt(-0.25d+0 * sqp) soli(4) = -dsqrt(-0.25d+0 * sqp) Nsol = 2 else if (sqp.lt.0.d+0 .and. sqm.lt.0.d+0) then sol(1) = -0.5d+0*xK sol(2) = -0.5d+0*xK soli(1) = dsqrt(-0.25d+0 * sqm) soli(2) = -dsqrt(-0.25d+0 * sqm) sol(3) = 0.5d+0*xK sol(4) = 0.5d+0*xK soli(3) = dsqrt(-0.25d+0 * sqp) soli(4) = -dsqrt(-0.25d+0 * sqp) Nsol = 0 endif do 20 i=1,4 sol(i) = sol(i) - b/(4.d+0*a) 20 continue C return END C ***CUBIC************************************************08.11.1986 C Solution of a cubic equation C Equations of lesser degree are solved by the appropriate formulas. C The solutions are arranged in ascending order. C NO WARRANTY, ALWAYS TEST THIS SUBROUTINE AFTER DOWNLOADING C ****************************************************************** C A(0:3) (i) vector containing the polynomial coefficients C X(1:L) (o) results C L (o) number of valid solutions (beginning with X(1)) C ================================================================== SUBROUTINE CUBIC(A,X,L) IMPLICIT DOUBLE PRECISION(A-H,O-Z) DIMENSION A(0:3),X(3),U(3) PARAMETER(PI=3.1415926535897932D+0,THIRD=1.D+0/3.D+0) INTRINSIC DMIN1,DMAX1,DACOS C C define cubic root as statement function CBRT(Z)=DSIGN(DABS(Z)**THIRD,Z) C C ==== determine the degree of the polynomial ==== C IF (A(3).NE.0.D+0) THEN C C cubic problem W=A(2)/A(3)*THIRD P=(A(1)/A(3)*THIRD-W**2)**3 Q=-.5D+0*(2.D+0*W**3-(A(1)*W-A(0))/A(3)) DIS=Q**2+P IF (DIS.LT.0.D+0) THEN C three real solutions! C Confine the argument of ACOS to the interval [-1;1]! PHI=DACOS(DMIN1(1.D+0,DMAX1(-1.D+0,Q/DSQRT(-P)))) P=2.D+0*(-P)**(5.D-1*THIRD) DO 100 I=1,3 U(I)=P*DCOS((PHI+DBLE(2*I)*PI)*THIRD)-W 100 continue X(1)=DMIN1(U(1),U(2),U(3)) X(2)=DMAX1(DMIN1(U(1),U(2)),DMIN1(U(1),U(3)),DMIN1(U(2),U(3))) X(3)=DMAX1(U(1),U(2),U(3)) L=3 ELSE C only one real solution! DIS=DSQRT(DIS) X(1)=CBRT(Q+DIS)+CBRT(Q-DIS)-W L=1 END IF C ELSE IF (A(2).NE.0.D+0) THEN C C quadratic problem P=5.D-1*A(1)/A(2) DIS=P**2-A(0)/A(2) IF (DIS.GE.0.D+0) THEN C two real solutions! X(1)=-P-DSQRT(DIS) X(2)=-P+DSQRT(DIS) L=2 ELSE C no real solution! L=0 END IF C ELSE IF (A(1).NE.0.D+0) THEN C C linear equation X(1)=-A(0)/A(1) L=1 C ELSE C no equation L=0 END IF C C ==== perform one step of a newton iteration in order to minimize C round-off errors ==== DO 110 I=1,L X(I)=X(I)-(A(0)+X(I)*(A(1)+X(I)*(A(2)+X(I)*A(3)))) * /(A(1)+X(I)*(2.D+0*A(2)+X(I)*3.D+0*A(3))) 110 CONTINUE RETURN END