LAPACK 3.3.0
|
00001 SUBROUTINE SLAED6( KNITER, ORGATI, RHO, D, Z, FINIT, TAU, INFO ) 00002 * 00003 * -- LAPACK routine (version 3.2) -- 00004 * -- LAPACK is a software package provided by Univ. of Tennessee, -- 00005 * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- 00006 * February 2007 00007 * 00008 * .. Scalar Arguments .. 00009 LOGICAL ORGATI 00010 INTEGER INFO, KNITER 00011 REAL FINIT, RHO, TAU 00012 * .. 00013 * .. Array Arguments .. 00014 REAL D( 3 ), Z( 3 ) 00015 * .. 00016 * 00017 * Purpose 00018 * ======= 00019 * 00020 * SLAED6 computes the positive or negative root (closest to the origin) 00021 * of 00022 * z(1) z(2) z(3) 00023 * f(x) = rho + --------- + ---------- + --------- 00024 * d(1)-x d(2)-x d(3)-x 00025 * 00026 * It is assumed that 00027 * 00028 * if ORGATI = .true. the root is between d(2) and d(3); 00029 * otherwise it is between d(1) and d(2) 00030 * 00031 * This routine will be called by SLAED4 when necessary. In most cases, 00032 * the root sought is the smallest in magnitude, though it might not be 00033 * in some extremely rare situations. 00034 * 00035 * Arguments 00036 * ========= 00037 * 00038 * KNITER (input) INTEGER 00039 * Refer to SLAED4 for its significance. 00040 * 00041 * ORGATI (input) LOGICAL 00042 * If ORGATI is true, the needed root is between d(2) and 00043 * d(3); otherwise it is between d(1) and d(2). See 00044 * SLAED4 for further details. 00045 * 00046 * RHO (input) REAL 00047 * Refer to the equation f(x) above. 00048 * 00049 * D (input) REAL array, dimension (3) 00050 * D satisfies d(1) < d(2) < d(3). 00051 * 00052 * Z (input) REAL array, dimension (3) 00053 * Each of the elements in z must be positive. 00054 * 00055 * FINIT (input) REAL 00056 * The value of f at 0. It is more accurate than the one 00057 * evaluated inside this routine (if someone wants to do 00058 * so). 00059 * 00060 * TAU (output) REAL 00061 * The root of the equation f(x). 00062 * 00063 * INFO (output) INTEGER 00064 * = 0: successful exit 00065 * > 0: if INFO = 1, failure to converge 00066 * 00067 * Further Details 00068 * =============== 00069 * 00070 * 30/06/99: Based on contributions by 00071 * Ren-Cang Li, Computer Science Division, University of California 00072 * at Berkeley, USA 00073 * 00074 * 10/02/03: This version has a few statements commented out for thread safety 00075 * (machine parameters are computed on each entry). SJH. 00076 * 00077 * 05/10/06: Modified from a new version of Ren-Cang Li, use 00078 * Gragg-Thornton-Warner cubic convergent scheme for better stability. 00079 * 00080 * ===================================================================== 00081 * 00082 * .. Parameters .. 00083 INTEGER MAXIT 00084 PARAMETER ( MAXIT = 40 ) 00085 REAL ZERO, ONE, TWO, THREE, FOUR, EIGHT 00086 PARAMETER ( ZERO = 0.0E0, ONE = 1.0E0, TWO = 2.0E0, 00087 $ THREE = 3.0E0, FOUR = 4.0E0, EIGHT = 8.0E0 ) 00088 * .. 00089 * .. External Functions .. 00090 REAL SLAMCH 00091 EXTERNAL SLAMCH 00092 * .. 00093 * .. Local Arrays .. 00094 REAL DSCALE( 3 ), ZSCALE( 3 ) 00095 * .. 00096 * .. Local Scalars .. 00097 LOGICAL SCALE 00098 INTEGER I, ITER, NITER 00099 REAL A, B, BASE, C, DDF, DF, EPS, ERRETM, ETA, F, 00100 $ FC, SCLFAC, SCLINV, SMALL1, SMALL2, SMINV1, 00101 $ SMINV2, TEMP, TEMP1, TEMP2, TEMP3, TEMP4, 00102 $ LBD, UBD 00103 * .. 00104 * .. Intrinsic Functions .. 00105 INTRINSIC ABS, INT, LOG, MAX, MIN, SQRT 00106 * .. 00107 * .. Executable Statements .. 00108 * 00109 INFO = 0 00110 * 00111 IF( ORGATI ) THEN 00112 LBD = D(2) 00113 UBD = D(3) 00114 ELSE 00115 LBD = D(1) 00116 UBD = D(2) 00117 END IF 00118 IF( FINIT .LT. ZERO )THEN 00119 LBD = ZERO 00120 ELSE 00121 UBD = ZERO 00122 END IF 00123 * 00124 NITER = 1 00125 TAU = ZERO 00126 IF( KNITER.EQ.2 ) THEN 00127 IF( ORGATI ) THEN 00128 TEMP = ( D( 3 )-D( 2 ) ) / TWO 00129 C = RHO + Z( 1 ) / ( ( D( 1 )-D( 2 ) )-TEMP ) 00130 A = C*( D( 2 )+D( 3 ) ) + Z( 2 ) + Z( 3 ) 00131 B = C*D( 2 )*D( 3 ) + Z( 2 )*D( 3 ) + Z( 3 )*D( 2 ) 00132 ELSE 00133 TEMP = ( D( 1 )-D( 2 ) ) / TWO 00134 C = RHO + Z( 3 ) / ( ( D( 3 )-D( 2 ) )-TEMP ) 00135 A = C*( D( 1 )+D( 2 ) ) + Z( 1 ) + Z( 2 ) 00136 B = C*D( 1 )*D( 2 ) + Z( 1 )*D( 2 ) + Z( 2 )*D( 1 ) 00137 END IF 00138 TEMP = MAX( ABS( A ), ABS( B ), ABS( C ) ) 00139 A = A / TEMP 00140 B = B / TEMP 00141 C = C / TEMP 00142 IF( C.EQ.ZERO ) THEN 00143 TAU = B / A 00144 ELSE IF( A.LE.ZERO ) THEN 00145 TAU = ( A-SQRT( ABS( A*A-FOUR*B*C ) ) ) / ( TWO*C ) 00146 ELSE 00147 TAU = TWO*B / ( A+SQRT( ABS( A*A-FOUR*B*C ) ) ) 00148 END IF 00149 IF( TAU .LT. LBD .OR. TAU .GT. UBD ) 00150 $ TAU = ( LBD+UBD )/TWO 00151 IF( D(1).EQ.TAU .OR. D(2).EQ.TAU .OR. D(3).EQ.TAU ) THEN 00152 TAU = ZERO 00153 ELSE 00154 TEMP = FINIT + TAU*Z(1)/( D(1)*( D( 1 )-TAU ) ) + 00155 $ TAU*Z(2)/( D(2)*( D( 2 )-TAU ) ) + 00156 $ TAU*Z(3)/( D(3)*( D( 3 )-TAU ) ) 00157 IF( TEMP .LE. ZERO )THEN 00158 LBD = TAU 00159 ELSE 00160 UBD = TAU 00161 END IF 00162 IF( ABS( FINIT ).LE.ABS( TEMP ) ) 00163 $ TAU = ZERO 00164 END IF 00165 END IF 00166 * 00167 * get machine parameters for possible scaling to avoid overflow 00168 * 00169 * modified by Sven: parameters SMALL1, SMINV1, SMALL2, 00170 * SMINV2, EPS are not SAVEd anymore between one call to the 00171 * others but recomputed at each call 00172 * 00173 EPS = SLAMCH( 'Epsilon' ) 00174 BASE = SLAMCH( 'Base' ) 00175 SMALL1 = BASE**( INT( LOG( SLAMCH( 'SafMin' ) ) / LOG( BASE ) / 00176 $ THREE ) ) 00177 SMINV1 = ONE / SMALL1 00178 SMALL2 = SMALL1*SMALL1 00179 SMINV2 = SMINV1*SMINV1 00180 * 00181 * Determine if scaling of inputs necessary to avoid overflow 00182 * when computing 1/TEMP**3 00183 * 00184 IF( ORGATI ) THEN 00185 TEMP = MIN( ABS( D( 2 )-TAU ), ABS( D( 3 )-TAU ) ) 00186 ELSE 00187 TEMP = MIN( ABS( D( 1 )-TAU ), ABS( D( 2 )-TAU ) ) 00188 END IF 00189 SCALE = .FALSE. 00190 IF( TEMP.LE.SMALL1 ) THEN 00191 SCALE = .TRUE. 00192 IF( TEMP.LE.SMALL2 ) THEN 00193 * 00194 * Scale up by power of radix nearest 1/SAFMIN**(2/3) 00195 * 00196 SCLFAC = SMINV2 00197 SCLINV = SMALL2 00198 ELSE 00199 * 00200 * Scale up by power of radix nearest 1/SAFMIN**(1/3) 00201 * 00202 SCLFAC = SMINV1 00203 SCLINV = SMALL1 00204 END IF 00205 * 00206 * Scaling up safe because D, Z, TAU scaled elsewhere to be O(1) 00207 * 00208 DO 10 I = 1, 3 00209 DSCALE( I ) = D( I )*SCLFAC 00210 ZSCALE( I ) = Z( I )*SCLFAC 00211 10 CONTINUE 00212 TAU = TAU*SCLFAC 00213 LBD = LBD*SCLFAC 00214 UBD = UBD*SCLFAC 00215 ELSE 00216 * 00217 * Copy D and Z to DSCALE and ZSCALE 00218 * 00219 DO 20 I = 1, 3 00220 DSCALE( I ) = D( I ) 00221 ZSCALE( I ) = Z( I ) 00222 20 CONTINUE 00223 END IF 00224 * 00225 FC = ZERO 00226 DF = ZERO 00227 DDF = ZERO 00228 DO 30 I = 1, 3 00229 TEMP = ONE / ( DSCALE( I )-TAU ) 00230 TEMP1 = ZSCALE( I )*TEMP 00231 TEMP2 = TEMP1*TEMP 00232 TEMP3 = TEMP2*TEMP 00233 FC = FC + TEMP1 / DSCALE( I ) 00234 DF = DF + TEMP2 00235 DDF = DDF + TEMP3 00236 30 CONTINUE 00237 F = FINIT + TAU*FC 00238 * 00239 IF( ABS( F ).LE.ZERO ) 00240 $ GO TO 60 00241 IF( F .LE. ZERO )THEN 00242 LBD = TAU 00243 ELSE 00244 UBD = TAU 00245 END IF 00246 * 00247 * Iteration begins -- Use Gragg-Thornton-Warner cubic convergent 00248 * scheme 00249 * 00250 * It is not hard to see that 00251 * 00252 * 1) Iterations will go up monotonically 00253 * if FINIT < 0; 00254 * 00255 * 2) Iterations will go down monotonically 00256 * if FINIT > 0. 00257 * 00258 ITER = NITER + 1 00259 * 00260 DO 50 NITER = ITER, MAXIT 00261 * 00262 IF( ORGATI ) THEN 00263 TEMP1 = DSCALE( 2 ) - TAU 00264 TEMP2 = DSCALE( 3 ) - TAU 00265 ELSE 00266 TEMP1 = DSCALE( 1 ) - TAU 00267 TEMP2 = DSCALE( 2 ) - TAU 00268 END IF 00269 A = ( TEMP1+TEMP2 )*F - TEMP1*TEMP2*DF 00270 B = TEMP1*TEMP2*F 00271 C = F - ( TEMP1+TEMP2 )*DF + TEMP1*TEMP2*DDF 00272 TEMP = MAX( ABS( A ), ABS( B ), ABS( C ) ) 00273 A = A / TEMP 00274 B = B / TEMP 00275 C = C / TEMP 00276 IF( C.EQ.ZERO ) THEN 00277 ETA = B / A 00278 ELSE IF( A.LE.ZERO ) THEN 00279 ETA = ( A-SQRT( ABS( A*A-FOUR*B*C ) ) ) / ( TWO*C ) 00280 ELSE 00281 ETA = TWO*B / ( A+SQRT( ABS( A*A-FOUR*B*C ) ) ) 00282 END IF 00283 IF( F*ETA.GE.ZERO ) THEN 00284 ETA = -F / DF 00285 END IF 00286 * 00287 TAU = TAU + ETA 00288 IF( TAU .LT. LBD .OR. TAU .GT. UBD ) 00289 $ TAU = ( LBD + UBD )/TWO 00290 * 00291 FC = ZERO 00292 ERRETM = ZERO 00293 DF = ZERO 00294 DDF = ZERO 00295 DO 40 I = 1, 3 00296 TEMP = ONE / ( DSCALE( I )-TAU ) 00297 TEMP1 = ZSCALE( I )*TEMP 00298 TEMP2 = TEMP1*TEMP 00299 TEMP3 = TEMP2*TEMP 00300 TEMP4 = TEMP1 / DSCALE( I ) 00301 FC = FC + TEMP4 00302 ERRETM = ERRETM + ABS( TEMP4 ) 00303 DF = DF + TEMP2 00304 DDF = DDF + TEMP3 00305 40 CONTINUE 00306 F = FINIT + TAU*FC 00307 ERRETM = EIGHT*( ABS( FINIT )+ABS( TAU )*ERRETM ) + 00308 $ ABS( TAU )*DF 00309 IF( ABS( F ).LE.EPS*ERRETM ) 00310 $ GO TO 60 00311 IF( F .LE. ZERO )THEN 00312 LBD = TAU 00313 ELSE 00314 UBD = TAU 00315 END IF 00316 50 CONTINUE 00317 INFO = 1 00318 60 CONTINUE 00319 * 00320 * Undo scaling 00321 * 00322 IF( SCALE ) 00323 $ TAU = TAU*SCLINV 00324 RETURN 00325 * 00326 * End of SLAED6 00327 * 00328 END