1 /*
2
3 Copyright (C) 2008-2009 Evgeni A. Nurminski <nurmi@dvo.ru>
4 Copyright (C) 2008-2009 Pete Gonzalez <pgonzalez@bluel.com>
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 3 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; see the file COPYING. If not, see
18 <https://www.gnu.org/licenses/>.
19
20 */
21
22 #ifdef _MSC_VER
23 #define _CRT_SECURE_NO_WARNINGS // disable spurious warnings
24 #define _USE_MATH_DEFINES // for math.h
25 #endif
26
27 #include "cl2bp_lib.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <math.h>
33 #include <string.h>
34
35 #include <stdexcept>
36
37 #define BIG_NUMBER 100000
38
39 //-----------------------------------------------------------------------------------------------------------
40 #ifdef CL2BP_LOGGING
log_printf(const char * format,...)41 static void log_printf(const char *format, ...) {
42 va_list argptr;
43 va_start(argptr, format);
44
45 char buf[20*1024];
46 if (vsnprintf(buf,20*1024-1,format,argptr) == -1) {
47 strcpy(buf, "#ERROR#");
48 }
49 va_end(argptr);
50
51 cl2bp_log(buf);
52 }
53 #else
54 #define log_printf(...) ((void)0) // don't log anything (for a big speed improvement)
55 #endif
56
57 //-----------------------------------------------------------------------------------------------------------
local_max(const MallocArray<double> & x,int n,MallocArray<int> & ix)58 static int local_max(const MallocArray<double>& x, int n, MallocArray<int>& ix) {
59 int i, mx;
60
61 mx = 0;
62
63 MallocArray<double> xx(n+2);
64
65 xx[0] = xx[n + 1] = -BIG_NUMBER;
66 for ( i = 1; i <= n; i++)
67 xx[i] = x[i - 1];
68 for ( i = 0; i < n; i++ ) {
69 (((xx[i] < xx[i + 1]) && (xx[i + 1] > xx[i + 2])) ||
70 ((xx[i] < xx[i + 1]) && (xx[i + 1] >= xx[i + 2])) ||
71 ((xx[i] <= xx[i + 1]) && (xx[i + 1] > xx[i + 2])) )
72 && ( ix[mx++] = i );
73 }
74 return mx;
75 }
76
77 //-----------------------------------------------------------------------------------------------------------
solvps(MallocArray<double> & a,MallocArray<double> & b,int n,void (* cancel_handler)(void *),void * cancel_state)78 static int solvps(MallocArray<double>& a, MallocArray<double>& b, int n,
79 void (*cancel_handler)(void *), void *cancel_state) {
80
81 double t;
82 int j, k;
83 int a_p;
84 int a_q;
85 int a_r;
86 int a_s;
87
88 // In empirical tests, 2% to 6% of the execution time was spent in solvps()
89 if (cancel_handler) cancel_handler(cancel_state);
90
91 for (j = 0, a_p = 0; j < n; ++j, a_p += n+1) {
92 for (a_q = j*n; a_q < a_p; ++a_q)
93 a[a_p] -= a[a_q] * a[a_q];
94 if (a[a_p] <= 0.)
95 return -1;
96 a[a_p] = sqrt(a[a_p]);
97 for (k = j + 1, a_q = a_p + n; k < n; ++k, a_q += n) {
98 for (a_r = j*n, a_s = k*n, t = 0.; a_r < a_p;)
99 t += a[a_r++] * a[a_s++];
100 a[a_q] -= t;
101 a[a_q] /= a[a_p];
102 }
103 }
104 for (j = 0, a_p = 0; j < n; ++j, a_p += n+1) {
105 for (k = 0, a_q = j*n; k < j;)
106 b[j] -=b [k++] * a[a_q++];
107 b[j] /= a[a_p];
108 }
109 for (j = n - 1, a_p = n*n - 1; j >= 0; --j, a_p -= n + 1) {
110 for (k = j + 1, a_q = a_p + n; k < n; a_q += n)
111 b[j] -= b[k++]* a[a_q];
112 b[j] /= a[a_p];
113 }
114 return 0;
115 }
116
117 //-----------------------------------------------------------------------------------------------------------
rmmult(MallocArray<double> & rm,const MallocArray<double> & a,const MallocArray<double> & b,int n,int m,int l,void (* cancel_handler)(void *),void * cancel_state)118 static void rmmult(MallocArray<double>& rm, const MallocArray<double>& a, const MallocArray<double>& b,
119 int n, int m, int l,
120 void (*cancel_handler)(void *), void *cancel_state) {
121
122 double z;
123 int i,j,k;
124 int b_p; // index into b
125 int a_p; // index into a
126 int rm_start = 0; // index into rm
127 int rm_q; // index into rm
128
129 MallocArray<double> q0(m);
130 for (i = 0; i < l ; ++i, ++rm_start) {
131 // In empirical tests, 87% to 95% of the execution time was spent in rmmult()
132 if (cancel_handler) cancel_handler(cancel_state);
133 for (k = 0, b_p = i; k < m; b_p += l)
134 q0[k++] = b[b_p];
135 for (j = 0, a_p = 0, rm_q = rm_start; j < n; ++j, rm_q += l) {
136 for (k = 0, z = 0.; k < m;)
137 z += a[a_p++] * q0[k++];
138 rm[rm_q]=z;
139 }
140 }
141 }
142
143 //-----------------------------------------------------------------------------------------------------------
mattr(MallocArray<double> & a,const MallocArray<double> & b,int m,int n)144 static void mattr(MallocArray<double>& a, const MallocArray<double>& b, int m, int n) {
145 int i, j;
146 int b_p;
147 int a_p = 0;
148 int b_start = 0;
149 for (i = 0; i < n; ++i, ++b_start)
150 for ( j = 0, b_p = b_start; j < m; ++j, b_p += n )
151 a[a_p++] = b[b_p];
152 }
153
154 //-----------------------------------------------------------------------------------------------------------
calcAx(MallocArray<double> & Ax,int m,int L)155 static void calcAx(MallocArray<double>& Ax, int m, int L) {
156 double r = M_SQRT2, pi = M_PI;
157 int i, j;
158
159 Ax.resize((L+1)*(m + 1));
160
161 for ( i = 0; i <= L; i++)
162 for ( j = 0; j <= m; j++)
163 Ax[i*(m+1) + j] = cos(i*j*pi/L);
164 for ( i = 0; i < (L+1)*(m+1); i += m + 1 )
165 Ax[i] /= r;
166 }
167
168 //-----------------------------------------------------------------------------------------------------------
169 #ifdef CL2BP_LOGGING
L2error(const MallocArray<double> & x,const MallocArray<double> & w,int L,double w1,double w2)170 static double L2error(const MallocArray<double>& x, const MallocArray<double>& w, int L, double w1, double w2) {
171 double xx, ww, sumerr, pi = M_PI;
172 int i;
173 for ( i = 0, sumerr = 0; i < L + 1; i++ ) {
174 ww = w[i];
175 xx = x[i];
176 sumerr += ( ww < w1*pi || ww > w2*pi ) ? xx*xx : (1 - xx)*(1 - xx);
177 }
178 return sumerr;
179 }
180 #endif // CL2BP_LOGGING
181 //-----------------------------------------------------------------------------------------------------------
CHerror(double * wmin,const MallocArray<double> & x,const MallocArray<double> & w,int L,double w1,double w2)182 static double CHerror(double *wmin, const MallocArray<double>& x, const MallocArray<double>& w,
183 int L, double w1, double w2) {
184
185 double xx, ww, err, errmax;
186 int i;
187 errmax = -1;
188 *wmin = 0;
189 for ( i = 0; i < L + 1; i++ ) {
190 ww = w[i];
191 xx = x[i];
192 err = (( ww < w1 ) || (ww > w2 )) ? fabs(xx) : fabs(1 - xx);
193 if ( err > errmax ) {
194 errmax = err;
195 *wmin = ww;
196 }
197 }
198 return errmax;
199 }
200
201 //-----------------------------------------------------------------------------------------------------------
Ggen(MallocArray<double> & G,int m,const MallocArray<double> & w,const MallocArray<int> & kmax,int l_kmax,const MallocArray<int> & kmin,int l_kmin)202 static void Ggen(MallocArray<double>& G, int m, const MallocArray<double>& w, const MallocArray<int>& kmax,
203 int l_kmax, const MallocArray<int>& kmin, int l_kmin) {
204
205 G.resize((l_kmax + l_kmin)*(m + 1));
206
207 int nsys, i, j;
208 double r = M_SQRT2;
209
210 nsys = l_kmax + l_kmin;
211 for ( i = 0; i < l_kmax; i++)
212 for ( j = 0; j <= m; j++)
213 G[i*(m+1) + j] = cos(w[kmax[i]]*j);
214 for ( i = l_kmax; i < nsys; i++)
215 for ( j = 0; j <= m; j++)
216 G[i*(m+1) + j] = -cos(w[kmin[i - l_kmax]]*j);
217 for ( i = 0; i < nsys*(m+1); i += m+1 )
218 G[i] /= r;
219 }
220
221 //-----------------------------------------------------------------------------------------------------------
cl2bp(MallocArray<double> & h,int m,double w1,double w2,double up[3],double lo[3],int L,double eps,int mit,void (* cancel_handler)(void *),void * cancel_state)222 bool cl2bp(MallocArray<double>& h, int m, double w1, double w2, double up[3], double lo[3], int L,
223 double eps, int mit, void (*cancel_handler)(void *), void *cancel_state) {
224
225 // Ensure sane values for input parameters
226 if (m < 2 || m > 5000)
227 throw std::invalid_argument("cl2bp: The m count must be between 2 and 5000");
228
229 if (w1 < 0 || w1 > w2 || w2 > 2*M_PI)
230 throw std::invalid_argument("cl2bp: The cutoffs must be in the range 0 < w1 < w2 < 2*pi");
231
232 // Z is allocated as Z(2*L-1-2*m)
233 if (L <= m)
234 throw std::invalid_argument("cl2bp: The \"gridsize\" parameter must be larger than \"m\"");
235
236 double r = M_SQRT2;
237 double pi = M_PI;
238 double wmin, ww, xw;
239 int q1, q2, q3, i, iter = 0;
240 int off, neg;
241
242 int ik;
243 int l_kmax;
244 int l_kmin;
245 int l_okmax;
246 int l_okmin;
247 double uvo = 0, lvo = 0;
248
249 double err, diff_up, diff_lo;
250 double erru, erro;
251 int iup, ilo;
252
253 int nsys, j;
254
255 int imin = BIG_NUMBER;
256 double umin;
257
258 int k1 = -1, k2 = -1, ak1, ak2;
259 double cerr;
260
261 h.resize(2*m+1);
262
263 bool converged = true;
264
265 MallocArray<double> x0(L+1);
266 MallocArray<double> x1(L+1);
267 MallocArray<double> xx(L+1);
268 MallocArray<double> xm1(L+1);
269 MallocArray<double> w(L+1);
270 MallocArray<double> u(L+1);
271 MallocArray<double> l(L+1);
272 MallocArray<double> a(L+1);
273 MallocArray<double> c(L+1);
274 MallocArray<int> kmax(L+1);
275 MallocArray<int> kmin(L+1);
276 l_kmax = l_kmin = 0;
277
278 MallocArray<int> okmin(L+1);
279 MallocArray<int> okmax(L+1);
280 l_okmax = l_okmin = 0;
281 MallocArray<double> rhs(m+2);
282 MallocArray<double> mu(2*(L+1));
283
284 for ( i = 0; i <= L; i++ )
285 w[i] = i*pi/L;
286
287 MallocArray<double> Z(2*L-1-2*m);
288
289 q1 = (int)floor(L*w1/pi);
290 q2 = (int)floor(L*(w2-w1)/pi);
291 q3 = L + 1 - q1 - q2;
292
293 off = 0;
294 for ( i = 0; i < q1; i++) {
295 u[i] = up[0];
296 l[i] = lo[0];
297 }
298 off += i;
299 for ( i = 0; i < q2; i++) {
300 u[off + i] = up[1];
301 l[off + i] = lo[1];
302 }
303 off += i;
304 for ( i = 0; i < q3; i++) {
305 u[off + i] = up[2];
306 l[off + i] = lo[2];
307 }
308
309
310 c[0] = (w2-w1)*r;
311 for ( i = 1; i <= m; i++)
312 c[i] = 2*(sin(w2*i)-sin(w1*i))/i;
313 for ( i = 0; i <= m; i++) {
314 c[i] /= pi;
315 a[i] = c[i];
316 }
317 log_printf("\nInitial approximation. Unconstrained L2 filter coefficients.\n");
318 log_printf("=============================================================\n");
319
320 log_printf("\nZero order term %8.3lf\n", a[0]);
321 for ( i = 1; i <= m; i++) {
322 log_printf("%4d %8.3lf", i, a[i]);
323 if (i - 8*(i/8) == 0)
324 log_printf("\n");
325 }
326 log_printf("\n");
327
328 // Precalculate Ax
329 MallocArray<double> Ax;
330 calcAx(Ax, m, L);
331
332 //calcA(x0, a, m, L);
333 rmmult(x0, Ax, a, L + 1, m + 1, 1, cancel_handler, cancel_state);
334
335 err = CHerror(&wmin, x0, w, L, w1, w2);
336 log_printf("\nChebyshev err %12.4e (%11.5e) <> L2 err %12.4e\n", err, wmin/pi, L2error(x0, w, L, w1, w2)/(L+1));
337 for (iter = 1; ; iter++) {
338 log_printf("\n:::::: Iteration %3d :::::::::::\n", iter);
339
340 if ( (uvo > eps*2) || (lvo > eps*2) ) {
341 log_printf("\nXXX Take care of old errors: uvo lvo %12.3e %12.3e", uvo, lvo);
342 if( k1 >= 0 ) log_printf(" k1 %3d(%d)", k1, okmax[k1]);
343 if( k2 >= 0 ) log_printf(" k2 %3d(%d)", k2, okmin[k2]);
344 log_printf("\n");
345
346 if ( uvo > lvo ) {
347 kmax[l_kmax] = okmax[k1];
348 l_kmax++;
349 l_okmax--;
350 for (i = k1; i < l_okmax; i++)
351 okmax[i] = okmax[i + 1];
352 } else {
353 kmin[l_kmin] = okmin[k2];
354 l_kmin++;
355 l_okmin--;
356 for (i = k2; i < l_okmin; i++)
357 okmin[i] = okmin[i + 1];
358 }
359 nsys = l_kmax + l_kmin;
360
361 /*
362 for (i = 0; i < l_kmax; i++)
363 log_printf("i %3d kmax %3d mu %12.4e\n",
364 i, kmax[i], mu[i]);
365 log_printf("\n");
366 for (i = 0; i < l_kmin; i++)
367 log_printf("i %3d kmin %3d mu %12.4e\n",
368 i, kmin[i], mu[i + l_kmax]);
369 log_printf("\n\n");
370 */
371 } else {
372
373 //calcA(x1, a, m, L);
374 rmmult(x1, Ax, a, L + 1, m + 1, 1, cancel_handler, cancel_state);
375
376
377 for ( i = 0; i < l_kmax; i++)
378 okmax[i] = kmax[i];
379 for ( i = 0; i < l_kmin; i++)
380 okmin[i] = kmin[i];
381 l_okmax = l_kmax;
382 l_okmin = l_kmin;
383
384 l_kmax = local_max(x1, L + 1, kmax);
385
386
387 for ( i = 0; i < L + 1; i++)
388 xm1[i] = -x1[i];
389 l_kmin = local_max(xm1, L + 1, kmin);
390
391 log_printf("\nSignificant deviations from the ideal filter. Levels:");
392 log_printf(" %8.2e %8.2e %8.2e (lo)", lo[0], lo[1], lo[2]);
393 log_printf(" %8.2e %8.2e %8.2e (up)", up[0], up[1], up[2]);
394 log_printf("\n");
395
396 for ( i = 0, ik = 0; i < l_kmax; i++) {
397 j = kmax[i];
398 if ( x1[j] > u[j] - 10*eps ) {
399 kmax[ik] = j;
400 ik++;
401 }
402 }
403 l_kmax = ik;
404
405 log_printf("overshoots = %d\n", l_kmax);
406 for ( i = 0; i < l_kmax; i++) {
407 j = kmax[i];
408 ww = w[j];
409 xw = x1[j];
410 err = (w1 < ww && ww < w2) ? xw - 1 : xw;
411 log_printf(" i = %3d kmax = %3d xw = %12.5e err = %10.3e u = %12.4e max = %9.2e\n",
412 i, j, xw, err, u[j], xw - u[j]);
413 }
414
415 for ( i = 0, ik = 0; i < l_kmin; i++) {
416 j = kmin[i];
417 if ( x1[j] < l[j] + 10*eps ) {
418 kmin[ik] = j;
419 ik++;
420 }
421 }
422 l_kmin = ik;
423
424 log_printf("undershoots = %d\n", l_kmin);
425 for ( i = 0; i < l_kmin; i++) {
426 j = kmin[i];
427 ww = w[j];
428 xw = -xm1[j];
429 err =(w1 < ww && ww < w2) ? xw - 1 : xw;
430 log_printf(" i = %3d kmin = %3d xw = %12.5e err = %10.3e l = %12.4e min = %9.2e\n",
431 i, j, xw, err, l[j], xw - l[j]);
432 }
433
434 err = erru = erro = diff_up = diff_lo = 0;
435 iup = ilo = 0;
436 for ( i = 0; i < l_kmax; i++) {
437 ik = kmax[i];
438 diff_up = x1[ik] - u[ik];
439 if ( diff_up > erru ) {
440 erru = diff_up;
441 iup = i;
442 }
443 }
444 for ( i = 0; i < l_kmin; i++) {
445 ik = kmin[i];
446 diff_lo = l[ik] - x1[ik];
447 if ( diff_lo > erro ) {
448 erro = diff_lo;
449 ilo = i;
450 }
451 }
452 err = erro > erru ? erro : erru;
453 log_printf("erru = %14.6e iup = %4d kmax = %4d ", erru, iup, kmax[iup]);
454 log_printf("erro = %14.6e ilo = %4d kmin = %4d\n", erro, ilo, kmin[ilo]);
455 #ifndef CL2BP_LOGGING
456 static_cast<void>(iup);
457 #endif
458
459 if ( err < eps )
460 break;
461 }
462
463
464 nsys = l_kmax + l_kmin;
465
466 MallocArray<double> G(nsys*(m + 1));
467 MallocArray<double> GT(nsys*(m + 1));
468 MallocArray<double> GG(nsys*nsys);
469
470 for ( i = 0; i < l_kmax; i++)
471 for ( j = 0; j <= m; j++)
472 G[i*(m+1) + j] = cos(w[kmax[i]]*j);
473 for ( i = l_kmax; i < nsys; i++)
474 for ( j = 0; j <= m; j++)
475 G[i*(m+1) + j] = -cos(w[kmin[i - l_kmax]]*j);
476 for ( i = 0; i < nsys*(m+1); i += m+1 )
477 G[i] /= r;
478 mattr(GT, G, nsys, m + 1);
479 rmmult(GG, G, GT, nsys, m + 1, nsys, cancel_handler, cancel_state);
480
481
482 rmmult(rhs, G, c, nsys, m + 1, 1, cancel_handler, cancel_state);
483 for ( i = 0; i < nsys; i++)
484 if ( i < l_kmax )
485 rhs[i] -= u[kmax[i]];
486 else
487 rhs[i] += l[kmin[i - l_kmax]];
488
489 for ( i = 0; i < nsys; ++i)
490 mu[i] = rhs[i];
491
492 solvps(GG, mu, nsys, cancel_handler, cancel_state);
493 log_printf("\nXXX KT-system with %d equations resolved.\n", nsys);
494 for ( i = 0, neg = 0; i < nsys; i++)
495 if ( mu[i] < 0 ) neg++;
496 log_printf("\nTotal number of negative multipliers = %3d\n\n", neg);
497 while (neg) {
498
499
500 umin = BIG_NUMBER;
501 for ( i = 0, j = 0; i < nsys; i++) {
502 if ( mu[i] >= 0 ) continue;
503 j++;
504 if ( mu[i] < umin ) {
505 imin = i;
506 umin = mu[i];
507 }
508 }
509
510 if ( umin > 0 )
511 break;
512 log_printf(" neg = %3d of %3d imin = %3d mu-min = %12.4e\n", j, nsys, imin, umin);
513
514 for ( i = imin; i < nsys - 1; i++) {
515 rhs[i] = rhs[i + 1];
516 for ( j = 0; j <= m; j++)
517 G[i*(m + 1) + j] = G[(i + 1)*(m + 1) + j];
518 }
519
520 if ( imin < l_kmax ) {
521 for ( i = imin; i < l_kmax - 1; i++)
522 kmax[i] = kmax[i + 1];
523 l_kmax--;
524 } else {
525 for ( i = imin; i < nsys - 1; i++)
526 kmin[i - l_kmax] = kmin[i - l_kmax + 1];
527 l_kmin--;
528 }
529
530 --nsys;
531
532 mattr(GT, G, nsys, m + 1);
533 rmmult(GG, G, GT, nsys, m + 1, nsys, cancel_handler, cancel_state);
534 for ( i = 0; i < nsys; ++i)
535 mu[i] = rhs[i];
536 solvps(GG, mu, nsys, cancel_handler, cancel_state);
537 }
538
539 MallocArray<double> da(m + 1);
540 MallocArray<double> zd(nsys);
541
542 rmmult(da, GT, mu, m + 1, nsys, 1, cancel_handler, cancel_state);
543 for ( i = 0; i <= m; i++)
544 a[i] = c[i] - da[i];
545 rmmult(zd, G, a, nsys, m + 1, 1, cancel_handler, cancel_state);
546
547 MallocArray<double> zz(l_okmax + l_okmin);
548 Ggen(G, m, w, okmax, l_okmax, okmin, l_okmin);
549 rmmult(zz, G, a, l_okmax + l_okmin, m + 1, 1, cancel_handler, cancel_state);
550 uvo = lvo = eps;
551 k1 = k2 = -1;
552 ak1 = ak2 = -1;
553 if (l_okmax + l_okmin > 0)
554 log_printf("\nErrors on the previous set of freqs\n\n");
555 for (i = 0; i < l_okmax; i++) {
556 j = okmax[i];
557 cerr = zz[i] - u[j];
558 log_printf(" i %2d j %3d u %12.4e Ga %12.4e cerr %12.4e\n",
559 i, j, u[j], zz[i], cerr);
560 if ( cerr > uvo ) {
561 uvo = cerr;
562 k1 = i;
563 ak1 = j;
564 }
565 }
566 cerr = 0;
567 for (i = 0; i < l_okmin; i++) {
568 j = okmin[i];
569 cerr = l[j] + zz[i + l_okmax];
570 log_printf(" i %2d j %3d l %12.4e Ga %12.4e cerr %12.4e\n",
571 i, j, l[j], zz[i + l_okmax], cerr);
572 if ( cerr > lvo ) {
573 lvo = cerr;
574 k2 = i, ak2 = j;
575 }
576 }
577 if ( l_okmax + l_okmin > 0 ) {
578 log_printf("\n uvo = %12.4e k1 = %4d (%3d) ", uvo, k1, ak1);
579 log_printf(" lvo = %12.4e k2 = %4d (%3d) ", lvo, k2, ak2);
580 log_printf(" maxerr = %12.4e\n", uvo > lvo ? uvo : lvo);
581 #ifndef CL2BP_LOGGING
582 static_cast<void>(ak1);
583 #endif
584 }
585
586 log_printf("\nConstrained L2 band filter coefficients.\n");
587 log_printf("=====================================\n");
588
589 #ifdef CL2BP_LOGGING
590 log_printf("\nZero order term %8.3lf\n", a[0]);
591 for ( i = 1; i <= m; i++) {
592 log_printf("%4d %8.3lf", i, a[i]);
593 if (i - 8*(i/8) == 0)
594 log_printf("\n");
595 }
596 log_printf("\n");
597 #endif
598
599 //calcA(xx, a, m, L);
600 rmmult(xx, Ax, a, L + 1, m + 1, 1, cancel_handler, cancel_state);
601
602 if ( iter >= mit ) {
603 log_printf("Maximum iterations reached\n");
604 converged = false;
605 }
606 }
607 for (i = 0; i < m; i++) {
608 h[i] = a[m - i]/2;
609 h[m + i + 1] = a[i + 1]/2;
610 }
611 h[m] = a[0]*r/2;
612
613 return converged;
614 }
615