subroutine aptqrtv (noptq, aa, bb, cc, qq, np, tol, & nroots, root1, root2, itrun, nerr) ccbeg. cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc c c SUBROUTINE APTQRTV c c call aptqrtv (noptq, aa, bb, cc, qq, np, tol, c & nroots, root1, root2, itrun, nerr) c c Version: aptqrtv Updated 1994 December 15 12:40. c aptqrtv Originated 1989 November 2 14:10. c c Author: Arthur L. Edwards, LLNL, L-298, Telephone (925) 422-4123. c c c Purpose: To find the real and complex roots of the quadratic equation: c c aa * x**2 + bb * x + cc = 0. c c for np sets of coefficients aa, bb, cc. c The solution is vectorized over the sets of coefficients, c which are calculated in sections of 64 (or less, for the c final section). c c The method minimizes truncation error, and indicates when c truncation error may still be significant, based on tol. c Option noptq = 1 allows the user to specify the value of c qq = bb**2 - 4.0 * aa *cc, instead of using the value c calculated here. This allows any cancellation of terms. c c For q = sqrt (qq), the roots are: c (-bb + q) / (2 * aa) = 2 * cc / (-bb - q) c (-bb - q) / (2 * aa) = 2 * cc / (-bb + q) c The most accurate form must be used, to minimize error. c c Note: aptqrts is a scalar version of aptqrtv. c c History: 1990 January 19 15:00. Fixed bug for a = 0.0 or b = 0.0. c 1990 March 21 14:00. Changed to allow truncation of small c positive qq to zero. c 1994 April 15 16:20. Changed to put two roots in order of c increasing value. c c Input: noptq, aa, bb, cc, qq, np, tol. c c Output: qq, nroots, root1, root2, itrun. c c Glossary: c c aa Input Coefficients of x**2 in a quadratic equation. Size np. c c bb Input Coefficients of x in a quadratic equation. Size np. c c cc Input Coefficients of 1 in a quadratic equation. Size np. c c itrun Output Truncation error indicator. 0 if insignificant. c 1 if the magnitude of qq is less than the estimated c truncation error, based on tol. This indicates c that the roots are near a minimum or maximum, or c that the quadratic is almost the square of a linear c function. The value of qq is truncated to zero. c 2 if the input value of qq (noptq = 1) differs from c the calculated value by more than the estimated c truncation error, based on tol. c Size np. c c nerr Output Indicates an input error, if not 0. c 1 if np is not positive. c c noptq Input Option for getting value of qq = bb**2 - 4.0 * aa * cc: c 0 to not use input qq, but calculate from aa, bb, cc. c Any value other than 1 has this result. c 1 to use the (more accurate) input value of qq. c A nonzero value of tol must be used with this c option, for comparision of the input with the c calculated value. c c nroots Output Number of real roots. Size np. c -1 if aa = 0 and bb = 0. c Equation is null (cc = 0) or bad (cc is not 0). c 0 if qq < 0. The two complex roots are c root1 + i * root2 and root1 - i * root2. c 1 if equation is linear: c aa is 0 and bb is not 0, or if qq = 0. c 2 if qq > 0. c c np Input Number of sets of input data aa, bb, cc, noptq, qq. c c qq Input If noptq = 1, qq = bb**2 - 4.0 * aa * cc, but c calculated more accurately, due to cancellation of c terms resulting from the composite nature of aa, bb, c and/or cc. Size np. c c qq Output If noptq is not 1, qq = bb**2 - 4.0 * aa * cc, c calculated locally. Size np. c c root1 Output If nroots = 1, the only real root. c If nroots = 2, the minimum real root. c If nroots = 0, the two complex roots are c root1 + i * root2 and root1 - i * root2. c c root2 Output If nroots = 2, the maximum real root. c If nroots = 0, the two complex roots are c root1 + i * root2 and root1 - i * root2. c c tol Input Numerical tolerance limit. c Must not be zero if noptq = 1. c On Cray computers, recommend 1.e-5 to 1.e-11. c cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc ccend. c.... Dimensioned arguments. c---- Coefficient of term x**2. dimension aa (1) c---- Coefficient of term x. dimension bb (1) c---- Coefficient of term 1. dimension cc (1) c---- Truncation error indicator. dimension itrun (1) c---- Number of real roots. dimension nroots (1) c---- Factor bb**2 - 4.0 * aa * cc. dimension qq (1) c---- First real root (-1.e+99 if none). dimension root1 (1) c---- Second real root (-1.e+99 if none). dimension root2 (1) c.... Local variables. c---- A very big number. common /laptqrtv/ big c---- A very small number. common /laptqrtv/ fuz c---- Index of coefficient set. common /laptqrtv/ n c---- First index of subset of data. common /laptqrtv/ n1 c---- Last index of subset of data. common /laptqrtv/ n2 c---- Index in external array. common /laptqrtv/ nn c---- Size of current subset of data. common /laptqrtv/ ns c---- Sqrt (qq), with the sign of bb. common /laptqrtv/ q c---- Truncation error in qqx. common /laptqrtv/ qqerr c---- Locally calculated value of qq. common /laptqrtv/ qqx c---- One of two roots. common /laptqrtv/ rootx cbugc***DEBUG begins. cbug 9901 format (/ 'aptqrtv finding roots. np=',i3,' noptq=',i2, cbug & ' tol=',1pe13.5) cbug 9902 format ( cbug & i3,' aa,bb,cc= ',1p3e22.14 / cbug & ' qq(input)=',1pe22.14 / cbug & ' qqx(calc)=',1pe22.14 / cbug & ' qqerr= ',1pe22.14) cbug write ( 3, 9901) np, noptq, tol cbug do 101 n = 1, np cbug if (noptq .ne. 1) qq(n) = 0.0 cbug qqx = bb(n)**2 - 4.0 * aa(n) * cc(n) cbug qqerr = 2.0 * tol * cbug & (bb(n)**2 + 4.0 * abs (aa(n) * cc(n))) cbug write ( 3, 9902) n, aa(n), bb(n), cc(n), qq(n), qqx, qqerr cbug 101 continue cbugc***DEBUG ends. c.... Initialize. c---- A very big number. big = 1.e+99 c---- A very small number. fuz = 1.e-99 nerr = 0 c.... Test for input errors. if (np .le. 0) then nerr = 1 go to 210 endif c.... Initialize. n1 = 1 n2 = min (np, 64) 110 ns = n2 - n1 + 1 c.... Find qq = bb**2 - 4.0 * aa * cc, and q = sqrt (qq). c---- Loop over coefficient sets. do 120 nn = n1, n2 qqx = bb(nn)**2 - 4.0 * aa(nn) * cc(nn) qqerr = 2.0 * tol * & (bb(nn)**2 + 4.0 * abs (aa(nn) * cc(nn))) if (abs (qqx) .lt. qqerr) then qqx = 0.0 endif if (abs (qqx) .lt. qqerr) then itrun(nn) = 1 else itrun(nn) = 0 endif if (noptq .ne. 1) then qq(nn) = qqx endif if (abs (qq(nn) - qqx) .gt. qqerr) then itrun(nn) = 2 endif c---- End of loop over coefficient sets. 120 continue c.... Find any roots. c---- Loop over coefficient sets. do 130 nn = n1, n2 q = sign (sqrt (amax1 (0.0, qq(nn))), bb(nn)) c.... No first root if qq .lt. 0, or if aa = bb = 0. root1(nn) = -2.0 * cc(nn) / (q + bb(nn) + fuz) if ((qq(nn) .lt. 0.0) .or. & ((aa(nn) .eq. 0.0) .and. & (bb(nn) .eq. 0.0)) ) then root1(nn) = -big endif if (root1(nn) .ne. -big) then nroots(nn) = 1 else nroots(nn) = 0 endif c.... No second real root if qq = 0, qq < 0, or if aa = 0. root2(nn) = -0.5 * (q + bb(nn)) / (aa(nn) + fuz) if ((qq(nn) .le. 0.0) .or. & (aa(nn) .eq. 0.0) ) then root2(nn) = -big endif if (root2(nn) .ne. -big) then nroots(nn) = nroots(nn) + 1 endif c.... Flag bad coefficients when aa = bb = 0. if ((aa(nn) .eq. 0.0) .and. & (bb(nn) .eq. 0.0) ) then nroots(nn) = -1 endif if ((nroots(nn) .eq. 2) .and. & (root2(nn) .lt. root1(nn))) then rootx = root1(nn) root1(nn) = root2(nn) root2(nn) = rootx endif c.... Return real and imaginary parts of two complex roots if qq < 0. if (qq(nn) .lt. 0.0) then nroots(nn) = 0 root1(nn) = -0.5 * bb(nn) / (aa(nn) + fuz) root2(nn) = 0.5 * sqrt (-qq(nn)) / (abs (aa(nn)) + fuz) endif c---- End of loop over coefficient sets. 130 continue c.... See if all sets are done. c---- Do another data set. if (n2 .lt. np) then n1 = n2 + 1 n2 = min (np, n1 + 63) go to 110 endif cbugc***DEBUG begins. cbug 9903 format (/ 'aptqrtv results:' / cbug & (i3,' nroots=',i2,' itrun=',i2 / cbug & ' root1,root2=',1p2e22.14)) cbug write ( 3, 9903) (n, nroots(n), itrun(n), cbug & root1(n), root2(n), n = 1, np) cbugc***DEBUG ends. 210 return c.... End of subroutine aptqrtv. (+1 line.) end UCRL-WEB-209832