UVES Pipeline Reference Manual  5.3.8
irplib_polynomial-test.c
1 /* $Id: irplib_polynomial-test.c,v 1.37 2013-01-29 08:43:33 jtaylor Exp $
2  *
3  * This file is part of the ESO Common Pipeline Library
4  * Copyright (C) 2001-2004 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jtaylor $
23  * $Date: 2013-01-29 08:43:33 $
24  * $Revision: 1.37 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 /*-----------------------------------------------------------------------------
29  Includes
30  -----------------------------------------------------------------------------*/
31 
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include <irplib_polynomial.h>
37 #include <math.h>
38 #include <float.h>
39 #include <stdint.h>
40 
41 /*-----------------------------------------------------------------------------
42  Defines
43  -----------------------------------------------------------------------------*/
44 
45 #define MAXDEGREE 6
46 
47 #define irplib_polynomial_test_root_all(A, B, C, D, E) \
48  irplib_polynomial_test_root_all_macro(A, B, C, D, E, __LINE__)
49 
50 /*-----------------------------------------------------------------------------
51  Static functions
52  -----------------------------------------------------------------------------*/
53 
54 static cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial *,
55  const cpl_vector *,
56  cpl_size);
57 static void irplib_polynomial_solve_1d_all_test(void);
58 
59 static void irplib_polynomial_test_root_all_macro(const cpl_vector *, cpl_size,
60  double, double, double,
61  unsigned);
62 
63 /*-----------------------------------------------------------------------------
64  Main
65  -----------------------------------------------------------------------------*/
66 int main(void)
67 {
68  /* Initialize CPL */
69  cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
70 
71  irplib_polynomial_solve_1d_all_test();
72 
73  return cpl_test_end(0);
74 }
75 
76 
77 /*----------------------------------------------------------------------------*/
84 /*----------------------------------------------------------------------------*/
85 static void irplib_polynomial_solve_1d_all_test(void)
86 {
87 
88  cpl_polynomial * p2d = cpl_polynomial_new(2);
89  cpl_polynomial * p1d = cpl_polynomial_new(1);
90  cpl_vector * xtrue = cpl_vector_new(2);
91  const cpl_size maxdegree = 4; /* Largest robustly handled degree */
92  cpl_size nreal = 0;
93  cpl_size i;
94 
95  cpl_test_eq(irplib_polynomial_solve_1d_all(NULL, xtrue, &nreal),
96  CPL_ERROR_NULL_INPUT);
97  cpl_test_error(CPL_ERROR_NULL_INPUT);
98 
99  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, NULL, &nreal),
100  CPL_ERROR_NULL_INPUT);
101  cpl_test_error(CPL_ERROR_NULL_INPUT);
102 
103  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, NULL),
104  CPL_ERROR_NULL_INPUT);
105  cpl_test_error(CPL_ERROR_NULL_INPUT);
106 
107  cpl_test_eq(irplib_polynomial_solve_1d_all(p2d, xtrue, &nreal),
108  CPL_ERROR_INVALID_TYPE);
109  cpl_test_error(CPL_ERROR_INVALID_TYPE);
110 
111  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
112  CPL_ERROR_DATA_NOT_FOUND);
113  cpl_test_error(CPL_ERROR_DATA_NOT_FOUND);
114 
115  /* Create a 1st degree polynomial, x = 0 */
116  i = 1;
117  cpl_test_eq(cpl_polynomial_set_coeff(p1d, &i, 1.0), CPL_ERROR_NONE);
118  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
119  CPL_ERROR_INCOMPATIBLE_INPUT);
120  cpl_test_error(CPL_ERROR_INCOMPATIBLE_INPUT);
121 
122  cpl_polynomial_delete(p1d);
123  cpl_polynomial_delete(p2d);
124 
125  for (nreal = 1; nreal <= maxdegree; nreal++) {
126  /* A single, zero-valued root with multiplicity equal to degree */
127  double xreal = 0.0;
128 
129 
130  cpl_vector_set_size(xtrue, nreal);
131 
132  (void)cpl_vector_fill(xtrue, xreal);
133 
134  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
135  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
136 
137  /* A single, non-zero integer root with multiplicity equal to degree */
138  xreal = 1.0;
139 
140  (void)cpl_vector_fill(xtrue, xreal);
141 
142  irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
143  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
144 
145  /* degree distinct real roots - with rounding */
146  for (i = 0; i < nreal; i++) {
147  (void)cpl_vector_set(xtrue, i, 2.0 * (double)i - CPL_MATH_E);
148  }
149 
150  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
151  20.0 * DBL_EPSILON,
152  300.0 * DBL_EPSILON);
153 
154  /* All real, one zero, one positive, rest negative, sum zero */
155  for (i = 0; i < nreal-1; i++) {
156  (void)cpl_vector_set(xtrue, nreal-i-2, (double)(-i));
157  }
158  (void)cpl_vector_set(xtrue, nreal-1, (double)(nreal-1)); /* FIXME: ? */
159 
160  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
161  16.0*DBL_EPSILON, 600.0*DBL_EPSILON);
162 
163  if (nreal < 2) continue;
164  /* Two complex, conjugate roots, the rest is real
165  with multiplicity degree-2 */
166 
167  (void)cpl_vector_fill(xtrue, 2.0);
168  (void)cpl_vector_set(xtrue, nreal-2, -1.0);
169  (void)cpl_vector_set(xtrue, nreal-1, 1.0);
170 
171  irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
172  30.0*DBL_EPSILON, 25.0*DBL_EPSILON);
173 
174  if (nreal < 3) continue;
175  if (nreal > 4) {
176  /* Two real roots, the smaller with multiplicity degree-1 */
177  (void)cpl_vector_fill(xtrue, 1.0);
178  (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
179 
180  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
181  DBL_EPSILON, DBL_EPSILON);
182  /* Same with negative roots */
183  (void)cpl_vector_fill(xtrue, -1.0);
184  (void)cpl_vector_set(xtrue, 0 , -2.0);
185 
186  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
187  DBL_EPSILON, DBL_EPSILON);
188  /* Two real roots, the larger with multiplicity degree-1 */
189  (void)cpl_vector_fill(xtrue, 2.0);
190  (void)cpl_vector_set(xtrue, 0, 1.0);
191 
192  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
193  DBL_EPSILON, DBL_EPSILON);
194  }
195 
196  if (nreal > 3) continue;
197 
198  /* Same with negative roots */
199  (void)cpl_vector_fill(xtrue, -2.0 * FLT_EPSILON);
200  (void)cpl_vector_set(xtrue, 0, -1.0);
201 
202  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
203  DBL_EPSILON, 2.0*DBL_EPSILON);
204 
205  /* A more extreme case: Same with negative roots */
206 #if defined SIZE_MAX && SIZE_MAX <= 4294967295
207  (void)cpl_vector_fill(xtrue, -0.1 * FLT_EPSILON);
208 #else
209  (void)cpl_vector_fill(xtrue, -0.2 * FLT_EPSILON);
210 #endif
211 
212  (void)cpl_vector_set(xtrue, 0, -1.0);
213 
214  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
215  FLT_EPSILON, 3.0*DBL_EPSILON);
216 
217  if (nreal != 3) {
218  /* The most extreme case: Same with negative roots */
219  (void)cpl_vector_fill(xtrue, -2.0 * DBL_EPSILON);
220  (void)cpl_vector_set(xtrue, 0, -1.0);
221 
222  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
223  DBL_EPSILON, 2.0*DBL_EPSILON);
224 
225 
226  (void)cpl_vector_set(xtrue, 0, -1.0);
227  (void)cpl_vector_set(xtrue, 1, -2.0e-4 * FLT_EPSILON);
228  (void)cpl_vector_set(xtrue, 2, 2.0e-4 * FLT_EPSILON);
229 
230  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
231  FLT_EPSILON, 2.0*DBL_EPSILON);
232  }
233 
234  /* Two complex conjugate roots, remaining:
235  small, with multiplicity degree-2 */
236  (void)cpl_vector_fill(xtrue, 2.0*DBL_EPSILON);
237  (void)cpl_vector_set(xtrue, nreal - 2 , 3.0);
238  (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
239 
240  irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
241  4.0 * DBL_EPSILON, DBL_EPSILON);
242 
243  /* Two complex conjugate roots with small real part, remaining:
244  with multiplicity degree-2 */
245  (void)cpl_vector_fill(xtrue, 3.0);
246  (void)cpl_vector_set(xtrue, nreal - 2 , -1.0);
247  (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
248 
249  irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
250  6.0*DBL_EPSILON, 220.0*DBL_EPSILON);
251 
252 
253  }
254 
255 #if MAXDEGREE > 2
256  /* Cover branch fixing cancellation with one negative,
257  one positive near-zero and one positive root. */
258  nreal = 3;
259 
260  cpl_vector_set_size(xtrue, nreal);
261 
262  /* -2, epsilon, 1.5 */
263  (void)cpl_vector_set(xtrue, 0, -2.0);
264  (void)cpl_vector_set(xtrue, 1, 2.0 * DBL_EPSILON);
265  (void)cpl_vector_set(xtrue, 2, 1.5);
266 
267  irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
268  4.0*DBL_EPSILON, 30.0*DBL_EPSILON);
269 
270 #if MAXDEGREE > 3
271  nreal = 4;
272 
273  cpl_vector_set_size(xtrue, nreal);
274 
275  /* Depressed has zero as root */
276  (void)cpl_vector_set(xtrue, 0, -1.0);
277  (void)cpl_vector_set(xtrue, 1, 1.0);
278  (void)cpl_vector_set(xtrue, 2, 2.0);
279  (void)cpl_vector_set(xtrue, 3, 2.0);
280 
281  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
282  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
283 
284  /* Depressed has zero as root, and two complex roots*/
285  irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
286  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
287 
288 
289  /* Depressed is biquadratic, with 4 real roots */
290  (void)cpl_vector_set(xtrue, 0, -2.0);
291  (void)cpl_vector_set(xtrue, 1, -1.0);
292  (void)cpl_vector_set(xtrue, 2, 1.0);
293  (void)cpl_vector_set(xtrue, 3, 2.0);
294 
295  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
296  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
297 
298  /* Depressed is biquadratic, with 2 real roots */
299  (void)cpl_vector_set(xtrue, 0, -1.0);
300  (void)cpl_vector_set(xtrue, 1, 1.0);
301  (void)cpl_vector_set(xtrue, 2, 0.0);
302  (void)cpl_vector_set(xtrue, 3, 2.0);
303 
304  irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
305  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
306 
307  /* Depressed is biquadratic (the quadratic has real, negative roots),
308  with 0 real roots */
309  (void)cpl_vector_set(xtrue, 0, 1.0);
310  (void)cpl_vector_set(xtrue, 1, 2.0);
311  (void)cpl_vector_set(xtrue, 2, 1.0);
312  (void)cpl_vector_set(xtrue, 3, 3.0);
313 
314  irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
315  10.0 * DBL_EPSILON, 10.0 * DBL_EPSILON);
316 
317  /* roots: 0, 0, ai, -ai */
318  (void)cpl_vector_set(xtrue, 0, 0.0);
319  (void)cpl_vector_set(xtrue, 1, 0.0);
320  (void)cpl_vector_set(xtrue, 2, 0.0);
321  (void)cpl_vector_set(xtrue, 3, 2.0);
322 
323  irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
324  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
325 
326  p1d = cpl_polynomial_new(1);
327 
328  i = 0;
329  cpl_polynomial_set_coeff(p1d, &i, -5.0);
330  i = 1;
331  cpl_polynomial_set_coeff(p1d, &i, -1.0);
332  i = 2;
333  cpl_polynomial_set_coeff(p1d, &i, -2.0);
334  i = 4;
335  cpl_polynomial_set_coeff(p1d, &i, 1.0);
336 
337  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
338  CPL_ERROR_NONE);
339 
340  cpl_msg_info(cpl_func, "Computed roots (%" CPL_SIZE_FORMAT " real): ",
341  nreal);
342  if (cpl_msg_get_level() <= CPL_MSG_INFO)
343  cpl_vector_dump(xtrue, stderr);
344  cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 0),
345  cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 0), NULL) );
346  cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 1),
347  cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 1), NULL) );
348 
349  cpl_polynomial_delete(p1d);
350 
351  (void)cpl_vector_set(xtrue, 0, 0.0);
352  (void)cpl_vector_set(xtrue, 1, 2.0);
353  (void)cpl_vector_set(xtrue, 2, 1.0);
354  (void)cpl_vector_set(xtrue, 3, 1.0);
355 
356  irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
357  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
358 
359  (void)cpl_vector_set(xtrue, 0, -1.0);
360  (void)cpl_vector_set(xtrue, 1, 2.0);
361  (void)cpl_vector_set(xtrue, 2, 1.0);
362  (void)cpl_vector_set(xtrue, 3, 3.0);
363 
364  irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
365  3.0 * DBL_EPSILON, 3.0 * DBL_EPSILON);
366 #if MAXDEGREE > 4
367  nreal = 5;
368 
369  cpl_vector_set_size(xtrue, nreal);
370 
371  /* Depressed has zero as root */
372  (void)cpl_vector_set(xtrue, 0, -1.0);
373  (void)cpl_vector_set(xtrue, 1, 1.0);
374  (void)cpl_vector_set(xtrue, 2, 2.0);
375  (void)cpl_vector_set(xtrue, 3, 3.0);
376  (void)cpl_vector_set(xtrue, 4, 4.0);
377 
378  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
379  48.0 * DBL_EPSILON, 2800.0 * DBL_EPSILON);
380 
381  irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
382  8.0 * DBL_EPSILON, 4000.0 * DBL_EPSILON);
383 
384  irplib_polynomial_test_root_all(xtrue, nreal-4, CPL_MATH_PI,
385  4.0 * DBL_EPSILON, 600.0 * DBL_EPSILON);
386 
387 #if MAXDEGREE > 5
388  nreal = 6;
389 
390  cpl_vector_set_size(xtrue, nreal);
391 
392  /* Depressed has zero as root */
393  (void)cpl_vector_set(xtrue, 0, -1.0);
394  (void)cpl_vector_set(xtrue, 1, 1.0);
395  (void)cpl_vector_set(xtrue, 2, 2.0);
396  (void)cpl_vector_set(xtrue, 3, 3.0);
397  (void)cpl_vector_set(xtrue, 4, 4.0);
398  (void)cpl_vector_set(xtrue, 5, 5.0);
399 
400  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
401  240.0 * DBL_EPSILON, 50.0e3 * DBL_EPSILON);
402 
403  irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
404  8.0 * DBL_EPSILON, 25.0e3 * DBL_EPSILON);
405 
406  irplib_polynomial_test_root_all(xtrue, nreal-4, CPL_MATH_PI,
407  12.0 * DBL_EPSILON, 1600.0 * DBL_EPSILON);
408 
409 #endif
410 #endif
411 #endif
412 #endif
413 
414  cpl_vector_delete(xtrue);
415 
416  return;
417 }
418 
419 /*----------------------------------------------------------------------------*/
430 /*----------------------------------------------------------------------------*/
431 static
432 cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial * self,
433  const cpl_vector * roots,
434  cpl_size nreal)
435 {
436 
437  const cpl_size nroots = cpl_vector_get_size(roots);
438  cpl_size i, degree;
439 
440  cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
441  cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
442  cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
443  CPL_ERROR_ILLEGAL_INPUT);
444 
445  cpl_ensure_code(nreal >= 0, CPL_ERROR_ILLEGAL_INPUT);
446  cpl_ensure_code(nreal <= nroots,
447  CPL_ERROR_ILLEGAL_INPUT);
448  cpl_ensure_code((cpl_vector_get_size(roots) - nreal) % 2 == 0,
449  CPL_ERROR_ILLEGAL_INPUT);
450 
451  i = 0;
452  degree = cpl_polynomial_get_degree(self);
453  cpl_ensure_code(degree > 0 || cpl_polynomial_get_coeff(self, &i) != 0.0,
454  CPL_ERROR_DATA_NOT_FOUND);
455 
456  for (i = 0; i < nreal; i++) {
457  const double root = cpl_vector_get(roots, i);
458  double prev = 0.0;
459  cpl_size j;
460 
461  degree++;
462 
463  for (j = degree; j >= 0; j--) {
464  double value = 0.0;
465  double newval;
466 
467  if (j > 0) {
468  const cpl_size jj = j - 1;
469  newval = value = cpl_polynomial_get_coeff(self, &jj);
470  } else {
471  newval = 0.0;
472  }
473 
474  if (j < degree) {
475  newval -= root * prev;
476  }
477 
478  cpl_polynomial_set_coeff(self, &j, newval);
479 
480  prev = value;
481 
482  }
483  }
484 
485  /* Multiplication with the complex conjugate root
486  (x-a-ib) (x-a+ib) p(x) = (x-a)^2 p(x) + b^2 p(x) */
487  for (; i < nroots; i += 2) {
488  const double a = cpl_vector_get(roots, i);
489  const double b = cpl_vector_get(roots, i+1);
490  cpl_vector * aroot = cpl_vector_new(2);
491  cpl_polynomial * copy = cpl_polynomial_duplicate(self);
492 
493  cpl_vector_fill(aroot, a);
494 
495  irplib_polynomial_multiply_1d_factor(self, aroot, 2);
496 
497  cpl_polynomial_multiply_scalar(copy, copy, b * b);
498 
499  cpl_polynomial_add(self, self, copy);
500 
501  cpl_vector_delete(aroot);
502  cpl_polynomial_delete(copy);
503 
504  }
505 
506  return CPL_ERROR_NONE;
507 
508 }
509 
510 /*----------------------------------------------------------------------------*/
523 /*----------------------------------------------------------------------------*/
524 static void
525 irplib_polynomial_test_root_all_macro(const cpl_vector * self, cpl_size nreal,
526  double factor, double tolerance,
527  double resitol, unsigned line)
528 {
529 
530  const cpl_size degree = cpl_vector_get_size(self);
531  cpl_polynomial * p1d = cpl_polynomial_new(1);
532  cpl_vector * roots = cpl_vector_new(degree);
533  cpl_size i = 0;
534  cpl_size jreal;
535 
536  cpl_test_eq(cpl_polynomial_set_coeff(p1d, &i, factor), CPL_ERROR_NONE);
537 
538  cpl_test_eq(irplib_polynomial_multiply_1d_factor(p1d, self, nreal),
539  CPL_ERROR_NONE);
540 
541  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, roots, &jreal),
542  CPL_ERROR_NONE);
543 
544  cpl_test_eq(jreal, nreal);
545  if (jreal != nreal) {
546  cpl_msg_info(cpl_func, "1D-polynomial:");
547  cpl_polynomial_dump(p1d, stderr);
548  cpl_msg_error(cpl_func, "True roots (%" CPL_SIZE_FORMAT
549  " real): (line=%u)", nreal, line);
550  cpl_vector_dump(self, stderr);
551  cpl_msg_error(cpl_func, "Computed roots (%" CPL_SIZE_FORMAT " real): ",
552  jreal);
553  cpl_vector_dump(roots, stderr);
554  } else if (cpl_msg_get_level() < CPL_MSG_WARNING) {
555  cpl_bivector * dump =
556  cpl_bivector_wrap_vectors((cpl_vector*)self, roots);
557 
558  cpl_msg_warning(cpl_func, "Comparing %" CPL_SIZE_FORMAT " roots (%"
559  CPL_SIZE_FORMAT " real): (line=%u)",
560  degree, nreal, line);
561  cpl_bivector_dump(dump, stderr);
562  cpl_bivector_unwrap_vectors(dump);
563  }
564 
565  for (i = 0; i < jreal; i++) {
566  const double root = cpl_vector_get(roots, i);
567  const double residual = cpl_polynomial_eval_1d(p1d, root, NULL);
568 
569  cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
570 
571  cpl_test_abs(residual, 0.0, resitol);
572 
573  }
574 
575  for (i = nreal; i < degree; i++) {
576  const double root = cpl_vector_get(roots, i);
577 
578  cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
579 
580  /* FIXME: Verify residual as well */
581 
582  }
583 
584  cpl_vector_delete(roots);
585  cpl_polynomial_delete(p1d);
586 
587  return;
588 }