home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 March / Gamestar_82_2006-03_dvd.iso / DVDStar / Editace / quake4_sdkv10.exe / source / idlib / math / Polynomial.cpp < prev    next >
C/C++ Source or Header  |  2005-11-14  |  5KB  |  216 lines

  1.  
  2. #include "../precompiled.h"
  3. #pragma hdrstop
  4.  
  5. const float EPSILON        = 1e-6f;
  6.  
  7. /*
  8. =============
  9. idPolynomial::Laguer
  10. =============
  11. */
  12. int idPolynomial::Laguer( const idComplex *coef, const int degree, idComplex &x ) const {
  13.     const int MT = 10, MAX_ITERATIONS = MT * 8;
  14.     static const float frac[] = { 0.0f, 0.5f, 0.25f, 0.75f, 0.13f, 0.38f, 0.62f, 0.88f, 1.0f };
  15.     int i, j;
  16.     float abx, abp, abm, err;
  17.     idComplex dx, cx, b, d, f, g, s, gps, gms, g2;
  18.  
  19.     for ( i = 1; i <= MAX_ITERATIONS; i++ ) {
  20.         b = coef[degree];
  21.         err = b.Abs();
  22.         d.Zero();
  23.         f.Zero();
  24.         abx = x.Abs();
  25.         for ( j = degree - 1; j >= 0; j-- ) {
  26.             f = x * f + d;
  27.             d = x * d + b;
  28.             b = x * b + coef[j];
  29.             err = b.Abs() + abx * err;
  30.         }
  31.         if ( b.Abs() < err * EPSILON ) {
  32.             return i;
  33.         }
  34.         g = d / b;
  35.         g2 = g * g;
  36.         s = ( ( degree - 1 ) * ( degree * ( g2 - 2.0f * f / b ) - g2 ) ).Sqrt();
  37.         gps = g + s;
  38.         gms = g - s;
  39.         abp = gps.Abs();
  40.         abm = gms.Abs();
  41.         if ( abp < abm ) {
  42.             gps = gms;
  43.         }
  44.         if ( Max( abp, abm ) > 0.0f ) {
  45.             dx = degree / gps;
  46.         } else {
  47.             dx = idMath::Exp( idMath::Log( 1.0f + abx ) ) * idComplex( idMath::Cos( i ), idMath::Sin( i ) );
  48.         }
  49.         cx = x - dx;
  50.         if ( x == cx ) {
  51.             return i;
  52.         }
  53.         if ( i % MT == 0 ) {
  54.             x = cx;
  55.         } else {
  56.             x -= frac[i/MT] * dx;
  57.         }
  58.     }
  59.     return i;
  60. }
  61.  
  62. /*
  63. =============
  64. idPolynomial::GetRoots
  65. =============
  66. */
  67. int idPolynomial::GetRoots( idComplex *roots ) const {
  68.     int i, j;
  69.     idComplex x, b, c, *coef;
  70.  
  71.     coef = (idComplex *) _alloca16( ( degree + 1 ) * sizeof( idComplex ) );
  72.     for ( i = 0; i <= degree; i++ ) {
  73.         coef[i].Set( coefficient[i], 0.0f );
  74.     }
  75.  
  76.     for ( i = degree - 1; i >= 0; i-- ) {
  77.         x.Zero();
  78.         Laguer( coef, i + 1, x );
  79.         if ( idMath::Fabs( x.i ) < 2.0f * EPSILON * idMath::Fabs( x.r ) ) {
  80.             x.i = 0.0f;
  81.         }
  82.         roots[i] = x;
  83.         b = coef[i+1];
  84.         for ( j = i; j >= 0; j-- ) {
  85.             c = coef[j];
  86.             coef[j] = b;
  87.             b = x * b + c;
  88.         }
  89.     }
  90.  
  91.     for ( i = 0; i <= degree; i++ ) {
  92.         coef[i].Set( coefficient[i], 0.0f );
  93.     }
  94.     for ( i = 0; i < degree; i++ ) {
  95.         Laguer( coef, degree, roots[i] );
  96.     }
  97.  
  98.     for ( i = 1; i < degree; i++ ) {
  99.         x = roots[i];
  100.         for ( j = i - 1; j >= 0; j-- ) {
  101.             if ( roots[j].r <= x.r ) {
  102.                 break;
  103.             }
  104.             roots[j+1] = roots[j];
  105.         }
  106.         roots[j+1] = x;
  107.     }
  108.  
  109.     return degree;
  110. }
  111.  
  112. /*
  113. =============
  114. idPolynomial::GetRoots
  115. =============
  116. */
  117. int idPolynomial::GetRoots( float *roots ) const {
  118.     int i, num;
  119.     idComplex *complexRoots;
  120.  
  121.     switch( degree ) {
  122.         case 0: return 0;
  123.         case 1: return GetRoots1( coefficient[1], coefficient[0], roots );
  124.         case 2: return GetRoots2( coefficient[2], coefficient[1], coefficient[0], roots );
  125.         case 3: return GetRoots3( coefficient[3], coefficient[2], coefficient[1], coefficient[0], roots );
  126.         case 4: return GetRoots4( coefficient[4], coefficient[3], coefficient[2], coefficient[1], coefficient[0], roots );
  127.     }
  128.  
  129.     // The Abel-Ruffini theorem states that there is no general solution
  130.     // in radicals to polynomial equations of degree five or higher.
  131.     // A polynomial equation can be solved by radicals if and only if
  132.     // its Galois group is a solvable group.
  133.  
  134.     complexRoots = (idComplex *) _alloca16( degree * sizeof( idComplex ) );
  135.  
  136.     GetRoots( complexRoots );
  137.  
  138.     for ( num = i = 0; i < degree; i++ ) {
  139.         if ( complexRoots[i].i == 0.0f ) {
  140.             roots[i] = complexRoots[i].r;
  141.             num++;
  142.         }
  143.     }
  144.     return num;
  145. }
  146.  
  147. /*
  148. =============
  149. idPolynomial::ToString
  150. =============
  151. */
  152. const char *idPolynomial::ToString( int precision ) const {
  153.     return idStr::FloatArrayToString( ToFloatPtr(), GetDimension(), precision );
  154. }
  155.  
  156. /*
  157. =============
  158. idPolynomial::Test
  159. =============
  160. */
  161. void idPolynomial::Test( void ) {
  162.     int i, num;
  163.     float roots[4], value;
  164.     idComplex complexRoots[4], complexValue;
  165.     idPolynomial p;
  166.  
  167.     p = idPolynomial( -5.0f, 4.0f );
  168.     num = p.GetRoots( roots );
  169.     for ( i = 0; i < num; i++ ) {
  170.         value = p.GetValue( roots[i] );
  171.         assert( idMath::Fabs( value ) < 1e-4f );
  172.     }
  173.  
  174.     p = idPolynomial( -5.0f, 4.0f, 3.0f );
  175.     num = p.GetRoots( roots );
  176.     for ( i = 0; i < num; i++ ) {
  177.         value = p.GetValue( roots[i] );
  178.         assert( idMath::Fabs( value ) < 1e-4f );
  179.     }
  180.  
  181.     p = idPolynomial( 1.0f, 4.0f, 3.0f, -2.0f );
  182.     num = p.GetRoots( roots );
  183.     for ( i = 0; i < num; i++ ) {
  184.         value = p.GetValue( roots[i] );
  185.         assert( idMath::Fabs( value ) < 1e-4f );
  186.     }
  187.  
  188.     p = idPolynomial( 5.0f, 4.0f, 3.0f, -2.0f );
  189.     num = p.GetRoots( roots );
  190.     for ( i = 0; i < num; i++ ) {
  191.         value = p.GetValue( roots[i] );
  192.         assert( idMath::Fabs( value ) < 1e-4f );
  193.     }
  194.  
  195.     p = idPolynomial( -5.0f, 4.0f, 3.0f, 2.0f, 1.0f );
  196.     num = p.GetRoots( roots );
  197.     for ( i = 0; i < num; i++ ) {
  198.         value = p.GetValue( roots[i] );
  199.         assert( idMath::Fabs( value ) < 1e-4f );
  200.     }
  201.  
  202.     p = idPolynomial( 1.0f, 4.0f, 3.0f, -2.0f );
  203.     num = p.GetRoots( complexRoots );
  204.     for ( i = 0; i < num; i++ ) {
  205.         complexValue = p.GetValue( complexRoots[i] );
  206.         assert( idMath::Fabs( complexValue.r ) < 1e-4f && idMath::Fabs( complexValue.i ) < 1e-4f );
  207.     }
  208.  
  209.     p = idPolynomial( 5.0f, 4.0f, 3.0f, -2.0f );
  210.     num = p.GetRoots( complexRoots );
  211.     for ( i = 0; i < num; i++ ) {
  212.         complexValue = p.GetValue( complexRoots[i] );
  213.         assert( idMath::Fabs( complexValue.r ) < 1e-4f && idMath::Fabs( complexValue.i ) < 1e-4f );
  214.     }
  215. }
  216.