• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

kig

  • sources
  • kde-4.12
  • kdeedu
  • kig
  • misc
kignumerics.cpp
Go to the documentation of this file.
1 
21 #include "kignumerics.h"
22 #include "common.h"
23 
24 using std::fabs;
25 
26 /*
27  * compute one of the roots of a cubic polynomial
28  * if xmin << 0 or xmax >> 0 then autocompute a bound for all the
29  * roots
30  */
31 
32 double calcCubicRoot ( double xmin, double xmax, double a,
33  double b, double c, double d, int root, bool& valid, int& numroots )
34 {
35  // renormalize: positive a and infinity norm = 1
36 
37  double infnorm = fabs(a);
38  if ( infnorm < fabs(b) ) infnorm = fabs(b);
39  if ( infnorm < fabs(c) ) infnorm = fabs(c);
40  if ( infnorm < fabs(d) ) infnorm = fabs(d);
41  if ( a < 0 ) infnorm = -infnorm;
42  a /= infnorm;
43  b /= infnorm;
44  c /= infnorm;
45  d /= infnorm;
46 
47  const double small = 1e-7;
48  valid = false;
49  if ( fabs(a) < small )
50  {
51  if ( fabs(b) < small )
52  {
53  if ( fabs(c) < small )
54  { // degree = 0;
55  numroots = 0;
56  return 0.0;
57  }
58  // degree = 1
59  double rootval = -d/c;
60  numroots = 1;
61  if ( rootval < xmin || xmax < rootval ) numroots--;
62  if ( root > numroots ) return 0.0;
63  valid = true;
64  return rootval;
65  }
66  // degree = 2
67  if ( b < 0 ) { b = -b; c = -c; d = -d; }
68  double discrim = c*c - 4*b*d;
69  numroots = 2;
70  if ( discrim < 0 )
71  {
72  numroots = 0;
73  return 0.0;
74  }
75  discrim = std::sqrt(discrim)/(2*fabs(b));
76  double rootmiddle = -c/(2*b);
77  if ( rootmiddle - discrim < xmin ) numroots--;
78  if ( rootmiddle + discrim > xmax ) numroots--;
79  if ( rootmiddle + discrim < xmin ) numroots--;
80  if ( rootmiddle - discrim > xmax ) numroots--;
81  if ( root > numroots ) return 0.0;
82  valid = true;
83  if ( root == 2 || rootmiddle - discrim < xmin ) return rootmiddle + discrim;
84  return rootmiddle - discrim;
85  }
86 
87  if ( xmin < -1e8 || xmax > 1e8 )
88  {
89 
90  // compute a bound for all the real roots:
91 
92  xmax = fabs(d/a);
93  if ( fabs(c/a) + 1 > xmax ) xmax = fabs(c/a) + 1;
94  if ( fabs(b/a) + 1 > xmax ) xmax = fabs(b/a) + 1;
95  xmin = -xmax;
96  }
97 
98  // computing the coefficients of the Sturm sequence
99  double p1a = 2*b*b - 6*a*c;
100  double p1b = b*c - 9*a*d;
101  double p0a = c*p1a*p1a + p1b*(3*a*p1b - 2*b*p1a);
102 
103  int varbottom = calcCubicVariations (xmin, a, b, c, d, p1a, p1b, p0a);
104  int vartop = calcCubicVariations (xmax, a, b, c, d, p1a, p1b, p0a);
105  numroots = vartop - varbottom;
106  valid = false;
107  if (root <= varbottom || root > vartop ) return 0.0;
108 
109  valid = true;
110 
111  // now use bisection to separate the required root
112  double dx = (xmax - xmin)/2;
113  while ( vartop - varbottom > 1 )
114  {
115  if ( fabs( dx ) < 1e-8 ) return (xmin + xmax)/2;
116  double xmiddle = xmin + dx;
117  int varmiddle = calcCubicVariations (xmiddle, a, b, c, d, p1a, p1b, p0a);
118  if ( varmiddle < root ) // I am below
119  {
120  xmin = xmiddle;
121  varbottom = varmiddle;
122  } else {
123  xmax = xmiddle;
124  vartop = varmiddle;
125  }
126  dx /= 2;
127  }
128 
129  /*
130  * now [xmin, xmax] enclose a single root, try using Newton
131  */
132  if ( vartop - varbottom == 1 )
133  {
134  double fval1 = a; // double check...
135  double fval2 = a;
136  fval1 = b + xmin*fval1;
137  fval2 = b + xmax*fval2;
138  fval1 = c + xmin*fval1;
139  fval2 = c + xmax*fval2;
140  fval1 = d + xmin*fval1;
141  fval2 = d + xmax*fval2;
142  assert ( fval1 * fval2 <= 0 );
143  return calcCubicRootwithNewton ( xmin, xmax, a, b, c, d, 1e-8 );
144  }
145  else // probably a double root here!
146  return ( xmin + xmax )/2;
147 }
148 
149 /*
150  * computation of the number of sign changes in the sturm sequence for
151  * a third degree polynomial at x. This number counts the number of
152  * roots of the polynomial on the left of point x.
153  *
154  * a, b, c, d: coefficients of the third degree polynomial (a*x^3 + ...)
155  *
156  * the second degree polynomial in the sturm sequence is just minus the
157  * derivative, so we don't need to compute it.
158  *
159  * p1a*x + p1b: is the third (first degree) polynomial in the sturm sequence.
160  *
161  * p0a: is the (constant) fourth polynomial of the sturm sequence.
162  */
163 
164 int calcCubicVariations (double x, double a, double b, double c,
165  double d, double p1a, double p1b, double p0a)
166 {
167  double fval, fpval;
168  fval = fpval = a;
169  fval = b + x*fval;
170  fpval = fval + x*fpval;
171  fval = c + x*fval;
172  fpval = fval + x*fpval;
173  fval = d + x*fval;
174 
175  double f1val = p1a*x + p1b;
176 
177  bool f3pos = fval >= 0;
178  bool f2pos = fpval <= 0;
179  bool f1pos = f1val >= 0;
180  bool f0pos = p0a >= 0;
181 
182  int variations = 0;
183  if ( f3pos != f2pos ) variations++;
184  if ( f2pos != f1pos ) variations++;
185  if ( f1pos != f0pos ) variations++;
186  return variations;
187 }
188 
189 /*
190  * use newton to solve a third degree equation with already isolated
191  * root
192  */
193 
194 inline void calcCubicDerivatives ( double x, double a, double b, double c,
195  double d, double& fval, double& fpval, double& fppval )
196 {
197  fval = fpval = fppval = a;
198  fval = b + x*fval;
199  fpval = fval + x*fpval;
200  fppval = fpval + x*fppval; // this is really half the second derivative
201  fval = c + x*fval;
202  fpval = fval + x*fpval;
203  fval = d + x*fval;
204 }
205 
206 double calcCubicRootwithNewton ( double xmin, double xmax, double a,
207  double b, double c, double d, double tol )
208 {
209  double fval, fpval, fppval;
210 
211  double fval1, fval2, fpval1, fpval2, fppval1, fppval2;
212  calcCubicDerivatives ( xmin, a, b, c, d, fval1, fpval1, fppval1 );
213  calcCubicDerivatives ( xmax, a, b, c, d, fval2, fpval2, fppval2 );
214  assert ( fval1 * fval2 <= 0 );
215 
216  assert ( xmax > xmin );
217  while ( xmax - xmin > tol )
218  {
219  // compute the values of function, derivative and second derivative:
220  assert ( fval1 * fval2 <= 0 );
221  if ( fppval1 * fppval2 < 0 || fpval1 * fpval2 < 0 )
222  {
223  double xmiddle = (xmin + xmax)/2;
224  calcCubicDerivatives ( xmiddle, a, b, c, d, fval, fpval, fppval );
225  if ( fval1*fval <= 0 )
226  {
227  xmax = xmiddle;
228  fval2 = fval;
229  fpval2 = fpval;
230  fppval2 = fppval;
231  } else {
232  xmin = xmiddle;
233  fval1 = fval;
234  fpval1 = fpval;
235  fppval1 = fppval;
236  }
237  } else
238  {
239  // now we have first and second derivative of constant sign, we
240  // can start with Newton from the Fourier point.
241  double x = xmin;
242  if ( fval2*fppval2 > 0 ) x = xmax;
243  double p = 1.0;
244  int iterations = 0;
245  while ( fabs(p) > tol && iterations++ < 100 )
246  {
247  calcCubicDerivatives ( x, a, b, c, d, fval, fpval, fppval );
248  p = fval/fpval;
249  x -= p;
250  }
251  if( iterations >= 100 )
252  {
253  // Newton scheme did not converge..
254  // we should end up with an invalid Coordinate
255  return double_inf;
256  };
257  return x;
258  }
259  }
260 
261  // we cannot apply Newton, (perhaps we are at an inflection point)
262 
263  return (xmin + xmax)/2;
264 }
265 
266 /*
267  * This function computes the LU factorization of a mxn matrix, with
268  * m typically less than n. This is done with complete pivoting; the
269  * exchanges in columns are recorded in the integer vector "exchange"
270  */
271 bool GaussianElimination( double *matrix[], int numrows,
272  int numcols, int exchange[] )
273 {
274  // start gaussian elimination
275  for ( int k = 0; k < numrows; ++k )
276  {
277  // ricerca elemento di modulo massimo
278  double maxval = -double_inf;
279  int imax = k;
280  int jmax = k;
281  for( int i = k; i < numrows; ++i )
282  {
283  for( int j = k; j < numcols; ++j )
284  {
285  if (fabs(matrix[i][j]) > maxval)
286  {
287  maxval = fabs(matrix[i][j]);
288  imax = i;
289  jmax = j;
290  }
291  }
292  }
293 
294  // row exchange
295  if ( imax != k )
296  for( int j = k; j < numcols; ++j )
297  {
298  double t = matrix[k][j];
299  matrix[k][j] = matrix[imax][j];
300  matrix[imax][j] = t;
301  }
302 
303  // column exchange
304  if ( jmax != k )
305  for( int i = 0; i < numrows; ++i )
306  {
307  double t = matrix[i][k];
308  matrix[i][k] = matrix[i][jmax];
309  matrix[i][jmax] = t;
310  }
311 
312  // remember this column exchange at step k
313  exchange[k] = jmax;
314 
315  // we can't usefully eliminate a singular matrix..
316  if ( maxval == 0. ) return false;
317 
318  // ciclo sulle righe
319  for( int i = k+1; i < numrows; ++i)
320  {
321  double mik = matrix[i][k]/matrix[k][k];
322  matrix[i][k] = mik; //ricorda il moltiplicatore... (not necessary)
323  // ciclo sulle colonne
324  for( int j = k+1; j < numcols; ++j )
325  {
326  matrix[i][j] -= mik*matrix[k][j];
327  }
328  }
329  }
330  return true;
331 }
332 
333 /*
334  * solve an undetermined homogeneous triangular system. the matrix is nonzero
335  * on its diagonal. The last unknown(s) are chosen to be 1. The
336  * vector "exchange" contains exchanges to be performed on the
337  * final solution components.
338  */
339 
340 void BackwardSubstitution( double *matrix[], int numrows, int numcols,
341  int exchange[], double solution[] )
342 {
343  // the system is homogeneous and underdetermined, the last unknown(s)
344  // are chosen = 1
345  for ( int j = numrows; j < numcols; ++j )
346  {
347  solution[j] = 1.0; // other choices are possible here
348  };
349 
350  for( int k = numrows - 1; k >= 0; --k )
351  {
352  // backward substitution
353  solution[k] = 0.0;
354  for ( int j = k+1; j < numcols; ++j)
355  {
356  solution[k] -= matrix[k][j]*solution[j];
357  }
358  solution[k] /= matrix[k][k];
359  }
360 
361  // ultima fase: riordinamento incognite
362 
363  for( int k = numrows - 1; k >= 0; --k )
364  {
365  int jmax = exchange[k];
366  double t = solution[k];
367  solution[k] = solution[jmax];
368  solution[jmax] = t;
369  }
370 }
371 
372 bool Invert3by3matrix ( const double m[3][3], double inv[3][3] )
373 {
374  double det = m[0][0]*(m[1][1]*m[2][2] - m[1][2]*m[2][1]) -
375  m[0][1]*(m[1][0]*m[2][2] - m[1][2]*m[2][0]) +
376  m[0][2]*(m[1][0]*m[2][1] - m[1][1]*m[2][0]);
377  if (det == 0) return false;
378 
379  for (int i=0; i < 3; i++)
380  {
381  for (int j=0; j < 3; j++)
382  {
383  int i1 = (i+1)%3;
384  int i2 = (i+2)%3;
385  int j1 = (j+1)%3;
386  int j2 = (j+2)%3;
387  inv[j][i] = (m[i1][j1]*m[i2][j2] - m[i1][j2]*m[i2][j1])/det;
388  }
389  }
390  return true;
391 }
calcCubicRoot
double calcCubicRoot(double xmin, double xmax, double a, double b, double c, double d, int root, bool &valid, int &numroots)
This file is part of Kig, a KDE program for Interactive Geometry...
Definition: kignumerics.cpp:32
calcCubicDerivatives
void calcCubicDerivatives(double x, double a, double b, double c, double d, double &fval, double &fpval, double &fppval)
Definition: kignumerics.cpp:194
Invert3by3matrix
bool Invert3by3matrix(const double m[3][3], double inv[3][3])
Definition: kignumerics.cpp:372
GaussianElimination
bool GaussianElimination(double *matrix[], int numrows, int numcols, int exchange[])
Gaussian Elimination.
Definition: kignumerics.cpp:271
calcCubicRootwithNewton
double calcCubicRootwithNewton(double xmin, double xmax, double a, double b, double c, double d, double tol)
Definition: kignumerics.cpp:206
common.h
double_inf
const double double_inf
Definition: common.cpp:509
BackwardSubstitution
void BackwardSubstitution(double *matrix[], int numrows, int numcols, int exchange[], double solution[])
Definition: kignumerics.cpp:340
kignumerics.h
calcCubicVariations
int calcCubicVariations(double x, double a, double b, double c, double d, double p1a, double p1b, double p0a)
Definition: kignumerics.cpp:164
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:35:39 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kig

Skip menu "kig"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal