00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "Wm4FoundationPCH.h"
00018 #include "Wm4PolynomialRoots.h"
00019
00020 namespace Wm4
00021 {
00022
00023 template <class Real>
00024 PolynomialRoots<Real>::PolynomialRoots (Real fEpsilon)
00025 {
00026 assert(fEpsilon >= (Real)0.0);
00027 m_fEpsilon = fEpsilon;
00028 m_iMaxIterations = 128;
00029 m_iCount = 0;
00030 m_iMaxRoot = 4;
00031 m_afRoot = WM4_NEW Real[m_iMaxRoot];
00032 }
00033
00034 template <class Real>
00035 PolynomialRoots<Real>::~PolynomialRoots ()
00036 {
00037 WM4_DELETE[] m_afRoot;
00038 }
00039
00040 template <class Real>
00041 int PolynomialRoots<Real>::GetCount () const
00042 {
00043 return m_iCount;
00044 }
00045
00046 template <class Real>
00047 const Real* PolynomialRoots<Real>::GetRoots () const
00048 {
00049 return m_afRoot;
00050 }
00051
00052 template <class Real>
00053 Real PolynomialRoots<Real>::GetRoot (int i) const
00054 {
00055 assert(0 <= i && i < m_iCount);
00056 if (0 <= i && i < m_iCount)
00057 {
00058 return m_afRoot[i];
00059 }
00060
00061 return Math<Real>::MAX_REAL;
00062 }
00063
00064 template <class Real>
00065 Real& PolynomialRoots<Real>::Epsilon ()
00066 {
00067 return m_fEpsilon;
00068 }
00069
00070 template <class Real>
00071 Real PolynomialRoots<Real>::Epsilon () const
00072 {
00073 return m_fEpsilon;
00074 }
00075
00076 template <class Real>
00077 int& PolynomialRoots<Real>::MaxIterations ()
00078 {
00079 return m_iMaxIterations;
00080 }
00081
00082 template <class Real>
00083 int PolynomialRoots<Real>::MaxIterations () const
00084 {
00085 return m_iMaxIterations;
00086 }
00087
00088
00089
00090
00091
00092 template <class Real>
00093 bool PolynomialRoots<Real>::FindA (Real fC0, Real fC1)
00094 {
00095 if (Math<Real>::FAbs(fC1) >= m_fEpsilon)
00096 {
00097 m_afRoot[0] = -fC0/fC1;
00098 m_iCount = 1;
00099 return true;
00100 }
00101
00102 m_iCount = 0;
00103 return false;
00104 }
00105
00106 template <class Real>
00107 Real PolynomialRoots<Real>::GetBound (Real fC0, Real fC1)
00108 {
00109 if (Math<Real>::FAbs(fC1) <= m_fEpsilon)
00110 {
00111
00112 return -(Real)1.0;
00113 }
00114
00115 Real fInvC1 = ((Real)1.0)/fC1;
00116 Real fMax = Math<Real>::FAbs(fC0)*fInvC1;
00117 return (Real)1.0 + fMax;
00118 }
00119
00120
00121
00122
00123
00124 template <class Real>
00125 bool PolynomialRoots<Real>::FindA (Real fC0, Real fC1, Real fC2)
00126 {
00127 if (Math<Real>::FAbs(fC2) <= m_fEpsilon)
00128 {
00129
00130 return FindA(fC0,fC1);
00131 }
00132
00133 Real fDiscr = fC1*fC1 - 4.0f*fC0*fC2;
00134 if (Math<Real>::FAbs(fDiscr) <= m_fEpsilon)
00135 {
00136 fDiscr = (Real)0.0;
00137 }
00138
00139 if (fDiscr < (Real)0.0)
00140 {
00141 m_iCount = 0;
00142 return false;
00143 }
00144
00145 Real fTmp = ((Real)0.5)/fC2;
00146
00147 if (fDiscr > (Real)0.0)
00148 {
00149 fDiscr = Math<Real>::Sqrt(fDiscr);
00150 m_afRoot[0] = fTmp*(-fC1 - fDiscr);
00151 m_afRoot[1] = fTmp*(-fC1 + fDiscr);
00152 m_iCount = 2;
00153 }
00154 else
00155 {
00156 m_afRoot[0] = -fTmp*fC1;
00157 m_iCount = 1;
00158 }
00159
00160 return true;
00161 }
00162
00163 template <class Real>
00164 Real PolynomialRoots<Real>::GetBound (Real fC0, Real fC1, Real fC2)
00165 {
00166 if (Math<Real>::FAbs(fC2) <= m_fEpsilon)
00167 {
00168
00169 return (FindA(fC0,fC1) ? m_afRoot[0] : Math<Real>::MAX_REAL);
00170 }
00171
00172 Real fInvC2 = ((Real)1.0)/fC2;
00173 Real fTmp0 = Math<Real>::FAbs(fC0)*fInvC2;
00174 Real fTmp1 = Math<Real>::FAbs(fC1)*fInvC2;
00175 Real fMax = ( fTmp0 >= fTmp1 ? fTmp0 : fTmp1 );
00176 return (Real)1.0 + fMax;
00177 }
00178
00179
00180
00181
00182
00183 template <class Real>
00184 bool PolynomialRoots<Real>::FindA (Real fC0, Real fC1, Real fC2, Real fC3)
00185 {
00186 if (Math<Real>::FAbs(fC3) <= m_fEpsilon)
00187 {
00188
00189 return FindA(fC0,fC1,fC2);
00190 }
00191
00192
00193 Real fInvC3 = ((Real)1.0)/fC3;
00194 fC0 *= fInvC3;
00195 fC1 *= fInvC3;
00196 fC2 *= fInvC3;
00197
00198
00199 const Real fThird = (Real)1.0/(Real)3.0;
00200 const Real fTwentySeventh = (Real)1.0/(Real)27.0;
00201 Real fOffset = fThird*fC2;
00202 Real fA = fC1 - fC2*fOffset;
00203 Real fB = fC0+fC2*(((Real)2.0)*fC2*fC2-((Real)9.0)*fC1)*fTwentySeventh;
00204 Real fHalfB = ((Real)0.5)*fB;
00205
00206 Real fDiscr = fHalfB*fHalfB + fA*fA*fA*fTwentySeventh;
00207 if (Math<Real>::FAbs(fDiscr) <= m_fEpsilon)
00208 {
00209 fDiscr = (Real)0.0;
00210 }
00211
00212 if (fDiscr > (Real)0.0)
00213 {
00214 fDiscr = Math<Real>::Sqrt(fDiscr);
00215 Real fTemp = -fHalfB + fDiscr;
00216 if (fTemp >= (Real)0.0)
00217 {
00218 m_afRoot[0] = Math<Real>::Pow(fTemp,fThird);
00219 }
00220 else
00221 {
00222 m_afRoot[0] = -Math<Real>::Pow(-fTemp,fThird);
00223 }
00224 fTemp = -fHalfB - fDiscr;
00225 if ( fTemp >= (Real)0.0 )
00226 {
00227 m_afRoot[0] += Math<Real>::Pow(fTemp,fThird);
00228 }
00229 else
00230 {
00231 m_afRoot[0] -= Math<Real>::Pow(-fTemp,fThird);
00232 }
00233 m_afRoot[0] -= fOffset;
00234 m_iCount = 1;
00235 }
00236 else if (fDiscr < (Real)0.0)
00237 {
00238 const Real fSqrt3 = Math<Real>::Sqrt((Real)3.0);
00239 Real fDist = Math<Real>::Sqrt(-fThird*fA);
00240 Real fAngle = fThird*Math<Real>::ATan2(Math<Real>::Sqrt(-fDiscr),
00241 -fHalfB);
00242 Real fCos = Math<Real>::Cos(fAngle);
00243 Real fSin = Math<Real>::Sin(fAngle);
00244 m_afRoot[0] = ((Real)2.0)*fDist*fCos-fOffset;
00245 m_afRoot[1] = -fDist*(fCos+fSqrt3*fSin)-fOffset;
00246 m_afRoot[2] = -fDist*(fCos-fSqrt3*fSin)-fOffset;
00247 m_iCount = 3;
00248 }
00249 else
00250 {
00251 Real fTemp;
00252 if (fHalfB >= (Real)0.0)
00253 {
00254 fTemp = -Math<Real>::Pow(fHalfB,fThird);
00255 }
00256 else
00257 {
00258 fTemp = Math<Real>::Pow(-fHalfB,fThird);
00259 }
00260 m_afRoot[0] = ((Real)2.0)*fTemp-fOffset;
00261 m_afRoot[1] = -fTemp-fOffset;
00262 m_afRoot[2] = m_afRoot[1];
00263 m_iCount = 3;
00264 }
00265
00266 return true;
00267 }
00268
00269 template <class Real>
00270 bool PolynomialRoots<Real>::FindE (Real fC0, Real fC1, Real fC2, Real fC3,
00271 bool bDoBalancing)
00272 {
00273 if (Math<Real>::FAbs(fC3) <= m_fEpsilon)
00274 {
00275
00276 return FindA(fC0,fC1,fC2);
00277 }
00278
00279
00280 Real fInvC3 = ((Real)1.0)/fC3;
00281 fC0 *= fInvC3;
00282 fC1 *= fInvC3;
00283 fC2 *= fInvC3;
00284
00285
00286 GMatrix<Real> kMat(3,3);
00287 kMat[1][0] = (Real)1.0;
00288 kMat[2][1] = (Real)1.0;
00289 kMat[0][2] = -fC0;
00290 kMat[1][2] = -fC1;
00291 kMat[2][2] = -fC2;
00292
00293 if (bDoBalancing)
00294 {
00295 BalanceCompanion3(kMat);
00296 }
00297
00298 return QRIteration3(kMat);
00299 }
00300
00301 template <class Real>
00302 Real PolynomialRoots<Real>::GetBound (Real fC0, Real fC1, Real fC2, Real fC3)
00303 {
00304 if (Math<Real>::FAbs(fC3) <= m_fEpsilon)
00305 {
00306
00307 return GetBound(fC0,fC1,fC2);
00308 }
00309
00310 Real fInvC3 = ((Real)1.0)/fC3;
00311 Real fMax = Math<Real>::FAbs(fC0)*fInvC3;
00312
00313 Real fTmp = Math<Real>::FAbs(fC1)*fInvC3;
00314 if (fTmp > fMax)
00315 {
00316 fMax = fTmp;
00317 }
00318
00319 fTmp = Math<Real>::FAbs(fC2)*fInvC3;
00320 if (fTmp > fMax)
00321 {
00322 fMax = fTmp;
00323 }
00324
00325 return (Real)1.0 + fMax;
00326 }
00327
00328 template <class Real>
00329 Real PolynomialRoots<Real>::SpecialCubic (Real fA, Real fB, Real fC)
00330 {
00331
00332
00333
00334
00335
00336
00337
00338
00339 const Real fThird = (Real)1.0/(Real)3.0;
00340 Real fD = Math<Real>::Sqrt(((Real)4.0)*fThird*fB/fA);
00341 Real fE = ((Real)4.0)*fC/(fA*fD*fD*fD);
00342 Real fF = Math<Real>::Pow(fE+Math<Real>::Sqrt(fE*fE+(Real)1.0),fThird);
00343 Real fRoot = ((Real)0.5)*fD*(fF-((Real)1.0)/fF);
00344 return fRoot;
00345 }
00346
00347 template <class Real>
00348 Real PolynomialRoots<Real>::GetRowNorm (int iRow, GMatrix<Real>& rkMat)
00349 {
00350 Real fNorm = Math<Real>::FAbs(rkMat[iRow][0]);
00351 for (int iCol = 1; iCol < rkMat.GetColumns(); iCol++)
00352 {
00353 Real fAbs = Math<Real>::FAbs(rkMat[iRow][iCol]);
00354 if (fAbs > fNorm)
00355 {
00356 fNorm = fAbs;
00357 }
00358 }
00359 return fNorm;
00360 }
00361
00362 template <class Real>
00363 Real PolynomialRoots<Real>::GetColNorm (int iCol, GMatrix<Real>& rkMat)
00364 {
00365 Real fNorm = Math<Real>::FAbs(rkMat[0][iCol]);
00366 for (int iRow = 1; iRow < rkMat.GetRows(); iRow++)
00367 {
00368 Real fAbs = Math<Real>::FAbs(rkMat[iRow][iCol]);
00369 if (fAbs > fNorm)
00370 {
00371 fNorm = fAbs;
00372 }
00373 }
00374 return fNorm;
00375 }
00376
00377 template <class Real>
00378 void PolynomialRoots<Real>::ScaleRow (int iRow, Real fScale,
00379 GMatrix<Real>& rkMat)
00380 {
00381 for (int iCol = 0; iCol < rkMat.GetColumns(); iCol++)
00382 {
00383 rkMat[iRow][iCol] *= fScale;
00384 }
00385 }
00386
00387 template <class Real>
00388 void PolynomialRoots<Real>::ScaleCol (int iCol, Real fScale,
00389 GMatrix<Real>& rkMat)
00390 {
00391 for (int iRow = 0; iRow < rkMat.GetRows(); iRow++)
00392 {
00393 rkMat[iRow][iCol] *= fScale;
00394 }
00395 }
00396
00397 template <class Real>
00398 bool PolynomialRoots<Real>::IsBalanced3 (GMatrix<Real>& rkMat)
00399 {
00400 const Real fTolerance = (Real)0.001;
00401 for (int i = 0; i < 3; i++)
00402 {
00403 Real fRowNorm = GetRowNorm(i,rkMat);
00404 Real fColNorm = GetColNorm(i,rkMat);
00405 Real fTest = Math<Real>::FAbs((Real)1.0 - fColNorm/fRowNorm);
00406 if (fTest > fTolerance)
00407 {
00408 return false;
00409 }
00410 }
00411 return true;
00412 }
00413
00414 template <class Real>
00415 void PolynomialRoots<Real>::Balance3 (GMatrix<Real>& rkMat)
00416 {
00417 const int iMax = 16;
00418 int i;
00419 for (i = 0; i < iMax; i++)
00420 {
00421 for (int j = 0; j < 3; j++)
00422 {
00423 Real fRowNorm = GetRowNorm(j,rkMat);
00424 Real fColNorm = GetColNorm(j,rkMat);
00425 Real fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00426 Real fInvScale = ((Real)1.0)/fScale;
00427 ScaleRow(j,fScale,rkMat);
00428 ScaleCol(j,fInvScale,rkMat);
00429 }
00430
00431 if (IsBalanced3(rkMat))
00432 {
00433 break;
00434 }
00435 }
00436 assert(i < iMax);
00437 }
00438
00439 template <class Real>
00440 bool PolynomialRoots<Real>::IsBalancedCompanion3 (Real fA10, Real fA21,
00441 Real fA02, Real fA12, Real fA22)
00442 {
00443 const Real fTolerance = (Real)0.001;
00444
00445
00446 Real fRowNorm = fA02;
00447 Real fColNorm = fA10;
00448 Real fTest = Math<Real>::FAbs((Real)1.0 - fColNorm/fRowNorm);
00449 if (fTest > fTolerance)
00450 {
00451 return false;
00452 }
00453
00454
00455 fRowNorm = (fA10 >= fA12 ? fA10 : fA12);
00456 fColNorm = fA21;
00457 fTest = Math<Real>::FAbs((Real)1.0 - fColNorm/fRowNorm);
00458 if (fTest > fTolerance)
00459 {
00460 return false;
00461 }
00462
00463
00464 fRowNorm = (fA21 >= fA22 ? fA21 : fA22);
00465 fColNorm = (fA02 >= fA12 ? fA02 : fA12);
00466 if (fA22 > fColNorm)
00467 {
00468 fColNorm = fA22;
00469 }
00470 fTest = Math<Real>::FAbs((Real)1.0 - fColNorm/fRowNorm);
00471 return fTest <= fTolerance;
00472 }
00473
00474 template <class Real>
00475 void PolynomialRoots<Real>::BalanceCompanion3 (GMatrix<Real>& rkMat)
00476 {
00477 Real fA10 = Math<Real>::FAbs(rkMat[1][0]);
00478 Real fA21 = Math<Real>::FAbs(rkMat[2][1]);
00479 Real fA02 = Math<Real>::FAbs(rkMat[0][2]);
00480 Real fA12 = Math<Real>::FAbs(rkMat[1][2]);
00481 Real fA22 = Math<Real>::FAbs(rkMat[2][2]);
00482 Real fRowNorm, fColNorm, fScale, fInvScale;
00483
00484 const int iMax = 16;
00485 int i;
00486 for (i = 0; i < iMax; i++)
00487 {
00488
00489 fRowNorm = fA02;
00490 fColNorm = fA10;
00491 fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00492 fA02 *= fScale;
00493 fA10 = fA02;
00494
00495
00496 fRowNorm = (fA10 >= fA12 ? fA10 : fA12);
00497 fColNorm = fA21;
00498 fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00499 fInvScale = ((Real)1.0)/fScale;
00500 fA10 *= fScale;
00501 fA12 *= fScale;
00502 fA21 *= fInvScale;
00503
00504
00505 fRowNorm = (fA21 >= fA22 ? fA21 : fA22);
00506 fColNorm = (fA02 >= fA12 ? fA02 : fA12);
00507 if (fA22 > fColNorm)
00508 {
00509 fColNorm = fA22;
00510 }
00511 fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00512 fInvScale = ((Real)1.0)/fScale;
00513 fA21 *= fScale;
00514 fA02 *= fInvScale;
00515 fA12 *= fInvScale;
00516
00517 if (IsBalancedCompanion3(fA10,fA21,fA02,fA12,fA22))
00518 {
00519 break;
00520 }
00521 }
00522 assert(i < iMax);
00523
00524 rkMat[1][0] = (rkMat[1][0] >= (Real)0.0 ? fA10 : -fA10);
00525 rkMat[2][1] = (rkMat[2][1] >= (Real)0.0 ? fA21 : -fA21);
00526 rkMat[0][2] = (rkMat[0][2] >= (Real)0.0 ? fA02 : -fA02);
00527 rkMat[1][2] = (rkMat[1][2] >= (Real)0.0 ? fA12 : -fA12);
00528 rkMat[2][2] = (rkMat[2][2] >= (Real)0.0 ? fA22 : -fA22);
00529 }
00530
00531 template <class Real>
00532 bool PolynomialRoots<Real>::QRIteration3 (GMatrix<Real>& rkMat)
00533 {
00534 GVector<Real> kW(3);
00535 Real fRHS, fTrace, fDet;
00536 for (int i = 0; i < m_iMaxIterations; i++)
00537 {
00538 fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[0][0]) +
00539 Math<Real>::FAbs(rkMat[1][1]));
00540
00541 if (Math<Real>::FAbs(rkMat[1][0]) <= fRHS)
00542 {
00543
00544 fTrace = rkMat[1][1] + rkMat[2][2];
00545 fDet = rkMat[1][1]*rkMat[2][2] - rkMat[1][2]*rkMat[2][1];
00546 FindA(fDet,-fTrace,(Real)1.0);
00547 m_afRoot[m_iCount++] = rkMat[0][0];
00548 return true;
00549 }
00550
00551 fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[1][1]) +
00552 Math<Real>::FAbs(rkMat[2][2]));
00553
00554 if (Math<Real>::FAbs(rkMat[2][1]) <= fRHS)
00555 {
00556
00557 fTrace = rkMat[0][0] + rkMat[1][1];
00558 fDet = rkMat[0][0]*rkMat[1][1] - rkMat[0][1]*rkMat[1][0];
00559 FindA(fDet,-fTrace,(Real)1.0);
00560 m_afRoot[m_iCount++] = rkMat[2][2];
00561 return true;
00562 }
00563
00564 FrancisQRStep(rkMat,kW);
00565 }
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 if (Math<Real>::FAbs(rkMat[1][0]) <= Math<Real>::FAbs(rkMat[2][1]))
00581 {
00582
00583 fTrace = rkMat[1][1] + rkMat[2][2];
00584 fDet = rkMat[1][1]*rkMat[2][2] - rkMat[1][2]*rkMat[2][1];
00585 FindA(fDet,-fTrace,(Real)1.0);
00586 m_afRoot[m_iCount++] = rkMat[0][0];
00587 }
00588 else
00589 {
00590
00591 fTrace = rkMat[0][0] + rkMat[1][1];
00592 fDet = rkMat[0][0]*rkMat[1][1] - rkMat[0][1]*rkMat[1][0];
00593 FindA(fDet,-fTrace,(Real)1.0);
00594 m_afRoot[m_iCount++] = rkMat[2][2];
00595 }
00596
00597 return true;
00598 }
00599
00600
00601
00602
00603
00604 template <class Real>
00605 bool PolynomialRoots<Real>::FindA (Real fC0, Real fC1, Real fC2, Real fC3,
00606 Real fC4)
00607 {
00608 if (Math<Real>::FAbs(fC4) <= m_fEpsilon)
00609 {
00610
00611 return FindA(fC0,fC1,fC2,fC3);
00612 }
00613
00614
00615 Real fInvC4 = ((Real)1.0)/fC4;
00616 fC0 *= fInvC4;
00617 fC1 *= fInvC4;
00618 fC2 *= fInvC4;
00619 fC3 *= fInvC4;
00620
00621
00622 Real fR0 = -fC3*fC3*fC0 + ((Real)4.0)*fC2*fC0 - fC1*fC1;
00623 Real fR1 = fC3*fC1 - ((Real)4.0)*fC0;
00624 Real fR2 = -fC2;
00625 FindA(fR0,fR1,fR2,(Real)1.0);
00626 Real fY = m_afRoot[0];
00627
00628 m_iCount = 0;
00629 Real fDiscr = ((Real)0.25)*fC3*fC3 - fC2 + fY;
00630 if (Math<Real>::FAbs(fDiscr) <= m_fEpsilon)
00631 {
00632 fDiscr = (Real)0.0;
00633 }
00634
00635 if (fDiscr > (Real)0.0)
00636 {
00637 Real fR = Math<Real>::Sqrt(fDiscr);
00638 Real fT1 = ((Real)0.75)*fC3*fC3 - fR*fR - ((Real)2.0)*fC2;
00639 Real fT2 = (((Real)4.0)*fC3*fC2 - ((Real)8.0)*fC1 - fC3*fC3*fC3) /
00640 (((Real)4.0)*fR);
00641
00642 Real fTplus = fT1+fT2;
00643 Real fTminus = fT1-fT2;
00644 if (Math<Real>::FAbs(fTplus) <= m_fEpsilon)
00645 {
00646 fTplus = (Real)0.0;
00647 }
00648 if (Math<Real>::FAbs(fTminus) <= m_fEpsilon)
00649 {
00650 fTminus = (Real)0.0;
00651 }
00652
00653 if (fTplus >= (Real)0.0)
00654 {
00655 Real fD = Math<Real>::Sqrt(fTplus);
00656 m_afRoot[0] = -((Real)0.25)*fC3+((Real)0.5)*(fR+fD);
00657 m_afRoot[1] = -((Real)0.25)*fC3+((Real)0.5)*(fR-fD);
00658 m_iCount += 2;
00659 }
00660 if (fTminus >= (Real)0.0)
00661 {
00662 Real fE = Math<Real>::Sqrt(fTminus);
00663 m_afRoot[m_iCount++] = -((Real)0.25)*fC3+((Real)0.5)*(fE-fR);
00664 m_afRoot[m_iCount++] = -((Real)0.25)*fC3-((Real)0.5)*(fE+fR);
00665 }
00666 }
00667 else if (fDiscr < (Real)0.0)
00668 {
00669 m_iCount = 0;
00670 }
00671 else
00672 {
00673 Real fT2 = fY*fY-((Real)4.0)*fC0;
00674 if (fT2 >= -m_fEpsilon)
00675 {
00676 if (fT2 < (Real)0.0)
00677 {
00678 fT2 = (Real)0.0;
00679 }
00680 fT2 = ((Real)2.0)*Math<Real>::Sqrt(fT2);
00681 Real fT1 = ((Real)0.75)*fC3*fC3 - ((Real)2.0)*fC2;
00682 if (fT1+fT2 >= m_fEpsilon)
00683 {
00684 Real fD = Math<Real>::Sqrt(fT1+fT2);
00685 m_afRoot[0] = -((Real)0.25)*fC3+((Real)0.5)*fD;
00686 m_afRoot[1] = -((Real)0.25)*fC3-((Real)0.5)*fD;
00687 m_iCount += 2;
00688 }
00689 if (fT1-fT2 >= m_fEpsilon)
00690 {
00691 Real fE = Math<Real>::Sqrt(fT1-fT2);
00692 m_afRoot[m_iCount++] = -((Real)0.25)*fC3+((Real)0.5)*fE;
00693 m_afRoot[m_iCount++] = -((Real)0.25)*fC3-((Real)0.5)*fE;
00694 }
00695 }
00696 }
00697
00698 return m_iCount > 0;
00699 }
00700
00701 template <class Real>
00702 bool PolynomialRoots<Real>::FindE (Real fC0, Real fC1, Real fC2, Real fC3,
00703 Real fC4, bool bDoBalancing)
00704 {
00705 if (Math<Real>::FAbs(fC4) <= m_fEpsilon)
00706 {
00707
00708 return FindA(fC0,fC1,fC2,fC3);
00709 }
00710
00711
00712 Real fInvC4 = ((Real)1.0)/fC4;
00713 fC0 *= fInvC4;
00714 fC1 *= fInvC4;
00715 fC2 *= fInvC4;
00716 fC3 *= fInvC4;
00717
00718
00719 GMatrix<Real> kMat(4,4);
00720 kMat[1][0] = (Real)1.0;
00721 kMat[2][1] = (Real)1.0;
00722 kMat[3][2] = (Real)1.0;
00723 kMat[0][3] = -fC0;
00724 kMat[1][3] = -fC1;
00725 kMat[2][3] = -fC2;
00726 kMat[3][3] = -fC3;
00727
00728 if (bDoBalancing)
00729 {
00730 BalanceCompanion4(kMat);
00731 }
00732
00733 return QRIteration4(kMat);
00734 }
00735
00736 template <class Real>
00737 Real PolynomialRoots<Real>::GetBound (Real fC0, Real fC1, Real fC2, Real fC3,
00738 Real fC4)
00739 {
00740 if (Math<Real>::FAbs(fC4) <= m_fEpsilon)
00741 {
00742
00743 return GetBound(fC0,fC1,fC2,fC3);
00744 }
00745
00746 Real fInvC4 = ((Real)1.0)/fC4;
00747 Real fMax = Math<Real>::FAbs(fC0)*fInvC4;
00748
00749 Real fTmp = Math<Real>::FAbs(fC1)*fInvC4;
00750 if (fTmp > fMax)
00751 {
00752 fMax = fTmp;
00753 }
00754
00755 fTmp = Math<Real>::FAbs(fC2)*fInvC4;
00756 if (fTmp > fMax)
00757 {
00758 fMax = fTmp;
00759 }
00760
00761 fTmp = Math<Real>::FAbs(fC3)*fInvC4;
00762 if (fTmp > fMax)
00763 {
00764 fMax = fTmp;
00765 }
00766
00767 return (Real)1.0 + fMax;
00768 }
00769
00770 template <class Real>
00771 bool PolynomialRoots<Real>::IsBalancedCompanion4 (Real fA10, Real fA21,
00772 Real fA32, Real fA03, Real fA13, Real fA23, Real fA33)
00773 {
00774 const Real fTolerance = (Real)0.001;
00775
00776
00777 Real fRowNorm = fA03;
00778 Real fColNorm = fA10;
00779 Real fTest = Math<Real>::FAbs(1.0f - fColNorm/fRowNorm);
00780 if (fTest > fTolerance)
00781 {
00782 return false;
00783 }
00784
00785
00786 fRowNorm = (fA10 >= fA13 ? fA10 : fA13);
00787 fColNorm = fA21;
00788 fTest = Math<Real>::FAbs(1.0f - fColNorm/fRowNorm);
00789 if (fTest > fTolerance)
00790 {
00791 return false;
00792 }
00793
00794
00795 fRowNorm = (fA21 >= fA23 ? fA21 : fA23);
00796 fColNorm = fA32;
00797 fTest = Math<Real>::FAbs(1.0f - fColNorm/fRowNorm);
00798 if (fTest > fTolerance)
00799 {
00800 return false;
00801 }
00802
00803
00804 fRowNorm = (fA32 >= fA33 ? fA32 : fA33);
00805 fColNorm = (fA03 >= fA13 ? fA03 : fA13);
00806 if (fA23 > fColNorm)
00807 {
00808 fColNorm = fA23;
00809 }
00810 if (fA33 > fColNorm)
00811 {
00812 fColNorm = fA33;
00813 }
00814 fTest = Math<Real>::FAbs(1.0f - fColNorm/fRowNorm);
00815 return fTest <= fTolerance;
00816 }
00817
00818 template <class Real>
00819 void PolynomialRoots<Real>::BalanceCompanion4 (GMatrix<Real>& rkMat)
00820 {
00821 Real fA10 = Math<Real>::FAbs(rkMat[1][0]);
00822 Real fA21 = Math<Real>::FAbs(rkMat[2][1]);
00823 Real fA32 = Math<Real>::FAbs(rkMat[3][2]);
00824 Real fA03 = Math<Real>::FAbs(rkMat[0][3]);
00825 Real fA13 = Math<Real>::FAbs(rkMat[1][3]);
00826 Real fA23 = Math<Real>::FAbs(rkMat[2][3]);
00827 Real fA33 = Math<Real>::FAbs(rkMat[3][3]);
00828 Real fRowNorm, fColNorm, fScale, fInvScale;
00829
00830 const int iMax = 16;
00831 int i;
00832 for (i = 0; i < iMax; i++)
00833 {
00834
00835 fRowNorm = fA03;
00836 fColNorm = fA10;
00837 fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00838 fA03 *= fScale;
00839 fA10 = fA03;
00840
00841
00842 fRowNorm = (fA10 >= fA13 ? fA10 : fA13);
00843 fColNorm = fA21;
00844 fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00845 fInvScale = ((Real)1.0)/fScale;
00846 fA10 *= fScale;
00847 fA13 *= fScale;
00848 fA21 *= fInvScale;
00849
00850
00851 fRowNorm = (fA21 >= fA23 ? fA21 : fA23);
00852 fColNorm = fA32;
00853 fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00854 fInvScale = ((Real)1.0)/fScale;
00855 fA21 *= fScale;
00856 fA23 *= fScale;
00857 fA32 *= fInvScale;
00858
00859
00860 fRowNorm = (fA32 >= fA33 ? fA32 : fA33);
00861 fColNorm = (fA03 >= fA13 ? fA03 : fA13);
00862 if (fA23 > fColNorm)
00863 {
00864 fColNorm = fA23;
00865 }
00866 if (fA33 > fColNorm)
00867 {
00868 fColNorm = fA33;
00869 }
00870 fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00871 fInvScale = ((Real)1.0)/fScale;
00872 fA32 *= fScale;
00873 fA03 *= fInvScale;
00874 fA13 *= fInvScale;
00875 fA23 *= fInvScale;
00876
00877 if (IsBalancedCompanion4(fA10,fA21,fA32,fA03,fA13,fA23,fA33))
00878 {
00879 break;
00880 }
00881 }
00882 assert(i < iMax);
00883
00884 rkMat[1][0] = (rkMat[1][0] >= (Real)0.0 ? fA10 : -fA10);
00885 rkMat[2][1] = (rkMat[2][1] >= (Real)0.0 ? fA21 : -fA21);
00886 rkMat[3][2] = (rkMat[3][2] >= (Real)0.0 ? fA32 : -fA32);
00887 rkMat[0][3] = (rkMat[0][3] >= (Real)0.0 ? fA03 : -fA03);
00888 rkMat[1][3] = (rkMat[1][3] >= (Real)0.0 ? fA13 : -fA13);
00889 rkMat[2][3] = (rkMat[2][3] >= (Real)0.0 ? fA23 : -fA23);
00890 rkMat[3][3] = (rkMat[3][3] >= (Real)0.0 ? fA33 : -fA33);
00891 }
00892
00893 template <class Real>
00894 bool PolynomialRoots<Real>::QRIteration4 (GMatrix<Real>& rkMat)
00895 {
00896 GVector<Real> kW(4);
00897 GMatrix<Real> kMS(3,3);
00898 Real fRHS, fTrace, fDet, afSaveRoot[2];
00899 int i, j, iSaveCount;
00900 for (i = 0; i < m_iMaxIterations; i++)
00901 {
00902 fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[0][0]) +
00903 Math<Real>::FAbs(rkMat[1][1]));
00904
00905 if (Math<Real>::FAbs(rkMat[1][0]) <= fRHS)
00906 {
00907
00908
00909
00910 kMS[0][0] = rkMat[1][1];
00911 kMS[0][1] = rkMat[1][2];
00912 kMS[0][2] = rkMat[1][3];
00913 kMS[1][0] = rkMat[2][1];
00914 kMS[1][1] = rkMat[2][2];
00915 kMS[1][2] = rkMat[2][3];
00916 kMS[2][0] = rkMat[3][1];
00917 kMS[2][1] = rkMat[3][2];
00918 kMS[2][2] = rkMat[3][3];
00919 QRIteration3(kMS);
00920 m_afRoot[m_iCount++] = rkMat[0][0];
00921 return true;
00922 }
00923
00924 fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[1][1]) +
00925 Math<Real>::FAbs(rkMat[2][2]));
00926
00927 if (Math<Real>::FAbs(rkMat[2][1]) <= fRHS)
00928 {
00929
00930
00931 fTrace = rkMat[0][0] + rkMat[1][1];
00932 fDet = rkMat[0][0]*rkMat[1][1] - rkMat[0][1]*rkMat[1][0];
00933 FindA(fDet,-fTrace,(Real)1.0);
00934 iSaveCount = m_iCount;
00935 for (j = 0; j < iSaveCount; j++)
00936 {
00937 afSaveRoot[j] = m_afRoot[j];
00938 }
00939
00940 fTrace = rkMat[2][2] + rkMat[3][3];
00941 fDet = rkMat[2][2]*rkMat[3][3] - rkMat[2][3]*rkMat[3][2];
00942 FindA(fDet,-fTrace,(Real)1.0);
00943 for (j = 0; j < iSaveCount; j++)
00944 {
00945 m_afRoot[m_iCount++] = afSaveRoot[j];
00946 }
00947 return m_iCount > 0;
00948 }
00949
00950 fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[2][2]) +
00951 Math<Real>::FAbs(rkMat[3][3]));
00952
00953 if (Math<Real>::FAbs(rkMat[3][2]) <= fRHS)
00954 {
00955
00956
00957
00958 kMS[0][0] = rkMat[0][0];
00959 kMS[0][1] = rkMat[0][1];
00960 kMS[0][2] = rkMat[0][2];
00961 kMS[1][0] = rkMat[1][0];
00962 kMS[1][1] = rkMat[1][1];
00963 kMS[1][2] = rkMat[1][2];
00964 kMS[2][0] = rkMat[2][0];
00965 kMS[2][1] = rkMat[2][1];
00966 kMS[2][2] = rkMat[2][2];
00967 QRIteration3(kMS);
00968 m_afRoot[m_iCount++] = rkMat[3][3];
00969 return true;
00970 }
00971
00972 FrancisQRStep(rkMat,kW);
00973 }
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984 i = 0;
00985 Real fMin = Math<Real>::FAbs(rkMat[1][0]);
00986 Real fAbs = Math<Real>::FAbs(rkMat[2][1]);
00987 if (fAbs < fMin)
00988 {
00989 fMin = fAbs;
00990 i = 1;
00991 }
00992 fAbs = Math<Real>::FAbs(rkMat[3][2]);
00993 if (fAbs < fMin)
00994 {
00995 fMin = fAbs;
00996 i = 2;
00997 }
00998
00999 if (i == 0)
01000 {
01001
01002
01003
01004 kMS[0][0] = rkMat[1][1];
01005 kMS[0][1] = rkMat[1][2];
01006 kMS[0][2] = rkMat[1][3];
01007 kMS[1][0] = rkMat[2][1];
01008 kMS[1][1] = rkMat[2][2];
01009 kMS[1][2] = rkMat[2][3];
01010 kMS[2][0] = rkMat[3][1];
01011 kMS[2][1] = rkMat[3][2];
01012 kMS[2][2] = rkMat[3][3];
01013 QRIteration3(kMS);
01014 m_afRoot[m_iCount++] = rkMat[0][0];
01015 }
01016 else if (i == 1)
01017 {
01018
01019
01020 fTrace = rkMat[0][0] + rkMat[1][1];
01021 fDet = rkMat[0][0]*rkMat[1][1] - rkMat[0][1]*rkMat[1][0];
01022 FindA(fDet,-fTrace,(Real)1.0);
01023 iSaveCount = m_iCount;
01024 for (j = 0; j < iSaveCount; j++)
01025 {
01026 afSaveRoot[j] = m_afRoot[j];
01027 }
01028
01029 fTrace = rkMat[2][2] + rkMat[3][3];
01030 fDet = rkMat[2][2]*rkMat[3][3] - rkMat[2][3]*rkMat[3][2];
01031 FindA(fDet,-fTrace,(Real)1.0);
01032 for (j = 0; j < iSaveCount; j++)
01033 {
01034 m_afRoot[m_iCount++] = afSaveRoot[j];
01035 }
01036 }
01037 else
01038 {
01039
01040
01041
01042 kMS[0][0] = rkMat[0][0];
01043 kMS[0][1] = rkMat[0][1];
01044 kMS[0][2] = rkMat[0][2];
01045 kMS[1][0] = rkMat[1][0];
01046 kMS[1][1] = rkMat[1][1];
01047 kMS[1][2] = rkMat[1][2];
01048 kMS[2][0] = rkMat[2][0];
01049 kMS[2][1] = rkMat[2][1];
01050 kMS[2][2] = rkMat[2][2];
01051 QRIteration3(kMS);
01052 m_afRoot[m_iCount++] = rkMat[3][3];
01053 }
01054
01055 return m_iCount > 0;
01056 }
01057
01058
01059
01060
01061
01062 template <class Real>
01063 bool PolynomialRoots<Real>::FindB (const Polynomial1<Real>& rkPoly,
01064 int iDigits)
01065 {
01066 Real fBound = GetBound(rkPoly);
01067 return FindB(rkPoly,-fBound,fBound,iDigits);
01068 }
01069
01070 template <class Real>
01071 bool PolynomialRoots<Real>::FindN (const Polynomial1<Real>&, int)
01072 {
01073
01074 assert(false);
01075 return false;
01076 }
01077
01078 template <class Real>
01079 bool PolynomialRoots<Real>::FindE (const Polynomial1<Real>&, bool)
01080 {
01081
01082 assert(false);
01083 return false;
01084 }
01085
01086 template <class Real>
01087 Real PolynomialRoots<Real>::GetBound (const Polynomial1<Real>& rkPoly)
01088 {
01089 Polynomial1<Real> kCPoly = rkPoly;
01090 kCPoly.Compress(m_fEpsilon);
01091 int iDegree = kCPoly.GetDegree();
01092 if (iDegree < 1)
01093 {
01094
01095 return -(Real)1.0;
01096 }
01097
01098 Real fInvCDeg = ((Real)1.0)/kCPoly[iDegree];
01099 Real fMax = (Real)0.0;
01100 for (int i = 0; i < iDegree; i++)
01101 {
01102 Real fTmp = Math<Real>::FAbs(kCPoly[i])*fInvCDeg;
01103 if (fTmp > fMax)
01104 {
01105 fMax = fTmp;
01106 }
01107 }
01108
01109 return (Real)1.0 + fMax;
01110 }
01111
01112 template <class Real>
01113 bool PolynomialRoots<Real>::FindB (const Polynomial1<Real>& rkPoly,
01114 Real fXMin, Real fXMax, int iDigits)
01115 {
01116
01117 if (rkPoly.GetDegree() > m_iMaxRoot)
01118 {
01119 m_iMaxRoot = rkPoly.GetDegree();
01120 WM4_DELETE[] m_afRoot;
01121 m_afRoot = WM4_NEW Real[m_iMaxRoot];
01122 }
01123
01124 Real fRoot;
01125 if (rkPoly.GetDegree() == 1)
01126 {
01127 if (Bisection(rkPoly,fXMin,fXMax,iDigits,fRoot))
01128 {
01129 m_iCount = 1;
01130 m_afRoot[0] = fRoot;
01131 return true;
01132 }
01133 m_iCount = 0;
01134 return false;
01135 }
01136
01137
01138 Polynomial1<Real> kDeriv = rkPoly.GetDerivative();
01139 FindB(kDeriv,fXMin,fXMax,iDigits);
01140
01141 int i, iNewCount = 0;
01142 Real* afNewRoot = WM4_NEW Real[m_iCount+1];
01143
01144 if ( m_iCount > 0 )
01145 {
01146
01147 if (Bisection(rkPoly,fXMin,m_afRoot[0],iDigits,fRoot))
01148 {
01149 afNewRoot[iNewCount++] = fRoot;
01150 }
01151
01152
01153 for (i = 0; i <= m_iCount-2; i++)
01154 {
01155 if (Bisection(rkPoly,m_afRoot[i],m_afRoot[i+1],iDigits,fRoot))
01156 {
01157 afNewRoot[iNewCount++] = fRoot;
01158 }
01159 }
01160
01161
01162 if (Bisection(rkPoly,m_afRoot[m_iCount-1],fXMax,iDigits,fRoot))
01163 {
01164 afNewRoot[iNewCount++] = fRoot;
01165 }
01166 }
01167 else
01168 {
01169
01170 if (Bisection(rkPoly,fXMin,fXMax,iDigits,fRoot))
01171 {
01172 afNewRoot[iNewCount++] = fRoot;
01173 }
01174 }
01175
01176
01177 if (iNewCount > 0)
01178 {
01179 m_iCount = 1;
01180 m_afRoot[0] = afNewRoot[0];
01181 for (i = 1; i < iNewCount; i++)
01182 {
01183 Real fRootDiff = afNewRoot[i]-afNewRoot[i-1];
01184 if (Math<Real>::FAbs(fRootDiff) > m_fEpsilon)
01185 {
01186 m_afRoot[m_iCount++] = afNewRoot[i];
01187 }
01188 }
01189 }
01190 else
01191 {
01192 m_iCount = 0;
01193 }
01194
01195 WM4_DELETE[] afNewRoot;
01196 return m_iCount > 0;
01197 }
01198
01199 template <class Real>
01200 bool PolynomialRoots<Real>::FindN (const Polynomial1<Real>&, Real, Real, int)
01201 {
01202
01203 assert(false);
01204 return false;
01205 }
01206
01207 template <class Real>
01208 bool PolynomialRoots<Real>::AllRealPartsNegative (
01209 const Polynomial1<Real>& rkPoly)
01210 {
01211
01212 int iDegree = rkPoly.GetDegree();
01213 const Real* afPolyCoeff = (const Real*)rkPoly;
01214 Real* afCoeff = WM4_NEW Real[iDegree+1];
01215 size_t uiSize = (iDegree+1)*sizeof(Real);
01216 System::Memcpy(afCoeff,uiSize,afPolyCoeff,uiSize);
01217
01218
01219 if (afCoeff[iDegree] != (Real)1.0)
01220 {
01221 Real fInv = ((Real)1.0)/afCoeff[iDegree];
01222 for (int i = 0; i < iDegree; i++)
01223 {
01224 afCoeff[i] *= fInv;
01225 }
01226 afCoeff[iDegree] = (Real)1.0;
01227 }
01228
01229 return AllRealPartsNegative(iDegree,afCoeff);
01230 }
01231
01232 template <class Real>
01233 bool PolynomialRoots<Real>::AllRealPartsPositive (
01234 const Polynomial1<Real>& rkPoly)
01235 {
01236
01237 int iDegree = rkPoly.GetDegree();
01238 const Real* afPolyCoeff = (const Real*)rkPoly;
01239 Real* afCoeff = WM4_NEW Real[iDegree+1];
01240 size_t uiSize = (iDegree+1)*sizeof(Real);
01241 System::Memcpy(afCoeff,uiSize,afPolyCoeff,uiSize);
01242
01243
01244 int i;
01245 if (afCoeff[iDegree] != (Real)1.0)
01246 {
01247 Real fInv = ((Real)1.0)/afCoeff[iDegree];
01248 for (i = 0; i < iDegree; i++)
01249 {
01250 afCoeff[i] *= fInv;
01251 }
01252 afCoeff[iDegree] = (Real)1.0;
01253 }
01254
01255
01256 int iSign = -1;
01257 for (i = iDegree-1; i >= 0; i--, iSign = -iSign)
01258 {
01259 afCoeff[i] *= iSign;
01260 }
01261
01262 return AllRealPartsNegative(iDegree,afCoeff);
01263 }
01264
01265 template <class Real>
01266 bool PolynomialRoots<Real>::AllRealPartsNegative (int iDegree, Real* afCoeff)
01267 {
01268
01269
01270 if (afCoeff[iDegree-1] <= (Real)0.0)
01271 {
01272 return false;
01273 }
01274 if (iDegree == 1)
01275 {
01276 return true;
01277 }
01278
01279 Real* afTmpCoeff = WM4_NEW Real[iDegree];
01280 afTmpCoeff[0] = ((Real)2.0)*afCoeff[0]*afCoeff[iDegree-1];
01281 int i;
01282 for (i = 1; i <= iDegree-2; i++)
01283 {
01284 afTmpCoeff[i] = afCoeff[iDegree-1]*afCoeff[i];
01285 if (((iDegree-i) % 2) == 0)
01286 {
01287 afTmpCoeff[i] -= afCoeff[i-1];
01288 }
01289 afTmpCoeff[i] *= (Real)2.0;
01290 }
01291 afTmpCoeff[iDegree-1] =
01292 ((Real)2.0)*afCoeff[iDegree-1]*afCoeff[iDegree-1];
01293
01294 int iNextDegree;
01295 for (iNextDegree = iDegree-1; iNextDegree >= 0; iNextDegree--)
01296 {
01297 if (afTmpCoeff[iNextDegree] != (Real)0.0)
01298 {
01299 break;
01300 }
01301 }
01302 for (i = 0; i <= iNextDegree-1; i++)
01303 {
01304 afCoeff[i] = afTmpCoeff[i]/afTmpCoeff[iNextDegree];
01305 }
01306 WM4_DELETE[] afTmpCoeff;
01307
01308 return AllRealPartsNegative(iNextDegree,afCoeff);
01309 }
01310
01311 template <class Real>
01312 int PolynomialRoots<Real>::GetRootCount (const Polynomial1<Real>& rkPoly,
01313 Real fT0, Real fT1)
01314 {
01315 int iDegree = rkPoly.GetDegree();
01316 const Real* afCoeff = (const Real*)rkPoly;
01317
01318 if (iDegree == 0)
01319 {
01320
01321 if (afCoeff[0] != (Real)0.0)
01322 {
01323 return 0;
01324 }
01325 else
01326 {
01327 return -1;
01328 }
01329 }
01330
01331
01332 std::vector<Polynomial1<Real>*> kSturm;
01333 Polynomial1<Real>* pkF0 = WM4_NEW Polynomial1<Real>(rkPoly);
01334 Polynomial1<Real>* pkF1 = WM4_NEW Polynomial1<Real>(
01335 pkF0->GetDerivative());
01336 kSturm.push_back(pkF0);
01337 kSturm.push_back(pkF1);
01338
01339 while (pkF1->GetDegree() > 0)
01340 {
01341 Polynomial1<Real>* pkF2 = WM4_NEW Polynomial1<Real>(-1);
01342 Polynomial1<Real> kQuot;
01343 pkF0->Divide(*pkF1,kQuot,*pkF2,Math<Real>::ZERO_TOLERANCE);
01344 *pkF2 = -(*pkF2);
01345 kSturm.push_back(pkF2);
01346 pkF0 = pkF1;
01347 pkF1 = pkF2;
01348 }
01349
01350 int i;
01351 Real fValue0, fValue1;
01352
01353
01354 int iSignChanges0 = 0;
01355 if (fT0 == -Math<Real>::MAX_REAL)
01356 {
01357 pkF0 = kSturm[0];
01358 if (pkF0->GetDegree() & 1)
01359 {
01360 fValue0 = -(*pkF0)[pkF0->GetDegree()];
01361 }
01362 else
01363 {
01364 fValue0 = (*pkF0)[pkF0->GetDegree()];
01365 }
01366
01367 if (Math<Real>::FAbs(fValue0) < m_fEpsilon)
01368 {
01369 fValue0 = (Real)0.0;
01370 }
01371
01372 for (i = 1; i < (int)kSturm.size(); i++)
01373 {
01374 pkF1 = kSturm[i];
01375
01376 if (pkF1->GetDegree() & 1)
01377 {
01378 fValue1 = -(*pkF1)[pkF1->GetDegree()];
01379 }
01380 else
01381 {
01382 fValue1 = (*pkF1)[pkF1->GetDegree()];
01383 }
01384
01385 if (Math<Real>::FAbs(fValue1) < m_fEpsilon)
01386 {
01387 fValue1 = (Real)0.0;
01388 }
01389
01390 if (fValue0*fValue1 < (Real)0.0 || fValue0 == (Real)0.0)
01391 {
01392 iSignChanges0++;
01393 }
01394
01395 fValue0 = fValue1;
01396 pkF0 = pkF1;
01397 }
01398 }
01399 else
01400 {
01401 pkF0 = kSturm[0];
01402 fValue0 = (*pkF0)(fT0);
01403 if (Math<Real>::FAbs(fValue0) < m_fEpsilon)
01404 {
01405 fValue0 = (Real)0.0;
01406 }
01407
01408 for (i = 1; i < (int)kSturm.size(); i++)
01409 {
01410 pkF1 = kSturm[i];
01411 fValue1 = (*pkF1)(fT0);
01412 if (Math<Real>::FAbs(fValue1) < m_fEpsilon)
01413 {
01414 fValue1 = (Real)0.0;
01415 }
01416
01417 if (fValue0*fValue1 < (Real)0.0 || fValue0 == (Real)0.0)
01418 {
01419 iSignChanges0++;
01420 }
01421
01422 fValue0 = fValue1;
01423 pkF0 = pkF1;
01424 }
01425 }
01426
01427
01428 int iSignChanges1 = 0;
01429 if (fT1 == Math<Real>::MAX_REAL)
01430 {
01431 pkF0 = kSturm[0];
01432 fValue0 = (*pkF0)[pkF0->GetDegree()];
01433 if (Math<Real>::FAbs(fValue0) < m_fEpsilon)
01434 {
01435 fValue0 = (Real)0.0;
01436 }
01437
01438 for (i = 1; i < (int)kSturm.size(); i++)
01439 {
01440 pkF1 = kSturm[i];
01441 fValue1 = (*pkF1)[pkF1->GetDegree()];
01442 if (Math<Real>::FAbs(fValue1) < m_fEpsilon)
01443 {
01444 fValue1 = (Real)0.0;
01445 }
01446
01447 if (fValue0*fValue1 < (Real)0.0 || fValue0 == (Real)0.0)
01448 {
01449 iSignChanges1++;
01450 }
01451
01452 fValue0 = fValue1;
01453 pkF0 = pkF1;
01454 }
01455 }
01456 else
01457 {
01458 pkF0 = kSturm[0];
01459 fValue0 = (*pkF0)(fT1);
01460 if (Math<Real>::FAbs(fValue0) < m_fEpsilon)
01461 {
01462 fValue0 = (Real)0.0;
01463 }
01464
01465 for (i = 1; i < (int)kSturm.size(); i++)
01466 {
01467 pkF1 = kSturm[i];
01468 fValue1 = (*pkF1)(fT1);
01469 if (Math<Real>::FAbs(fValue1) < m_fEpsilon)
01470 {
01471 fValue1 = (Real)0.0;
01472 }
01473
01474 if (fValue0*fValue1 < (Real)0.0 || fValue0 == (Real)0.0 )
01475 {
01476 iSignChanges1++;
01477 }
01478
01479 fValue0 = fValue1;
01480 pkF0 = pkF1;
01481 }
01482 }
01483
01484
01485 for (i = 0; i < (int)kSturm.size(); i++)
01486 {
01487 WM4_DELETE kSturm[i];
01488 }
01489
01490 if (iSignChanges0 >= iSignChanges1)
01491 {
01492 return iSignChanges0 - iSignChanges1;
01493 }
01494
01495
01496 assert(false);
01497 return 0;
01498 }
01499
01500 template <class Real>
01501 bool PolynomialRoots<Real>::Bisection (const Polynomial1<Real>& rkPoly,
01502 Real fXMin, Real fXMax, int iDigits, Real& rfRoot)
01503 {
01504 Real fP0 = rkPoly(fXMin);
01505 if (Math<Real>::FAbs(fP0) <= Math<Real>::ZERO_TOLERANCE)
01506 {
01507 rfRoot = fXMin;
01508 return true;
01509 }
01510 Real fP1 = rkPoly(fXMax);
01511 if (Math<Real>::FAbs(fP1) <= Math<Real>::ZERO_TOLERANCE)
01512 {
01513 rfRoot = fXMax;
01514 return true;
01515 }
01516 if (fP0*fP1 > (Real)0.0)
01517 return false;
01518
01519
01520 Real fTmp0 = Math<Real>::Log(fXMax-fXMin);
01521 Real fTmp1 = ((Real)iDigits)*Math<Real>::Log((Real)10.0);
01522 Real fArg = (fTmp0 + fTmp1)/Math<Real>::Log((Real)2.0);
01523 int iMaxIter = (int)(fArg + (Real)0.5);
01524
01525 for (int i = 0; i < iMaxIter; i++)
01526 {
01527 rfRoot = ((Real)0.5)*(fXMin + fXMax);
01528 Real fP = rkPoly(rfRoot);
01529 Real fProduct = fP*fP0;
01530 if (fProduct < (Real)0.0)
01531 {
01532 fXMax = rfRoot;
01533 fP1 = fP;
01534 }
01535 else if (fProduct > (Real)0.0)
01536 {
01537 fXMin = rfRoot;
01538 fP0 = fP;
01539 }
01540 else
01541 {
01542 break;
01543 }
01544 }
01545
01546 return true;
01547 }
01548
01549
01550
01551
01552
01553 template <class Real>
01554 void PolynomialRoots<Real>::GetHouseholderVector (int iSize,
01555 const Vector3<Real>& rkU, Vector3<Real>& rkV)
01556 {
01557
01558
01559
01560
01561
01562
01563 Real fLength = rkU[0]*rkU[0];
01564 int i;
01565 for (i = 1; i < iSize; i++)
01566 {
01567 fLength += rkU[i]*rkU[i];
01568 }
01569 fLength = Math<Real>::Sqrt(fLength);
01570
01571 if (fLength > m_fEpsilon)
01572 {
01573 Real fInv = ((Real)1.0)/(rkU[0]+Math<Real>::Sign(rkU[0])*fLength);
01574 rkV[0] = (Real)1.0;
01575 for (i = 1; i < iSize; i++)
01576 {
01577 rkV[i] = fInv*rkU[i];
01578 }
01579 }
01580 else
01581 {
01582
01583 rkV[0] = (Real)1.0;
01584 for (i = 1; i < iSize; i++)
01585 {
01586 rkV[i] = (Real)0.0;
01587 }
01588 }
01589 }
01590
01591 template <class Real>
01592 void PolynomialRoots<Real>::PremultiplyHouseholder (GMatrix<Real>& rkMat,
01593 GVector<Real>& rkW, int iRMin, int iRMax, int iCMin, int iCMax,
01594 int iVSize, const Vector3<Real>& rkV)
01595 {
01596
01597
01598
01599
01600
01601 int iSubRows = iRMax - iRMin + 1, iSubCols = iCMax - iCMin + 1;
01602 int iRow, iCol;
01603
01604 Real fSqrLen = rkV[0]*rkV[0];
01605 for (int i = 1; i < iVSize; i++)
01606 {
01607 fSqrLen += rkV[i]*rkV[i];
01608 }
01609
01610 Real fBeta = -((Real)2.0)/fSqrLen;
01611 for (iCol = 0; iCol < iSubCols; iCol++)
01612 {
01613 rkW[iCol] = (Real)0.0;
01614 for (iRow = 0; iRow < iSubRows; iRow++)
01615 {
01616 rkW[iCol] += rkV[iRow]*rkMat[iRMin+iRow][iCMin+iCol];
01617 }
01618 rkW[iCol] *= fBeta;
01619 }
01620
01621 for (iRow = 0; iRow < iSubRows; iRow++)
01622 {
01623 for (iCol = 0; iCol < iSubCols; iCol++)
01624 {
01625 rkMat[iRMin+iRow][iCMin+iCol] += rkV[iRow]*rkW[iCol];
01626 }
01627 }
01628 }
01629
01630 template <class Real>
01631 void PolynomialRoots<Real>::PostmultiplyHouseholder (GMatrix<Real>& rkMat,
01632 GVector<Real>& rkW, int iRMin, int iRMax, int iCMin, int iCMax,
01633 int iVSize, const Vector3<Real>& rkV)
01634 {
01635
01636
01637
01638
01639
01640 int iSubRows = iRMax - iRMin + 1, iSubCols = iCMax - iCMin + 1;
01641 int iRow, iCol;
01642
01643 Real fSqrLen = rkV[0]*rkV[0];
01644 for (int i = 1; i < iVSize; i++)
01645 {
01646 fSqrLen += rkV[i]*rkV[i];
01647 }
01648
01649 Real fBeta = -((Real)2.0)/fSqrLen;
01650 for (iRow = 0; iRow < iSubRows; iRow++)
01651 {
01652 rkW[iRow] = (Real)0.0;
01653 for (iCol = 0; iCol < iSubCols; iCol++)
01654 {
01655 rkW[iRow] += rkMat[iRMin+iRow][iCMin+iCol]*rkV[iCol];
01656 }
01657 rkW[iRow] *= fBeta;
01658 }
01659
01660 for (iRow = 0; iRow < iSubRows; iRow++)
01661 {
01662 for (iCol = 0; iCol < iSubCols; iCol++)
01663 {
01664 rkMat[iRMin+iRow][iCMin+iCol] += rkW[iRow]*rkV[iCol];
01665 }
01666 }
01667 }
01668
01669 template <class Real>
01670 void PolynomialRoots<Real>::FrancisQRStep (GMatrix<Real>& rkH,
01671 GVector<Real>& rkW)
01672 {
01673
01674
01675
01676
01677
01678
01679
01680
01681 int iN = rkH.GetRows();
01682 Real fTrace = rkH[iN-2][iN-2] + rkH[iN-1][iN-1];
01683 Real fDet = rkH[iN-2][iN-2]*rkH[iN-1][iN-1] -
01684 rkH[iN-2][iN-1]*rkH[iN-1][iN-2];
01685 Vector3<Real> kU;
01686 kU[0] = rkH[0][0]*rkH[1][1]+rkH[0][1]*rkH[1][0]-fTrace*rkH[0][0]+fDet;
01687 kU[1] = rkH[1][0]*(rkH[0][0]+rkH[1][1]-fTrace);
01688 kU[2] = rkH[1][0]*rkH[2][1];
01689
01690
01691 Vector3<Real> kV;
01692 GetHouseholderVector(3,kU,kV);
01693 PremultiplyHouseholder(rkH,rkW,0,2,0,iN-1,3,kV);
01694 PostmultiplyHouseholder(rkH,rkW,0,iN-1,0,2,3,kV);
01695
01696 for (int i = 1; i <= iN-3; i++)
01697 {
01698
01699 kU[0] = rkH[i ][i-1];
01700 kU[1] = rkH[i+1][i-1];
01701 kU[2] = rkH[i+2][i-1];
01702 GetHouseholderVector(3,kU,kV);
01703
01704
01705
01706 PremultiplyHouseholder(rkH,rkW,i,i+2,i-1,iN-1,3,kV);
01707
01708
01709
01710 int iRMax = i+3;
01711 if (iRMax >= iN)
01712 {
01713 iRMax = iN-1;
01714 }
01715 PostmultiplyHouseholder(rkH,rkW,0,iRMax,i,i+2,3,kV);
01716 }
01717
01718
01719 kU[0] = rkH[iN-2][iN-3];
01720 kU[1] = rkH[iN-1][iN-3];
01721 GetHouseholderVector(2,kU,kV);
01722
01723
01724
01725 PremultiplyHouseholder(rkH,rkW,iN-2,iN-1,iN-3,iN-1,2,kV);
01726
01727 PostmultiplyHouseholder(rkH,rkW,0,iN-1,iN-2,iN-1,2,kV);
01728 }
01729
01730
01731
01732
01733
01734 template WM4_FOUNDATION_ITEM
01735 class PolynomialRoots<float>;
01736
01737 template WM4_FOUNDATION_ITEM
01738 class PolynomialRoots<double>;
01739
01740 }