Algorithms_in_C 1.0.0
Set of algorithms implemented in C.
Loading...
Searching...
No Matches
durand_kerner_roots.c File Reference

Compute all possible approximate roots of any given polynomial using Durand Kerner algorithm More...

#include <complex.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
Include dependency graph for durand_kerner_roots.c:

Macros

#define ACCURACY   1e-10
 maximum accuracy limit
 

Functions

long double complex poly_function (long double *coeffs, unsigned int degree, long double complex x)
 Evaluate the value of a polynomial with given coefficients. More...
 
const char * complex_str (long double complex x)
 create a textual form of complex number More...
 
char check_termination (long double delta)
 check for termination condition More...
 
int main (int argc, char **argv)
 

Detailed Description

Compute all possible approximate roots of any given polynomial using Durand Kerner algorithm

Author
Krishna Vedala

Test the algorithm online: https://gist.github.com/kvedala/27f1b0b6502af935f6917673ec43bcd7

Try the highly unstable Wilkinson's polynomial:

./numerical_methods/durand_kerner_roots.c 1 -210 20615 -1256850 53327946
-1672280820 40171771630 -756111184500 11310276995381 -135585182899530
1307535010540395 -10142299865511450 63030812099294896 -311333643161390640
1206647803780373360 -3599979517947607200 8037811822645051776
-12870931245150988800 13803759753640704000 -8752948036761600000
2432902008176640000

Sample implementation results to compute approximate roots of the equation \(x^4-1=0\):
Error evolution during root approximations computed every
iteration. Roots evolution - shows the initial approximation of the
roots and their convergence to a final approximation along with the iterative
approximations

Function Documentation

◆ check_termination()

char check_termination ( long double  delta)

check for termination condition

Parameters
[in]deltapoint at which to evaluate the polynomial
Returns
0 if termination not reached
1 if termination reached
84{
85 static long double past_delta = INFINITY;
86 if (fabsl(past_delta - delta) <= ACCURACY || delta < ACCURACY)
87 return 1;
88 past_delta = delta;
89 return 0;
90}
#define ACCURACY
maximum accuracy limit
Definition: durand_kerner_roots.c:41

◆ complex_str()

const char * complex_str ( long double complex  x)

create a textual form of complex number

Parameters
[in]xpoint at which to evaluate the polynomial
Returns
pointer to converted string
67{
68 static char msg[50];
69 double r = creal(x);
70 double c = cimag(x);
71
72 sprintf(msg, "% 7.04g%+7.04gj", r, c);
73
74 return msg;
75}

◆ main()

int main ( int  argc,
char **  argv 
)

store intermediate values to a CSV file

