00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "xrb_polynomial.hpp"
00012
00013 #include "xrb_math.hpp"
00014
00015 namespace Xrb
00016 {
00017
00018 Polynomial::Polynomial (Polynomial const &polynomial)
00019 {
00020 ASSERT1(polynomial.IsHighestCoefficientNonZero());
00021
00022 m.resize(polynomial.m.size());
00023 copy(polynomial.m.begin(), polynomial.m.end(), m.begin());
00024
00025 ASSERT1(IsHighestCoefficientNonZero());
00026 }
00027
00028 Float Polynomial::Evaluate (Float const x) const
00029 {
00030 Uint32 order = Order();
00031 Float retval = m[0];
00032 if (order > 0)
00033 {
00034 Uint32 basis_size = Math::HighestBitIndex(order) + 1;
00035 Float basis_vector[32];
00036 basis_vector[0] = x;
00037 for (Uint32 i = 1; i < basis_size; ++i)
00038 basis_vector[i] = basis_vector[i-1] * basis_vector[i-1];
00039
00040 for (Uint32 i = 1, size = m.size(); i < size; ++i)
00041 retval += m[i] * FastPow(i, basis_vector);
00042 }
00043 return retval;
00044 }
00045
00046 void Polynomial::Derive (Uint32 const order)
00047 {
00048 ASSERT1(IsHighestCoefficientNonZero());
00049
00050
00051 for (Uint32 d = 0; d < order; ++d)
00052 {
00053 if (Order() == 0)
00054 {
00055 m[0] = 0.0f;
00056 break;
00057 }
00058
00059 for (Uint32 i = 0, size = m.size()-1;
00060 i < size;
00061 ++i)
00062 {
00063 m[i] = static_cast<Float>(i+1) * m[i+1];
00064 }
00065 m.resize(m.size() - 1);
00066 }
00067
00068 ASSERT1(IsHighestCoefficientNonZero());
00069 }
00070
00071 void Polynomial::Integrate (Uint32 const order)
00072 {
00073 ASSERT1(IsHighestCoefficientNonZero());
00074
00075
00076 for (Uint32 d = 0; d < order; ++d)
00077 {
00078 m.resize(m.size() + 1);
00079 Uint32 high_order = Order();
00080 for (Uint32 i = high_order; i > 0; --i)
00081 {
00082 m[i] = m[i-1] / static_cast<Float>(i);
00083 }
00084 m[0] = 0.0f;
00085 }
00086
00087 Minimize();
00088 ASSERT1(IsHighestCoefficientNonZero());
00089 }
00090
00091 void Polynomial::Solve (SolutionSet *const solution_set, Float const tolerance) const
00092 {
00093 ASSERT1(tolerance > 0.0f);
00094 ASSERT1(solution_set != NULL);
00095 ASSERT1(solution_set->empty());
00096
00097 if (Order() == 0 && m[0] == 0.0f)
00098 {
00099
00100 }
00101 else if (Order() == 1)
00102 {
00103
00104 solution_set->insert(-m[0] / m[1]);
00105 }
00106 else if (Order() == 2)
00107 {
00108
00109 Float determinant = m[1] * m[1] - 4.0f * m[2] * m[0];
00110 if (determinant >= 0.0f)
00111 {
00112 Float base = -m[1];
00113 Float offset = sqrt(determinant);
00114 Float divisor = 2.0f * m[2];
00115 solution_set->insert((base - offset) / divisor);
00116 solution_set->insert((base + offset) / divisor);
00117 }
00118 }
00119 else
00120 {
00121
00122 Polynomial derivative(Derivative());
00123 std::set<Float> derivative_solution_set;
00124 derivative.Solve(&derivative_solution_set, tolerance);
00125
00126 Float solution;
00127
00128
00129 if (derivative_solution_set.size() == 0)
00130 {
00131 if (NewtonsMethod(&solution, derivative, 0.0f, tolerance))
00132 solution_set->insert(solution);
00133 }
00134 else
00135 {
00136
00137 if (NewtonsMethod(&solution, derivative, *derivative_solution_set.begin() - 1.0f, tolerance))
00138 solution_set->insert(solution);
00139
00140 for (std::set<Float>::iterator it_b = derivative_solution_set.begin(),
00141 it_a = it_b++,
00142 it_end = derivative_solution_set.end();
00143 it_b != it_end;
00144 ++it_a, ++it_b)
00145 {
00146 Float span = *it_b - *it_a;
00147 if (span == 0.0f)
00148 continue;
00149 if (NewtonsMethod(&solution, derivative, *it_b - 0.5f * span, tolerance))
00150 solution_set->insert(solution);
00151 }
00152
00153 if (NewtonsMethod(&solution, derivative, *derivative_solution_set.rbegin() + 1.0f, tolerance))
00154 solution_set->insert(solution);
00155 }
00156 }
00157 }
00158
00159 void Polynomial::operator = (Polynomial const &operand)
00160 {
00161 ASSERT1(IsHighestCoefficientNonZero());
00162 ASSERT1(operand.IsHighestCoefficientNonZero());
00163
00164 m.resize(operand.m.size());
00165 copy(operand.m.begin(), operand.m.end(), m.begin());
00166
00167 ASSERT1(IsHighestCoefficientNonZero());
00168 }
00169
00170 Polynomial Polynomial::operator * (Polynomial const &operand) const
00171 {
00172 ASSERT1(IsHighestCoefficientNonZero());
00173 ASSERT1(operand.IsHighestCoefficientNonZero());
00174
00175 Polynomial retval;
00176 if (Order() == 0 && m[0] == 0.0f)
00177 return retval;
00178
00179 Uint32 left_operand_order = Order();
00180 Uint32 right_operand_order = operand.Order();
00181 Uint32 order = left_operand_order + right_operand_order;
00182 retval.m.resize(order + 1);
00183
00184 for (Uint32 i = 0; i <= order; ++i)
00185 {
00186 retval.m[i] = 0.0f;
00187
00188 Uint32 right_operand_term = Min(i, right_operand_order);
00189 Uint32 left_operand_term = i - right_operand_term;
00190 ASSERT1(left_operand_term <= left_operand_order);
00191
00192 for (;
00193 left_operand_term <= left_operand_order &&
00194 right_operand_term <= right_operand_order;
00195 ++left_operand_term, --right_operand_term)
00196 {
00197 retval.m[i] += m[left_operand_term] * operand.m[right_operand_term];
00198 }
00199 }
00200
00201 ASSERT1(retval.IsHighestCoefficientNonZero());
00202 return retval;
00203 }
00204
00205 void Polynomial::operator += (Polynomial const &operand)
00206 {
00207 ASSERT1(IsHighestCoefficientNonZero());
00208 ASSERT1(operand.IsHighestCoefficientNonZero());
00209
00210 Uint32 size = Max(m.size(), operand.m.size());
00211 m.resize(size);
00212 for (Uint32 i = 0; i < size; ++i)
00213 m[i] += operand.Get(i);
00214
00215 Minimize();
00216 ASSERT1(IsHighestCoefficientNonZero());
00217 }
00218
00219 void Polynomial::operator -= (Polynomial const &operand)
00220 {
00221 ASSERT1(IsHighestCoefficientNonZero());
00222 ASSERT1(operand.IsHighestCoefficientNonZero());
00223
00224 Uint32 size = Max(m.size(), operand.m.size());
00225 m.resize(size);
00226 for (Uint32 i = 0; i < size; ++i)
00227 m[i] -= operand.Get(i);
00228
00229 Minimize();
00230 ASSERT1(IsHighestCoefficientNonZero());
00231 }
00232
00233 void Polynomial::operator *= (Polynomial const &operand)
00234 {
00235 ASSERT1(IsHighestCoefficientNonZero());
00236 ASSERT1(operand.IsHighestCoefficientNonZero());
00237
00238 Polynomial result;
00239 if (Order() > 0 || m[0] != 0.0f)
00240 {
00241 Uint32 left_operand_order = Order();
00242 Uint32 right_operand_order = operand.Order();
00243 Uint32 order = left_operand_order + right_operand_order;
00244 result.m.resize(order + 1);
00245
00246 for (Uint32 i = 0; i <= order; ++i)
00247 {
00248 result.m[i] = 0.0f;
00249
00250 Uint32 right_operand_term = Min(i, right_operand_order);
00251 Uint32 left_operand_term = i - right_operand_term;
00252 ASSERT1(left_operand_term <= left_operand_order);
00253
00254 for (;
00255 left_operand_term <= left_operand_order &&
00256 right_operand_term <= right_operand_order;
00257 ++left_operand_term, --right_operand_term)
00258 {
00259 result.m[i] += m[left_operand_term] * operand.m[right_operand_term];
00260 }
00261 }
00262 }
00263
00264 ASSERT1(result.IsHighestCoefficientNonZero());
00265 operator=(result);
00266 }
00267
00268 bool Polynomial::NewtonsMethod (
00269 Float *const solution,
00270 Polynomial const &derivative,
00271 Float const x,
00272 Float const tolerance) const
00273 {
00274 ASSERT1(solution != NULL);
00275
00276 Float iterator[2];
00277 iterator[0] = x;
00278
00279 Float epsilon;
00280 Uint32 i = 0;
00281 Uint32 iteration_count = 0;
00282 do
00283 {
00284 i = 1 - i;
00285 iterator[i] = NewtonsMethodIteration(derivative, iterator[1 - i]);
00286 if (iterator[i] == Math::Nan())
00287 return false;
00288
00289 ++iteration_count;
00290 epsilon = Abs(iterator[0] - iterator[1]);
00291 }
00292 while (epsilon > tolerance && iteration_count < 50);
00293
00294 *solution = iterator[i];
00295 return epsilon <= tolerance;
00296 }
00297
00298 Float Polynomial::NewtonsMethodIteration (
00299 Polynomial const &derivative,
00300 Float const x) const
00301 {
00302 Float f_prime_x = derivative.Evaluate(x);
00303 if (f_prime_x != 0.0f)
00304 return x - Evaluate(x) / f_prime_x;
00305 else
00306 return Math::Nan();
00307 }
00308
00309 void Polynomial::Minimize () const
00310 {
00311 Uint32 highest_nonzero_coefficient = 0;
00312 for (Uint32 i = m.size()-1; i > 0; --i)
00313 {
00314 if (m[i] != 0.0f)
00315 {
00316 highest_nonzero_coefficient = i;
00317 break;
00318 }
00319 }
00320 m.resize(highest_nonzero_coefficient + 1);
00321 }
00322
00323 std::ostream &operator << (std::ostream &stream, Polynomial const &polynomial)
00324 {
00325 Uint32 order = polynomial.Order();
00326 for (Uint32 i = 0; i <= order; ++i)
00327 {
00328 if (polynomial[i] != 0.0f)
00329 {
00330 stream << polynomial[i] << "*x^" << i;
00331 if (i < order)
00332 stream << " + ";
00333 }
00334 }
00335
00336 return stream;
00337 }
00338
00339 }