qf_poly.cpp
----------------
begin : Mon Jan 02 2006
copyright : (C) 2006 by Vincent Habchi, F5RCS
email : 10.50@free.fr
***************************************************************************/
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <cmath>
#include <cstring>
#include <iostream>
#include <stdlib.h>
#undef _QF_POLY_DEBUG
#include "qf_poly.h"
namespace qf {
poly::poly() : rep(NONE), d(0), krts(0), p(NULL), rts(NULL) {}
poly::poly(unsigned o) : rep(NONE), d(o), krts(0), p(NULL), rts(NULL) {}
poly::poly(qf_float a, qf_float b, qf_float c, unsigned deg) {
#ifdef _QF_POLY_DEBUG
std::cout << "poly (ax^2+bx+c), a = " << a << ", b = " << b << ", c = " << c
<< ", d° = " << deg << "\n";
#endif
if ((deg == 2) && (a == 0)) {
deg = 1;
a = b;
b = c;
}
if ((deg == 1) && (a == 0)) {
deg = 0;
a = b;
}
switch (deg) {
case 0:
d = 0;
p = new qf_float[1];
p[0] = a;
rts = NULL;
krts = a;
rep = BOTH;
break;
case 1:
d = 1;
p = new qf_float[2];
p[0] = b;
p[1] = a;
rts = new qf_float[2];
rts[0] = ROUND_ROOT(-b / a);
rts[1] = 0;
krts = a;
rep = BOTH;
break;
default:
if (deg > 2) {
std::cout << "Warning: poly called with deg > 2.\n";
}
d = 2;
p = new qf_float[3];
p[0] = c;
p[1] = b;
p[2] = a;
rts = new qf_float[4];
krts = a;
qf_float dlt = (b * b - 4 * a * c);
if (dlt == 0) {
rts[0] = rts[2] = ROUND_ROOT(-b / (2 * a));
rts[1] = rts[3] = 0;
} else if (dlt > 0) {
rts[1] = rts[3] = 0;
rts[0] = ROUND_ROOT((-b + sqrt(dlt)) / (2 * a));
rts[2] = ROUND_ROOT(-(b + sqrt(dlt)) / (2 * a));
} else {
rts[0] = rts[2] = ROUND_ROOT(-b / (2 * a));
rts[1] = ROUND_ROOT(sqrt(-dlt) / (2 * a));
rts[3] = -rts[1];
}
rep = BOTH;
break;
}
#ifdef _QF_POLY_DEBUG
std::cout << "poly ax^2+bx+c: ";
this->disp("prod");
#endif
}
poly::poly(int o, const qf_float coef[])
: rep(COEFF), d(o), krts(0), rts(NULL) {
p = new qf_float[o + 1];
for (int i = o; i >= 0; i--) {
p[i] = coef[o - i];
}
#ifdef _QF_POLY_DEBUG
std::cout << "poly coeffs: ";
this->disp("P");
#endif
return;
}
poly::poly(int o, qf_float k, const qf_float r[]) : rep(ROOTS), d(o), p(NULL) {
rts = new qf_float[2 * o];
for (int i = 0; i < 2 * o; i++) {
rts[i] = ROUND_ROOT(r[i]);
}
krts = k;
#ifdef _QF_POLY_DEBUG
std::cout << "poly (roots): ";
this->disp("P");
#endif
return;
}
poly::poly(const poly& P) : rep(P.rep), d(P.d), krts(0), p(NULL), rts(NULL) {
if (rep & COEFF) {
p = new qf_float[d + 1];
memcpy(p, P.p, sizeof(qf_float) * (d + 1));
}
if (rep & ROOTS) {
rts = new qf_float[2 * d];
memcpy(rts, P.rts, sizeof(qf_float) * 2 * d);
krts = P.krts;
}
}
poly& poly::operator=(const poly& P) {
if (&P == this) {
return (*this);
}
d = P.d;
rep = P.rep;
if (p != NULL) {
delete[] p;
}
if (rts != NULL) {
delete[] rts;
}
p = rts = NULL;
krts = 0;
if (rep & COEFF) {
p = new qf_float[d + 1];
memcpy(p, P.p, sizeof(qf_float) * (d + 1));
}
if (rep & ROOTS) {
rts = new qf_float[2 * d];
memcpy(rts, P.rts, sizeof(qf_float) * (2 * d));
krts = P.krts;
}
return (*this);
}
poly::~poly() {
if (p != NULL) {
delete[] p;
}
if (rts != NULL) {
delete[] rts;
}
}
qf_float& poly::operator[](int i) {
if (rep == NONE) {
std::cout << "poly::[] used on a NONE polynom.\n";
exit(-1);
}
if (rep & COEFF) {
return p[i];
}
return rts[i];
}
unsigned poly::deg() {
return d;
}
qf_float poly::k() {
if (rep == NONE) {
std::cout << "poly::k () used on a NONE polynom.\n";
exit(-1);
}
if (rep & ROOTS) {
return krts;
}
return p[d];
}
void poly::spl() {
int i = d;
if (rep == NONE) {
std::cout << "poly::spl () used on a NONE polynom.\n";
exit(-1);
}
if (d == 0) {
return;
}
if (rep == ROOTS) {
return;
}
while (i > 0) {
if (p[i] == 0) {
i--;
} else {
break;
}
}
d = i;
return;
}
poly poly::operator-(void) {
if (rep == NONE) {
std::cout << "poly::unary - used on a NONE polynom.\n";
exit(-1);
}
poly R(d);
if (rep & COEFF) {
R.p = new qf_float[d + 1];
for (unsigned i = 0; i <= d; i++) {
R.p[i] = -p[i];
}
}
if (rep & ROOTS) {
R.rts = new qf_float[2 * d];
memcpy(R.rts, rts, sizeof(qf_float) * 2 * d);
R.krts = -krts;
}
R.rep = rep;
return R;
}
poly operator+(poly P, poly Q) {
if ((Q.rep == NONE) || (P.rep == NONE)) {
std::cout << "poly::+ used on a NONE polynom.\n";
exit(-1);
}
if (Q.d >= P.d) {
poly R(Q);
return R += P;
} else {
poly R(P);
return R += Q;
}
}
poly poly::operator+=(poly P) {
if ((rep == NONE) || (P.rep == NONE)) {
std::cout << "poly::+= used on a NONE polynom.\n";
exit(-1);
}
if (rep == ROOTS) {
to_coeff();
}
if (P.rep == ROOTS) {
P.to_coeff();
}
if (d >= P.d) {
for (unsigned i = 0; i <= P.d; i++) {
p[i] += P.p[i];
}
} else {
qf_float* pp = new qf_float[P.d];
memcpy(pp, P.p, sizeof(qf_float) * P.d);
for (unsigned i = 0; i <= d; i++) {
pp[i] += p[i];
}
delete[] p;
p = pp;
}
if (rep & ROOTS) {
rep = COEFF;
delete[] rts;
rts = NULL;
krts = 0;
}
spl();
return (*this);
}
poly operator-(poly P, poly Q) {
if ((P.rep == NONE) || (Q.rep == NONE)) {
std::cout << "poly::- used on a NONE polynom.\n";
exit(-1);
}
if (P.d >= Q.d) {
poly R(P);
return R -= Q;
} else {
poly R(Q);
return R -= P;
}
}
poly poly::operator-=(poly P) {
if ((rep == NONE) || (P.rep == NONE)) {
std::cout << "poly::-= used on a NONE polynom.\n";
exit(-1);
}
if (rep == ROOTS) {
to_coeff();
}
if (P.rep == ROOTS) {
P.to_coeff();
}
if (d >= P.d) {
for (unsigned i = 0; i <= P.d; i++) {
p[i] -= P.p[i];
}
} else {
qf_float* pp = new qf_float[P.d + 1];
memcpy(pp, P.p, sizeof(qf_float) * (P.d + 1));
for (unsigned i = 0; i <= P.d; i++) {
if (i <= d) {
pp[i] = p[i] - pp[i];
} else {
pp[i] = -pp[i];
}
}
delete[] p;
p = pp;
}
if (rep & ROOTS) {
rep = COEFF;
delete[] rts;
rts = NULL;
krts = 0;
}
spl();
return (*this);
}
poly operator*(poly P, poly Q) {
if ((P.rep == NONE) || (Q.rep == NONE)) {
std::cout << "poly::* used on a NONE polynom.\n";
exit(-1);
}
poly R(P);
R *= Q;
return R;
}
poly operator*(poly P, const qf_float m) {
if (P.rep == NONE) {
std::cout << "poly::* (scalar) used on a NONE polynom.\n";
exit(-1);
}
poly R(P);
R *= m;
return R;
}
poly poly::operator*=(poly P) {
if ((rep == NONE) || (P.rep == NONE)) {
std::cout << "poly::*= () used on a NONE polynom.\n";
exit(-1);
}
if (P.d < 1) {
if (P.rep & COEFF) {
return ((*this) *= P.p[0]);
} else {
return ((*this) *= P.krts);
}
}
if (rep & COEFF) {
if (!(P.rep & COEFF)) {
P.to_coeff();
}
qf_float* q = new qf_float[d + P.d + 1];
memset(q, 0, sizeof(qf_float) * (d + P.d + 1));
for (unsigned i = 0; i <= d; i++) {
for (unsigned j = 0; j <= P.d; j++) {
q[i + j] += p[i] * P.p[j];
}
}
delete[] p;
p = q;
}
if (rep & ROOTS) {
if (!(P.rep & ROOTS)) {
P.to_roots();
}
qf_float* rtsp = new qf_float[2 * (d + P.d)];
memcpy(rtsp, rts, sizeof(qf_float) * 2 * d);
memcpy(&rtsp[2 * d], P.rts, sizeof(qf_float) * 2 * P.d);
delete[] rts;
rts = rtsp;
krts *= P.krts;
}
d += P.d;
return (*this);
}
poly poly::operator*=(const qf_float m) {
if (rep == NONE) {
std::cout << "poly::*= (scalar) used on a NONE polynom.\n";
exit(-1);
}
if (m == 0) {
krts = d = 0;
delete[] rts;
delete[] p;
rts = p = NULL;
rep = COEFF;
return (*this);
}
if (m == 1) {
return (*this);
}
if (rep & COEFF) {
for (unsigned i = 0; i <= d; i++) {
p[i] *= m;
}
}
if (rep & ROOTS) {
krts *= m;
}
return (*this);
}
bool poly::operator==(poly P) {
if (rep == NONE) {
return false;
}
if (d != P.d) {
return false;
}
if (rep == ROOTS) {
to_coeff();
}
if (P.rep == ROOTS) {
P.to_coeff();
}
for (unsigned i = 0; i <= d; i++) {
if (p[i] != P.p[i]) {
return false;
}
}
return true;
}
bool poly::operator!=(poly P) {
return !((*this) == P);
}
bool poly::is_null(void) {
if (rep == NONE) {
std::cout << "Warning poly::is_null() on a NONE polynom.\n";
return true;
}
if (d == 0) {
return true;
}
if (d > 1) {
return false;
}
if (rep & ROOTS) {
return (krts == 0);
} else {
return (p[0] == 0);
}
}
poly poly::operator<<(unsigned n) {
if (rep == NONE) {
std::cout << "poly::<< used on a NONE polynom.\n";
exit(-1);
}
if (n == 0) {
return (*this);
}
if (d < n) {
return poly(0, 0, 0, 0);
}
else if (d == n) {
return poly(p[d], 0, 0, 0);
}
poly R;
if (rep & COEFF) {
for (unsigned i = 0; i < n; i++) {
if (p[i] != 0) {
std::cout << "Warning: << by " << n << " asked for but only " << i
<< " possible.\n";
n = i;
}
}
R.p = new qf_float[d - n + 1];
memcpy(R.p, &(p[n]), sizeof(qf_float) * (d - n + 1));
R.d = d - n;
}
if (rep & ROOTS) {
int nbz = n;
R.rts = new qf_float[2 * d];
R.krts = krts;
for (unsigned i = 0, j = 0; i < 2 * d; i += 2) {
if ((rts[i] == 0) && (rts[i + 1] == 0) && (nbz != 0)) {
nbz--;
}
else {
R.rts[j] = rts[i];
R.rts[j + 1] = rts[i + 1];
j += 2;
}
}
R.d = d - n;
if (nbz != 0) {
std::cout << "Warning: << by " << n << " asked for but only " << n - nbz
<< " possible.\n";
R.d += nbz;
}
}
R.rep = rep;
return R;
}
poly poly::operator>>(unsigned n) {
if (rep == NONE) {
std::cout << "poly::>> used on a NONE polynom.\n";
exit(-1);
}
if (n == 0) {
return (*this);
}
poly R(d + n);
if (rep & COEFF) {
R.p = new qf_float[d + n + 1];
memset(R.p, 0, sizeof(qf_float) * n);
memcpy(&(R.p[n]), p, sizeof(qf_float) * (d + 1));
}
if (rep & ROOTS) {
R.rts = new qf_float[2 * (d + n)];
memset(R.rts, 0, sizeof(qf_float) * 2 * n);
memcpy(&(R.rts[2 * n]), rts, sizeof(qf_float) * 2 * d);
R.krts = krts;
}
R.rep = rep;
return R;
}
poly poly::odd() {
qpr orep = rep;
if (rep == NONE) {
std::cout << "poly::odd () used on a NONE polynom.\n";
exit(-1);
}
if (rep == ROOTS) {
to_coeff();
}
poly P(*this);
int i = d;
if ((i % 2) == 1) {
i--;
}
for (; i >= 0; i -= 2) {
P.p[i] = 0;
}
P.spl();
if ((orep == ROOTS) || (orep == BOTH)) {
P.to_roots();
}
return P;
}
poly poly::even() {
qpr orep = rep;
if (rep == NONE) {
std::cout << "poly::even () used on a NONE polynom.\n";
exit(-1);
}
if (rep == ROOTS) {
to_coeff();
}
poly P(*this);
int i = d;
if (i == 0) {
return P;
}
if ((i % 2) == 0) {
i--;
}
for (; i >= 1; i -= 2) {
P.p[i] = 0;
}
P.spl();
if ((orep == ROOTS) || (orep == BOTH)) {
P.to_roots();
}
return P;
}
poly poly::mnx() {
if (rep == NONE) {
std::cout << "poly::mnx () used on a NONE polynom.\n";
exit(-1);
}
poly P(d);
if ((rep == COEFF) || (rep == BOTH)) {
P.p = new qf_float[d + 1];
for (unsigned i = 0; i <= d; i++) {
P.p[i] = ((i % 2) == 0 ? p[i] : -p[i]);
}
}
if ((rep == ROOTS) || (rep == BOTH)) {
P.rts = new qf_float[2 * d];
for (unsigned i = 0; i < 2 * d; i++) {
P.rts[i] = -rts[i];
}
P.krts = ((d % 2) == 0 ? krts : -krts);
}
P.rep = rep;
return P;
}
poly poly::hsq() {
if (rep == NONE) {
std::cout << "poly::hsq () used on a NONE polynom.\n";
exit(-1);
}
poly P(*this);
P *= mnx();
return P;
}
poly poly::sqr() {
if (rep == NONE) {
std::cout << "poly::sqr () used on a NONE polynom.\n";
exit(-1);
}
if (rep == ROOTS) {
to_coeff();
}
poly P(even());
if ((*this) != P) {
std::cout << "Error! poly::sqr () used on a non-square polynom.\n";
exit(-1);
}
poly Q(d / 2);
Q.p = new qf_float[d / 2 + 1];
for (unsigned i = 0; i <= d / 2; i++) {
Q.p[i] = p[2 * i];
}
Q.rep = COEFF;
if ((rep == BOTH) || (rep == ROOTS)) {
Q.to_roots();
}
return Q;
}
void poly::div(qf_float r, qf_float i) {
if (rep == NONE) {
std::cout << "poly::div () used on a NONE polynom.\n";
exit(-1);
}
i = std::abs(i);
if (d == 0) {
std::cout << "Warning: Div () called on a constant polynom.\n";
return;
}
if ((d == 1) && (i != 0)) {
std::cout << "Div () real/complex error.\n";
return;
}
if (d == 1) {
if (((rep == ROOTS) || (rep == BOTH)) &&
(std::abs(rts[0] - r) < ROOT_TOL) && (std::abs(rts[1]) < ROOT_TOL)) {
d = 0;
delete[] rts;
rts = NULL;
delete[] p;
p = new qf_float[1];
p[0] = krts;
rep = BOTH;
return;
}
if ((rep == COEFF) && (std::abs(p[0] / p[1] + r) < ROOT_TOL)) {
qf_float temp = p[1];
d = 0;
delete[] p;
p = new qf_float[1];
p[0] = temp;
delete[] rts;
krts = temp;
rep = BOTH;
return;
}
std::cout << "Warning: Div () error. Specified factor not found.\n";
return;
}
if (rep == COEFF) {
to_roots();
}
qf_float* rtsp = new qf_float[2 * d];
bool found = false;
for (unsigned k = 0, j = 0; k < 2 * d; k += 2) {
#ifdef _QF_POLY_DEBUG
std::cout << "Div: " << std::abs(rts[k] - r) << " "
<< std::abs(rts[k + 1] - i) << "\n";
#endif
if ((std::abs(rts[k] - r) > ROOT_TOL) ||
(std::abs(rts[k + 1] - i) > ROOT_TOL)) {
rtsp[j] = rts[k];
rtsp[j + 1] = rts[k + 1];
j += 2;
}
else {
if (i != 0) {
k += 2;
}
found = true;
}
}
if (!found) {
delete[] rtsp;
std::cout << "Div () : factor not found! \n";
return;
}
delete[] rts;
rts = rtsp;
if (i == 0) {
d--;
} else {
d -= 2;
}
rep = ROOTS;
}
void smpf(poly& N, poly& D) {
unsigned dN = N.d;
unsigned dD = D.d;
unsigned i, j;
std::cout << "dN: " << dN << " dD : " << dD << '\n';
bool* Ln = new bool[dN];
bool* Ld = new bool[dD];
for (i = 0; i < dN; i++) {
Ln[i] = true;
}
for (i = 0; i < dD; i++) {
Ld[i] = true;
}
if (N.rep == COEFF) {
N.to_roots();
}
if (D.rep == COEFF) {
D.to_roots();
}
unsigned ndN = dN;
unsigned ndD = dD;
for (i = 0; i < 2 * dN; i += 2) {
for (j = 0; j < 2 * dD; j += 2) {
std::cout << "N.rts[" << i << "] = " << N.rts[i] << ", ";
std::cout << "D.rts[" << j << "] = " << D.rts[j] << "\n";
std::cout << "N.rts[" << i + 1 << "] = " << N.rts[i + 1] << ", ";
std::cout << "D.rts[" << j + 1 << "] = " << D.rts[j + 1] << "\n";
if ((Ld[j / 2]) && (std::abs(N.rts[i] - D.rts[j]) < ROOT_TOL) &&
(std::abs(N.rts[i + 1] - D.rts[j + 1]) < ROOT_TOL)) {
Ln[i / 2] = false;
Ld[j / 2] = false;
ndN--;
ndD--;
std::cout << "Common root: (" << D.rts[j] << ", " << D.rts[j + 1]
<< "i)\n";
break;
}
}
}
if (ndN != dN) {
qf_float* nrN = new qf_float[2 * ndN];
qf_float* nrD = new qf_float[2 * ndD];
for (i = 0, j = 0; i < 2 * dN; i += 2) {
if (Ln[i / 2]) {
nrN[j] = N.rts[i];
nrN[j + 1] = N.rts[i + 1];
j += 2;
}
}
delete[] N.rts;
N.rts = nrN;
N.d = ndN;
N.rep = ROOTS;
for (i = 0, j = 0; i < 2 * D.d; i += 2) {
if (Ld[i / 2]) {
nrD[j] = D.rts[i];
nrD[j + 1] = D.rts[i + 1];
j += 2;
}
}
delete[] D.rts;
D.rts = nrD;
D.d = ndD;
D.rep = ROOTS;
N.to_coeff();
D.to_coeff();
std::cout << "ndN: " << ndN << " ndD : " << ndD << '\n';
}
delete[] Ln;
delete[] Ld;
}
void poly::hurw() {
if (rep == NONE) {
std::cout << "poly::hurw () used on a NONE polynom.\n";
return;
}
if (rep == COEFF) {
to_roots();
}
qf_float* rtsp = new qf_float[2 * d];
unsigned j = 0;
for (unsigned i = 0; i < 2 * d; i += 2) {
if (rts[i] > 0) {
if (rts[i + 1] == 0) {
continue;
}
else {
i += 2;
continue;
}
}
else {
rtsp[j] = rts[i];
rtsp[j + 1] = rts[i + 1];
j += 2;
}
}
delete[] rts;
rts = rtsp;
d = j / 2;
if (krts < 0) {
krts = -krts;
}
rep = ROOTS;
}
qf_float poly::eval(qf_float a) {
if (rep == NONE) {
std::cout << "poly::eval () used on a NONE polynom.\n";
return 0;
}
if ((rep == COEFF) || (rep == BOTH)) {
if (d == 0) {
return p[0];
}
qf_float r = p[d];
for (int i = d - 1; i >= 0; i--) {
r = r * a + p[i];
}
return r;
}
if (d == 0) {
return krts;
}
qf_float r = krts;
for (unsigned i = 0; i < 2 * d; i += 2) {
if (rts[i + 1] == 0) {
r *= (a - rts[i]);
}
else {
qf_float m = rts[i] * rts[i] + rts[i + 1] * rts[i + 1];
qf_float n = -2 * rts[i];
r *= (a * a + n * a + m);
i += 2;
}
}
return r;
}
qf_float poly::evalX2(qf_float c) {
return (sqr()).eval(c);
}
#ifdef _QF_POLY_DEBUG
void poly::disp(const char* name) {
if (rep == NONE) {
std::cout << name << "(x) is not initalized.\n";
return;
}
if ((rep == COEFF) || (rep == BOTH)) {
std::cout << name << "(x) = ";
disp_c();
}
if ((rep == ROOTS) || (rep == BOTH)) {
std::cout << name << "(x) = ";
disp_r();
}
}
#else
void poly::disp(const char*) {}
#endif
void poly::disp_c(void) {
if (d == 0) {
std::cout << p[0] << '\n';
return;
}
if (p[d] < 0) {
std::cout << "-";
}
if (std::abs(p[d]) != 1) {
std::cout << std::abs(p[d]);
}
if (d == 1) {
std::cout << " x ";
}
else {
std::cout << " x^" << d << ' ';
for (unsigned i = d - 1; i > 1; i--) {
if (p[i] == 0) {
continue;
}
if (p[i] > 0) {
std::cout << "+ ";
} else {
std::cout << "- ";
}
if (std::abs(p[i]) != 1) {
std::cout << std::abs(p[i]);
}
std::cout << " x^" << i << ' ';
}
if (p[1] != 0) {
if (p[1] > 0) {
std::cout << "+ ";
} else {
std::cout << "- ";
}
if (std::abs(p[1]) != 1) {
std::cout << std::abs(p[1]);
}
std::cout << " x ";
}
}
if (p[0] != 0) {
if (p[0] > 0) {
std::cout << "+ ";
} else {
std::cout << "- ";
}
std::cout << std::abs(p[0]);
}
std::cout << '\n';
}
void poly::disp_r(void) {
if (krts == -1) {
std::cout << "- ";
}
else if (krts != 1) {
std::cout << krts << ' ';
}
for (unsigned i = 0; i < 2 * d; i += 2) {
if (rts[i + 1] == 0) {
std::cout << "(X";
if (rts[i] == 0) {
std::cout << ") ";
}
else if (rts[i] < 0) {
std::cout << " + " << std::abs(rts[i]) << ") ";
}
else {
std::cout << " - " << rts[i] << ") ";
}
} else {
std::cout << "(X^2 ";
qf_float m = rts[i] * rts[i] + rts[i + 1] * rts[i + 1];
qf_float n = 2 * rts[i];
if (n > 0) {
std::cout << "- " << n << "X ";
}
if (n < 0) {
std::cout << "+ " << std::abs(n) << "X ";
}
std::cout << "+ " << m << ") ";
i += 2;
}
}
std::cout << '\n';
}
the roots (product form) P(X) = k * prod (X - r[i]) */
void poly::to_coeff(void) {
if (rep == NONE) {
std::cout << "poly::to_coeff () used on a NONE polynom.\n";
exit(-1);
}
if ((rep == COEFF) || (rep == BOTH)) {
return;
}
if (p != NULL) {
delete[] p;
}
rep = BOTH;
p = new qf_float[1];
p[0] = krts;
if ((rts == NULL) || (d == 0)) {
return;
}
if (d == 1) {
p = new qf_float[2];
p[0] = -krts * rts[0];
p[1] = krts;
return;
}
unsigned r = 0;
do {
if (rts[2 * r + 1] == 0) {
qf_float* q = new qf_float[r + 2];
q[0] = 0;
memcpy(&(q[1]), p, sizeof(qf_float) * (r + 1));
for (unsigned j = 0; j < r + 1; j++) {
q[j] -= rts[2 * r] * p[j];
}
delete[] p;
p = q;
r++;
}
else {
qf_float m, n;
qf_float* q = new qf_float[r + 3];
qf_float* s = new qf_float[r + 2];
m = rts[2 * r] * rts[2 * r] + rts[2 * r + 1] * rts[2 * r + 1];
n = -2 * rts[2 * r];
q[0] = q[1] = s[0] = 0;
memcpy(&(q[2]), p, sizeof(qf_float) * (r + 1));
memcpy(&(s[1]), p, sizeof(qf_float) * (r + 1));
for (unsigned j = 0; j < r + 1; j++) {
q[j] += n * s[j] + m * p[j];
}
q[r + 1] += n * s[r + 1];
delete[] p;
delete[] s;
p = q;
r += 2;
}
} while (r < d);
(*this).disp("poly::to_coeff: ");
}
p(x) = a_{n-1} * x^{n-1} + ... a_{2} * x^{2} + a_{1} * x + a_{0}
The results are stored in the vector rst, real part followed by
imaginary part for each complex root. It return zero on success
and non-zero otherwise. */
void poly::to_roots(void) {
if (rep == NONE) {
std::cout << "poly::to_roots () used on a NONE polynom.\n";
exit(-1);
}
if ((rep == ROOTS) || (rep == BOTH)) {
return;
}
if (d == 0) {
return;
}
matrix m(d);
if (rts != NULL) {
delete[] rts;
}
rts = new qf_float[2 * d];
krts = p[d];
scm(m);
bcm(m);
qrc(m, rts);
for (unsigned i = 0; i < 2 * d; i++) {
if (std::abs(rts[i]) <= ROOT_PREC) {
rts[i] = 0;
} else {
rts[i] = ROUND_ROOT(rts[i]);
}
}
rep = BOTH;
}
void poly::scm(matrix& m) {
unsigned int i, j;
for (i = 0; i < m.n; i++) {
for (j = 0; j < m.n; j++) {
m(i, j) = 0;
}
}
for (i = 1; i < m.n; i++) {
m(i, i - 1) = 1;
}
for (i = 0; i < m.n; i++) {
m(i, m.n - 1) = -p[i] / p[m.n];
}
}
void poly::bcm(matrix& m) {
int not_converged = 1;
qf_float row_norm = 0;
qf_float col_norm = 0;
while (not_converged) {
unsigned int i, j;
qf_float g, f, s;
not_converged = 0;
for (i = 0; i < m.n; i++) {
if (i != m.n - 1) {
col_norm = std::abs(m(i + 1, i));
}
else {
col_norm = 0;
for (j = 0; j < m.n - 1; j++) {
col_norm += std::abs(m(j, m.n - 1));
}
}
if (i == 0) {
row_norm = std::abs(m(0, m.n - 1));
}
else if (i == m.n - 1) {
row_norm = std::abs(m(i, i - 1));
}
else {
row_norm = std::abs(m(i, i - 1)) + std::abs(m(i, m.n - 1));
}
if ((col_norm == 0) || (row_norm == 0)) {
continue;
}
g = row_norm / RADIX;
f = 1;
s = col_norm + row_norm;
while (col_norm < g) {
f *= RADIX;
col_norm *= RADIX2;
}
g = row_norm * RADIX;
while (col_norm > g) {
f /= RADIX;
col_norm /= RADIX2;
}
if ((row_norm + col_norm) < 0.95 * s * f) {
not_converged = 1;
g = 1 / f;
if (i == 0) {
m(0, m.n - 1) *= g;
}
else {
m(i, i - 1) *= g;
m(i, m.n - 1) *= g;
}
if (i == m.n - 1) {
for (j = 0; j < m.n; j++) {
m(j, i) *= f;
}
} else {
m(i + 1, i) *= f;
}
}
}
}
}
int poly::qrc(matrix& h, qf_float* zroot) {
qf_float t = 0;
unsigned int iterations, e, i, j, k, m;
qf_float w, x, y, s, z;
qf_float p = 0, q = 0, r = 0;
int notlast;
unsigned int n = d;
next_root:
if (n == 0) {
return 0;
}
iterations = 0;
next_iteration:
for (e = n; e >= 2; e--) {
qf_float a1 = std::abs(h(e - 1, e - 2));
qf_float a2 = std::abs(h(e - 2, e - 2));
qf_float a3 = std::abs(h(e - 1, e - 1));
if (a1 <= EPSILON * (a2 + a3)) {
break;
}
}
x = h(n - 1, n - 1);
if (e == n) {
SET_COMPLEX_PACKED(zroot, n - 1, x + t, 0);
n--;
goto next_root;
}
y = h(n - 2, n - 2);
w = h(n - 2, n - 1) * h(n - 1, n - 2);
if (e == n - 1) {
p = (y - x) / 2;
q = p * p + w;
y = sqrt(std::abs(q));
x += t;
if (q > 0) {
if (p < 0) {
y = -y;
}
y += p;
SET_COMPLEX_PACKED(zroot, n - 1, x - w / y, 0);
SET_COMPLEX_PACKED(zroot, n - 2, x + y, 0);
}
else {
SET_COMPLEX_PACKED(zroot, n - 1, x + p, -y);
SET_COMPLEX_PACKED(zroot, n - 2, x + p, y);
}
n -= 2;
goto next_root;
}
if (iterations == MAX_ITERATIONS) {
return -1;
}
if (iterations % 10 == 0 && iterations > 0) {
t += x;
for (i = 0; i < n; i++) {
h(i, i) -= x;
}
s = std::abs(h(n - 1, n - 2)) + std::abs(h(n - 2, n - 3));
y = 0.75 * s;
x = y;
w = -0.4375 * s * s;
}
iterations++;
for (m = n - 2; m >= e; m--) {
qf_float a1, a2, a3;
z = h(m - 1, m - 1);
r = x - z;
s = y - z;
p = h(m - 1, m) + (r * s - w) / h(m, m - 1);
q = h(m, m) - z - r - s;
r = h(m + 1, m);
s = std::abs(p) + std::abs(q) + std::abs(r);
p /= s;
q /= s;
r /= s;
if (m == e) {
break;
}
a1 = std::abs(h(m - 1, m - 2));
a2 = std::abs(h(m - 2, m - 2));
a3 = std::abs(h(m, m));
if (a1 * (std::abs(q) + std::abs(r)) <= EPSILON * std::abs(p) * (a2 + a3)) {
break;
}
}
for (i = m + 2; i <= n; i++) {
h(i - 1, i - 3) = 0;
}
for (i = m + 3; i <= n; i++) {
h(i - 1, i - 4) = 0;
}
for (k = m; k <= n - 1; k++) {
notlast = (k != n - 1);
if (k != m) {
p = h(k - 1, k - 2);
q = h(k, k - 2);
r = notlast ? h(k + 1, k - 2) : 0;
x = std::abs(p) + std::abs(q) + std::abs(r);
if (x == 0) {
continue;
}
p /= x;
q /= x;
r /= x;
}
s = sqrt(p * p + q * q + r * r);
if (p < 0) {
s = -s;
}
if (k != m) {
h(k - 1, k - 2) = -s * x;
} else if (e != m) {
h(k - 1, k - 2) *= -1;
}
p += s;
x = p / s;
y = q / s;
z = r / s;
q /= p;
r /= p;
for (j = k; j <= n; j++) {
p = h(k - 1, j - 1) + q * h(k, j - 1);
if (notlast) {
p += r * h(k + 1, j - 1);
h(k + 1, j - 1) -= p * z;
}
h(k, j - 1) -= p * y;
h(k - 1, j - 1) -= p * x;
}
j = (k + 3 < n) ? (k + 3) : n;
for (i = e; i <= j; i++) {
p = x * h(i - 1, k - 1) + y * h(i - 1, k);
if (notlast) {
p += z * h(i - 1, k + 1);
h(i - 1, k + 1) -= p * r;
}
h(i - 1, k) -= p * q;
h(i - 1, k - 1) -= p;
}
}
goto next_iteration;
}
}