96{
97 long double *coeffs = NULL;
98 long double complex *s0 = NULL;
99 unsigned int degree = 0;
100 unsigned int n, i;
101
102 if (argc < 2)
103 {
104 printf(
105 "Please pass the coefficients of the polynomial as commandline "
106 "arguments.\n");
107 return 0;
108 }
109
110 degree = argc - 1; /* detected polynomial degree */
111 coeffs = (long double *)malloc(
112 degree * sizeof(long double)); /* store all input coefficients */
113 s0 = (long double complex *)malloc(
114 (degree - 1) *
115 sizeof(long double complex)); /* number of roots = degree-1 */
116
117 /* initialize random seed: */
118 srand(time(NULL));
119
120 if (!coeffs || !s0)
121 {
122 perror("Unable to allocate memory!");
123 if (coeffs)
124 free(coeffs);
125 if (s0)
126 free(s0);
127 return EXIT_FAILURE;
128 }
129
130#if defined(DEBUG) || !defined(NDEBUG)
131 /**
132 * store intermediate values to a CSV file
133 */
134 FILE *log_file = fopen("durand_kerner.log.csv", "wt");
135 if (!log_file)
136 {
137 perror("Unable to create a storage log file!");
138 free(coeffs);
139 free(s0);
140 return EXIT_FAILURE;
141 }
142 fprintf(log_file, "iter#,");
143#endif
144
145 printf("Computing the roots for:\n\t");
146 for (n = 0; n < degree; n++)
147 {
148 coeffs[n] = strtod(argv[n + 1], NULL);
149 if (n < degree - 1 && coeffs[n] != 0)
150 printf("(%Lg) x^%d + ", coeffs[n], degree - n - 1);
151 else if (coeffs[n] != 0)
152 printf("(%Lg) x^%d = 0\n", coeffs[n], degree - n - 1);
153
154 double tmp;
155 if (n > 0)
156 coeffs[n] /= tmp; /* numerical errors less when the first
157 coefficient is "1" */
158 else
159 {
160 tmp = coeffs[0];
161 coeffs[0] = 1;
162 }
163
164 /* initialize root approximations with random values */
165 if (n < degree - 1)
166 {
167 s0[n] = (long double)rand() + (long double)rand() * I;
168#if defined(DEBUG) || !defined(NDEBUG)
169 fprintf(log_file, "root_%d,", n);
170#endif
171 }
172 }
173
174#if defined(DEBUG) || !defined(NDEBUG)
175 fprintf(log_file, "avg. correction");
176 fprintf(log_file, "\n0,");
177 for (n = 0; n < degree - 1; n++)
178 fprintf(log_file, "%s,", complex_str(s0[n]));
179#endif
180
181 double tol_condition = 1;
182 unsigned long iter = 0;
183
184 clock_t end_time, start_time = clock();
185 while (!check_termination(tol_condition) && iter < INT_MAX)
186 {
187 long double complex delta = 0;
188 tol_condition = 0;
189 iter++;
190
191#if defined(DEBUG) || !defined(NDEBUG)
192 fprintf(log_file, "\n%ld,", iter);
193#endif
194
195 for (n = 0; n < degree - 1; n++)
196 {
197 long double complex numerator =
198 poly_function(coeffs, degree, s0[n]);
199 long double complex denominator = 1.0;
200 for (i = 0; i < degree - 1; i++)
201 if (i != n)
202 denominator *= s0[n] - s0[i];
203
204 delta = numerator / denominator;
205
206 if (isnan(cabsl(delta)) || isinf(cabsl(delta)))
207 {
208 printf("\n\nOverflow/underrun error - got value = %Lg",
209 cabsl(delta));
210 goto end;
211 }
212
213 s0[n] -= delta;
214
215 tol_condition = fmaxl(tol_condition, fabsl(cabsl(delta)));
216
217#if defined(DEBUG) || !defined(NDEBUG)
218 fprintf(log_file, "%s,", complex_str(s0[n]));
219#endif
220 }
221 // tol_condition /= (degree - 1);
222
223#if defined(DEBUG) || !defined(NDEBUG)
224 if (iter % 500 == 0)
225 {
226 printf("Iter: %lu\t", iter);
227 for (n = 0; n < degree - 1; n++) printf("\t%s", complex_str(s0[n]));
228 printf("\t\tabsolute average change: %.4g\n", tol_condition);
229 }
230
231 fprintf(log_file, "%.4g", tol_condition);
232#endif
233 }
234end:
235
236 end_time = clock();
237
238#if defined(DEBUG) || !defined(NDEBUG)
239 fclose(log_file);
240#endif
241
242 printf("\nIterations: %lu\n", iter);
243 for (n = 0; n < degree - 1; n++) printf("\t%s\n", complex_str(s0[n]));
244 printf("absolute average change: %.4g\n", tol_condition);
245 printf("Time taken: %.4g sec\n",
246 (end_time - start_time) / (double)CLOCKS_PER_SEC);
247
248 free(coeffs);
249 free(s0);
250
251 return 0;
252}
char check_termination(long double delta)
check for termination condition
Definition: durand_kerner_roots.c:83
long double complex poly_function(long double *coeffs, unsigned int degree, long double complex x)
Evaluate the value of a polynomial with given coefficients.
Definition: durand_kerner_roots.c:50
const char * complex_str(long double complex x)
create a textual form of complex number
Definition: durand_kerner_roots.c:66
#define malloc(bytes)
This macro replace the standard malloc function with malloc_dbg.
Definition: malloc_dbg.h:18
#define free(ptr)
This macro replace the standard free function with free_dbg.
Definition: malloc_dbg.h:26
Here is the call graph for this function:

◆ poly_function()

long double complex poly_function ( long double *  coeffs,
unsigned int  degree,
long double complex  x 
)

Evaluate the value of a polynomial with given coefficients.

Parameters
[in]coeffscoefficients of the polynomial
[in]degreedegree of polynomial
[in]xpoint at which to evaluate the polynomial
Returns
\(f(x)\)
52{
53 long double complex out = 0.;
54 unsigned int n;
55
56 for (n = 0; n < degree; n++) out += coeffs[n] * cpow(x, degree - n - 1);
57
58 return out;
59}