/* qrbdv.c CCMATH mathematics library source code. * * Copyright (C) 2000 Daniel A. Atkinson All rights reserved. * This code may be redistributed under the terms of the GNU library * public license (LGPL). ( See the lgpl.license file for details.) * ------------------------------------------------------------------------ */ #include "ccmath.h" int qrbdv(double *dm, double *em, double *um, int mm, double *vm, int m) { int i, j, k, n, jj, nm; double u, x, y, a, b, c, s, t, w, *p, *q; for (j = 1, t = fabs(dm[0]); j < m; ++j) if ((s = fabs(dm[j]) + fabs(em[j - 1])) > t) t = s; t *= 1.e-15; n = 100 * m; nm = m; for (j = 0; m > 1 && j < n; ++j) { for (k = m - 1; k > 0; --k) { if (fabs(em[k - 1]) < t) break; if (fabs(dm[k - 1]) < t) { for (i = k, s = 1., c = 0.; i < m; ++i) { a = s * em[i - 1]; b = dm[i]; em[i - 1] *= c; dm[i] = u = sqrt(a * a + b * b); s = -a / u; c = b / u; for (jj = 0, p = um + k - 1; jj < mm; ++jj, p += mm) { q = p + i - k + 1; w = c * *p + s * *q; *q = c * *q - s * *p; *p = w; } } break; } } y = dm[k]; x = dm[m - 1]; u = em[m - 2]; a = (y + x) * (y - x) - u * u; s = y * em[k]; b = s + s; u = sqrt(a * a + b * b); if (u != 0.) { c = sqrt((u + a) / (u + u)); if (c != 0.) s /= (c * u); else s = 1.; for (i = k; i < m - 1; ++i) { b = em[i]; if (i > k) { a = s * em[i]; b *= c; em[i - 1] = u = sqrt(x * x + a * a); c = x / u; s = a / u; } a = c * y + s * b; b = c * b - s * y; for (jj = 0, p = vm + i; jj < nm; ++jj, p += nm) { w = c * *p + s * *(p + 1); *(p + 1) = c * *(p + 1) - s * *p; *p = w; } s *= dm[i + 1]; dm[i] = u = sqrt(a * a + s * s); y = c * dm[i + 1]; c = a / u; s /= u; x = c * b + s * y; y = c * y - s * b; for (jj = 0, p = um + i; jj < mm; ++jj, p += mm) { w = c * *p + s * *(p + 1); *(p + 1) = c * *(p + 1) - s * *p; *p = w; } } } em[m - 2] = x; dm[m - 1] = y; if (fabs(x) < t) --m; if (m == k + 1) --m; } return j; }