2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../precompiled.h"
32 const float EPSILON = 1e-6f;
39 int idPolynomial::Laguer( const idComplex *coef, const int degree, idComplex &x ) const {
40 const int MT = 10, MAX_ITERATIONS = MT * 8;
41 static const float frac[] = { 0.0f, 0.5f, 0.25f, 0.75f, 0.13f, 0.38f, 0.62f, 0.88f, 1.0f };
43 float abx, abp, abm, err;
44 idComplex dx, cx, b, d, f, g, s, gps, gms, g2;
46 for ( i = 1; i <= MAX_ITERATIONS; i++ ) {
52 for ( j = degree - 1; j >= 0; j-- ) {
56 err = b.Abs() + abx * err;
58 if ( b.Abs() < err * EPSILON ) {
63 s = ( ( degree - 1 ) * ( degree * ( g2 - 2.0f * f / b ) - g2 ) ).Sqrt();
71 if ( Max( abp, abm ) > 0.0f ) {
74 dx = idMath::Exp( idMath::Log( 1.0f + abx ) ) * idComplex( idMath::Cos( i ), idMath::Sin( i ) );
91 idPolynomial::GetRoots
94 int idPolynomial::GetRoots( idComplex *roots ) const {
96 idComplex x, b, c, *coef;
98 coef = (idComplex *) _alloca16( ( degree + 1 ) * sizeof( idComplex ) );
99 for ( i = 0; i <= degree; i++ ) {
100 coef[i].Set( coefficient[i], 0.0f );
103 for ( i = degree - 1; i >= 0; i-- ) {
105 Laguer( coef, i + 1, x );
106 if ( idMath::Fabs( x.i ) < 2.0f * EPSILON * idMath::Fabs( x.r ) ) {
111 for ( j = i; j >= 0; j-- ) {
118 for ( i = 0; i <= degree; i++ ) {
119 coef[i].Set( coefficient[i], 0.0f );
121 for ( i = 0; i < degree; i++ ) {
122 Laguer( coef, degree, roots[i] );
125 for ( i = 1; i < degree; i++ ) {
127 for ( j = i - 1; j >= 0; j-- ) {
128 if ( roots[j].r <= x.r ) {
131 roots[j+1] = roots[j];
141 idPolynomial::GetRoots
144 int idPolynomial::GetRoots( float *roots ) const {
146 idComplex *complexRoots;
150 case 1: return GetRoots1( coefficient[1], coefficient[0], roots );
151 case 2: return GetRoots2( coefficient[2], coefficient[1], coefficient[0], roots );
152 case 3: return GetRoots3( coefficient[3], coefficient[2], coefficient[1], coefficient[0], roots );
153 case 4: return GetRoots4( coefficient[4], coefficient[3], coefficient[2], coefficient[1], coefficient[0], roots );
156 // The Abel-Ruffini theorem states that there is no general solution
157 // in radicals to polynomial equations of degree five or higher.
158 // A polynomial equation can be solved by radicals if and only if
159 // its Galois group is a solvable group.
161 complexRoots = (idComplex *) _alloca16( degree * sizeof( idComplex ) );
163 GetRoots( complexRoots );
165 for ( num = i = 0; i < degree; i++ ) {
166 if ( complexRoots[i].i == 0.0f ) {
167 roots[i] = complexRoots[i].r;
176 idPolynomial::ToString
179 const char *idPolynomial::ToString( int precision ) const {
180 return idStr::FloatArrayToString( ToFloatPtr(), GetDimension(), precision );
188 void idPolynomial::Test( void ) {
190 float roots[4], value;
191 idComplex complexRoots[4], complexValue;
194 p = idPolynomial( -5.0f, 4.0f );
195 num = p.GetRoots( roots );
196 for ( i = 0; i < num; i++ ) {
197 value = p.GetValue( roots[i] );
198 assert( idMath::Fabs( value ) < 1e-4f );
201 p = idPolynomial( -5.0f, 4.0f, 3.0f );
202 num = p.GetRoots( roots );
203 for ( i = 0; i < num; i++ ) {
204 value = p.GetValue( roots[i] );
205 assert( idMath::Fabs( value ) < 1e-4f );
208 p = idPolynomial( 1.0f, 4.0f, 3.0f, -2.0f );
209 num = p.GetRoots( roots );
210 for ( i = 0; i < num; i++ ) {
211 value = p.GetValue( roots[i] );
212 assert( idMath::Fabs( value ) < 1e-4f );
215 p = idPolynomial( 5.0f, 4.0f, 3.0f, -2.0f );
216 num = p.GetRoots( roots );
217 for ( i = 0; i < num; i++ ) {
218 value = p.GetValue( roots[i] );
219 assert( idMath::Fabs( value ) < 1e-4f );
222 p = idPolynomial( -5.0f, 4.0f, 3.0f, 2.0f, 1.0f );
223 num = p.GetRoots( roots );
224 for ( i = 0; i < num; i++ ) {
225 value = p.GetValue( roots[i] );
226 assert( idMath::Fabs( value ) < 1e-4f );
229 p = idPolynomial( 1.0f, 4.0f, 3.0f, -2.0f );
230 num = p.GetRoots( complexRoots );
231 for ( i = 0; i < num; i++ ) {
232 complexValue = p.GetValue( complexRoots[i] );
233 assert( idMath::Fabs( complexValue.r ) < 1e-4f && idMath::Fabs( complexValue.i ) < 1e-4f );
236 p = idPolynomial( 5.0f, 4.0f, 3.0f, -2.0f );
237 num = p.GetRoots( complexRoots );
238 for ( i = 0; i < num; i++ ) {
239 complexValue = p.GetValue( complexRoots[i] );
240 assert( idMath::Fabs( complexValue.r ) < 1e-4f && idMath::Fabs( complexValue.i ) < 1e-4f );