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 <stdlib.h>
#include <string.h>
#include <cmath>
#include <iostream>
#undef _QF_POLY_DEBUG
#include "qf_poly.h"
qf_poly::qf_poly () :
rep (NONE), d (0), krts (0), p (NULL), rts (NULL) {
}
qf_poly::qf_poly (unsigned o) :
rep (NONE), d (o), krts (0), p (NULL), rts (NULL) {
}
qf_poly::qf_poly (qf_double_t a, qf_double_t b, qf_double_t c, unsigned deg) {
#ifdef _QF_POLY_DEBUG
std::cout << "qf_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_double_t[1];
p[0] = a;
rts = NULL;
krts = a;
rep = BOTH;
break;
case 1:
d = 1;
p = new qf_double_t[2];
p[0] = b;
p[1] = a;
rts = new qf_double_t[2];
rts[0] = ROUND_ROOT (-b / a);
rts[1] = 0;
krts = a;
rep = BOTH;
break;
default:
if (deg > 2)
std::cout << "Warning: qf_poly called with deg > 2.\n";
d = 2;
p = new qf_double_t[3];
p[0] = c;
p[1] = b;
p[2] = a;
rts = new qf_double_t[4];
krts = a;
qf_double_t 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 << "qf_poly ax^2+bx+c: ";
this->disp ("prod");
#endif
}
qf_poly::qf_poly (int o, const qf_double_t coef[]) :
rep (COEFF), d (o), krts (0), rts (NULL) {
p = new qf_double_t[o + 1];
for (int i = o; i >= 0; i--) p[i] = coef[o - i];
#ifdef _QF_POLY_DEBUG
std::cout << "qf_poly coeffs: ";
this->disp ("P");
#endif
return;
}
qf_poly::qf_poly (int o, qf_double_t k, const qf_double_t r[]) :
rep (ROOTS), d (o), p (NULL) {
rts = new qf_double_t[2 * o];
for (int i = 0; i < 2 * o; i++)
rts[i] = ROUND_ROOT (r[i]);
krts = k;
#ifdef _QF_POLY_DEBUG
std::cout << "qf_poly (roots): ";
this->disp ("P");
#endif
return;
}
qf_poly::qf_poly (const qf_poly & P) :
rep (P.rep), d (P.d), krts (0), p (NULL), rts (NULL) {
if (rep & COEFF) {
p = new qf_double_t[d + 1];
memcpy (p, P.p, sizeof (qf_double_t) * (d + 1));
}
if (rep & ROOTS) {
rts = new qf_double_t[2 * d];
memcpy (rts, P.rts, sizeof (qf_double_t) * 2 * d);
krts = P.krts;
}
}
qf_poly & qf_poly::operator = (const qf_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_double_t[d + 1];
memcpy (p, P.p, sizeof (qf_double_t) * (d + 1));
}
if (rep & ROOTS) {
rts = new qf_double_t[2 * d];
memcpy (rts, P.rts, sizeof (qf_double_t) * (2 * d));
krts = P.krts;
}
return (*this);
}
qf_poly::~qf_poly () {
if (p != NULL) delete[] p;
if (rts != NULL) delete[] rts;
}
qf_double_t & qf_poly::operator [] (int i) {
if (rep == NONE) {
std::cout << "qf_poly::[] used on a NONE polynom.\n";
exit (-1);
}
if (rep & COEFF)
return p[i];
return rts[i];
}
unsigned qf_poly::deg () {
return d;
}
qf_double_t qf_poly::k () {
if (rep == NONE) {
std::cout << "qf_poly::k () used on a NONE polynom.\n";
exit (-1);
}
if (rep & ROOTS)
return krts;
return p[d];
}
void qf_poly::spl () {
int i = d;
if (rep == NONE) {
std::cout << "qf_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;
}
qf_poly qf_poly::operator - (void) {
if (rep == NONE) {
std::cout << "qf_poly::unary - used on a NONE polynom.\n";
exit (-1);
}
qf_poly R (d);
if (rep & COEFF) {
R.p = new qf_double_t[d + 1];
for (unsigned i = 0; i <= d; i++)
R.p[i] = -p[i];
}
if (rep & ROOTS) {
R.rts = new qf_double_t[2 * d];
memcpy (R.rts, rts, sizeof (qf_double_t) * 2 * d);
R.krts = -krts;
}
R.rep = rep;
return R;
}
qf_poly operator + (qf_poly P, qf_poly Q) {
if ((Q.rep == NONE) || (P.rep == NONE)) {
std::cout << "qf_poly::+ used on a NONE polynom.\n";
exit (-1);
}
if (Q.d >= P.d) {
qf_poly R (Q);
return R += P;
}
else {
qf_poly R (P);
return R += Q;
}
}
qf_poly qf_poly::operator += (qf_poly P) {
if ((rep == NONE) || (P.rep == NONE)) {
std::cout << "qf_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_double_t * pp = new qf_double_t[P.d];
memcpy (pp, P.p, sizeof (qf_double_t) * 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);
}
qf_poly operator - (qf_poly P, qf_poly Q) {
if ((P.rep == NONE) || (Q.rep == NONE)) {
std::cout << "qf_poly::- used on a NONE polynom.\n";
exit (-1);
}
if (P.d >= Q.d) {
qf_poly R (P);
return R -= Q;
}
else {
qf_poly R (Q);
return R -= P;
}
}
qf_poly qf_poly::operator -= (qf_poly P) {
if ((rep == NONE) || (P.rep == NONE)) {
std::cout << "qf_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_double_t * pp = new qf_double_t[P.d + 1];
memcpy (pp, P.p, sizeof (qf_double_t) * (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);
}
qf_poly operator * (qf_poly P, qf_poly Q) {
if ((P.rep == NONE) || (Q.rep == NONE)) {
std::cout << "qf_poly::* used on a NONE polynom.\n";
exit (-1);
}
qf_poly R (P);
R *= Q;
return R;
}
qf_poly operator * (qf_poly P, const qf_double_t m) {
if (P.rep == NONE) {
std::cout << "qf_poly::* (scalar) used on a NONE polynom.\n";
exit (-1);
}
qf_poly R (P);
R *= m;
return R;
}
qf_poly qf_poly::operator *= (qf_poly P) {
if ((rep == NONE) || (P.rep == NONE)) {
std::cout << "qf_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_double_t * q = new qf_double_t[d + P.d + 1];
memset (q, 0, sizeof (qf_double_t) * (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_double_t * rtsp = new qf_double_t[2 * (d + P.d)];
memcpy (rtsp, rts, sizeof (qf_double_t) * 2 * d);
memcpy (&rtsp[2 * d], P.rts, sizeof (qf_double_t) * 2 * P.d);
delete[] rts;
rts = rtsp;
krts *= P.krts;
}
d += P.d;
return (*this);
}
qf_poly qf_poly::operator *= (const qf_double_t m) {
if (rep == NONE) {
std::cout << "qf_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 qf_poly::operator == (qf_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 qf_poly::operator != (qf_poly P) {
return !((*this) == P);
}
bool qf_poly::is_null (void) {
if (rep == NONE) {
std::cout << "Warning qf_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);
}
qf_poly qf_poly::operator << (unsigned n) {
if (rep == NONE) {
std::cout << "qf_poly::<< used on a NONE polynom.\n";
exit (-1);
}
if (n == 0)
return (*this);
if (d < n)
return qf_poly (0, 0, 0, 0);
else if (d == n)
return qf_poly (p[d], 0, 0, 0);
qf_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_double_t[d - n + 1];
memcpy (R.p, &(p[n]), sizeof (qf_double_t) * (d - n + 1));
R.d = d - n;
}
if (rep & ROOTS) {
int nbz = n;
R.rts = new qf_double_t[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;
}
qf_poly qf_poly::operator >> (unsigned n) {
if (rep == NONE) {
std::cout << "qf_poly::>> used on a NONE polynom.\n";
exit (-1);
}
if (n == 0)
return (*this);
qf_poly R (d + n);
if (rep & COEFF) {
R.p = new qf_double_t[d + n + 1];
memset (R.p, 0, sizeof (qf_double_t) * n);
memcpy (&(R.p[n]), p, sizeof (qf_double_t) * (d + 1));
}
if (rep & ROOTS) {
R.rts = new qf_double_t[2 * (d + n)];
memset (R.rts, 0, sizeof (qf_double_t) * 2 * n);
memcpy (&(R.rts[2 * n]), rts, sizeof (qf_double_t) * 2 * d);
R.krts = krts;
}
R.rep = rep;
return R;
}
qf_poly qf_poly::odd () {
qpr orep = rep;
if (rep == NONE) {
std::cout << "qf_poly::odd () used on a NONE polynom.\n";
exit (-1);
}
if (rep == ROOTS)
to_coeff ();
qf_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;
}
qf_poly qf_poly::even () {
qpr orep = rep;
if (rep == NONE) {
std::cout << "qf_poly::even () used on a NONE polynom.\n";
exit (-1);
}
if (rep == ROOTS)
to_coeff ();
qf_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;
}
qf_poly qf_poly::mnx () {
if (rep == NONE) {
std::cout << "qf_poly::mnx () used on a NONE polynom.\n";
exit (-1);
}
qf_poly P (d);
if ((rep == COEFF) || (rep == BOTH)) {
P.p = new qf_double_t[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_double_t[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;
}
qf_poly qf_poly::hsq () {
if (rep == NONE) {
std::cout << "qf_poly::hsq () used on a NONE polynom.\n";
exit (-1);
}
qf_poly P (*this);
P *= mnx ();
return P;
}
qf_poly qf_poly::sqr () {
if (rep == NONE) {
std::cout << "qf_poly::sqr () used on a NONE polynom.\n";
exit (-1);
}
if (rep == ROOTS)
to_coeff ();
qf_poly P (even ());
if ((*this) != P) {
std::cout << "Error! qf_poly::sqr () used on a non-square polynom.\n";
exit (-1);
}
qf_poly Q (d / 2);
Q.p = new qf_double_t[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 qf_poly::div (qf_double_t r, qf_double_t i) {
if (rep == NONE) {
std::cout << "qf_poly::div () used on a NONE polynom.\n";
exit (-1);
}
i = fabs (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))
&& (fabs (rts[0] - r) < ROOT_TOL)
&& (fabs (rts[1]) < ROOT_TOL)) {
d = 0;
delete[] rts;
rts = NULL;
delete[] p;
p = new qf_double_t[1];
p[0] = krts;
rep = BOTH;
return;
}
if ((rep == COEFF) && (fabs (p[0] / p[1] + r) < ROOT_TOL)) {
qf_double_t temp = p[1];
d = 0;
delete[] p;
p = new qf_double_t[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_double_t * rtsp = new qf_double_t[2 * d];
bool found = false;
for (unsigned k = 0, j = 0; k < 2 * d; k += 2) {
#ifdef _QF_POLY_DEBUG
std::cout << "Div: " << fabs (rts[k] - r) << " "
<< fabs (rts[k + 1] - i) << "\n";
#endif
if ((fabs (rts[k] - r) > ROOT_TOL) || (fabs (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 (qf_poly & N, qf_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]) &&
(fabs (N.rts[i] - D.rts[j]) < ROOT_TOL) &&
(fabs (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_double_t * nrN = new qf_double_t[2 * ndN];
qf_double_t * nrD = new qf_double_t[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 qf_poly::hurw () {
if (rep == NONE) {
std::cout << "qf_poly::hurw () used on a NONE polynom.\n";
return;
}
if (rep == COEFF)
to_roots ();
qf_double_t * rtsp = new qf_double_t[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_double_t qf_poly::eval (qf_double_t a) {
if (rep == NONE) {
std::cout << "qf_poly::eval () used on a NONE polynom.\n";
return 0;
}
if ((rep == COEFF) || (rep == BOTH)) {
if (d == 0)
return p[0];
qf_double_t r = p[d];
for (int i = d - 1; i >= 0; i--)
r = r * a + p[i];
return r;
}
if (d == 0)
return krts;
qf_double_t r = krts;
for (unsigned i = 0; i < 2 * d; i += 2) {
if (rts[i + 1] == 0)
r *= (a - rts[i]);
else {
qf_double_t m = rts[i] * rts[i] + rts[i + 1] * rts[i + 1];
qf_double_t n = -2 * rts[i];
r *= (a * a + n * a + m);
i += 2;
}
}
return r;
}
qf_double_t qf_poly::evalX2 (qf_double_t c) {
return (sqr ()).eval (c);
}
#ifdef _QF_POLY_DEBUG
void qf_poly::disp (const char *name) {
if (rep == NONE) {
std::cout << name << "(x) is not initialized.\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 qf_poly::disp (const char *) { }
#endif
void qf_poly::disp_c (void) {
if (d == 0) {
std::cout << p[0] << '\n';
return;
}
if (p[d] < 0)
std::cout << "-";
if (fabs (p[d]) != 1)
std::cout << fabs (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 (fabs (p[i]) != 1)
std::cout << fabs (p[i]);
std::cout << " x^" << i << ' ';
}
if (p[1] != 0) {
if (p[1] > 0)
std::cout << "+ ";
else
std::cout << "- ";
if (fabs (p[1]) != 1)
std::cout << fabs (p[1]);
std::cout << " x ";
}
}
if (p[0] != 0) {
if (p[0] > 0)
std::cout << "+ ";
else
std::cout << "- ";
std::cout << fabs (p[0]);
}
std::cout << '\n';
}
void qf_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 << " + " << fabs (rts[i]) << ") ";
else
std::cout << " - " << rts[i] << ") ";
}
else {
std::cout << "(X^2 ";
qf_double_t m = rts[i] * rts[i] + rts[i + 1] * rts[i + 1];
qf_double_t n = 2 * rts[i];
if (n > 0)
std::cout << "- " << n << "X ";
if (n < 0)
std::cout << "+ " << fabs (n) << "X ";
std::cout << "+ " << m << ") ";
i += 2;
}
}
std::cout << '\n';
}
the roots (product form) P(X) = k * prod (X - r[i]) */
void qf_poly::to_coeff (void) {
if (rep == NONE) {
std::cout << "qf_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_double_t[1];
p[0] = krts;
if ((rts == NULL) || (d == 0))
return;
if (d == 1) {
p = new qf_double_t[2];
p[0] = -krts * rts[0];
p[1] = krts;
return;
}
unsigned r = 0;
do {
if (rts[2 * r + 1] == 0) {
qf_double_t *q = new qf_double_t[r + 2];
q[0] = 0;
memcpy (&(q[1]), p, sizeof (qf_double_t) * (r + 1));
for (unsigned j = 0; j < r + 1; j++)
q[j] -= rts[2 * r] * p[j];
delete[] p;
p = q;
r++;
}
else {
qf_double_t m, n;
qf_double_t *q = new qf_double_t[r + 3];
qf_double_t *s = new qf_double_t[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_double_t) * (r + 1));
memcpy (&(s[1]), p, sizeof (qf_double_t) * (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 ("qf_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 qf_poly::to_roots (void) {
if (rep == NONE) {
std::cout << "qf_poly::to_roots () used on a NONE polynom.\n";
exit (-1);
}
if ((rep == ROOTS) || (rep == BOTH))
return;
if (d == 0)
return;
qf_matrix m (d);
if (rts != NULL)
delete[] rts;
rts = new qf_double_t[2 * d];
krts = p[d];
qf_scm (m);
qf_bcm (m);
qf_qrc (m, rts);
for (unsigned i = 0; i < 2 * d; i++) {
if (fabs (rts[i]) <= ROOT_PREC)
rts[i] = 0;
else
rts[i] = ROUND_ROOT (rts[i]);
}
rep = BOTH;
}
void qf_poly::qf_scm (qf_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 qf_poly::qf_bcm (qf_matrix & m) {
int not_converged = 1;
qf_double_t row_norm = 0;
qf_double_t col_norm = 0;
while (not_converged) {
unsigned int i, j;
qf_double_t g, f, s;
not_converged = 0;
for (i = 0; i < m.n; i++) {
if (i != m.n - 1) {
col_norm = fabs (m (i + 1, i));
}
else {
col_norm = 0;
for (j = 0; j < m.n - 1; j++) {
col_norm += fabs (m (j, m.n - 1));
}
}
if (i == 0) {
row_norm = fabs (m (0, m.n - 1));
}
else if (i == m.n - 1) {
row_norm = fabs (m (i, i - 1));
}
else {
row_norm = fabs (m (i, i - 1)) + fabs (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 qf_poly::qf_qrc (qf_matrix & h, qf_double_t * zroot) {
qf_double_t t = 0;
unsigned int iterations, e, i, j, k, m;
qf_double_t w, x, y, s, z;
qf_double_t 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_double_t a1 = fabs (h (e - 1, e - 2));
qf_double_t a2 = fabs (h (e - 2, e - 2));
qf_double_t a3 = fabs (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 (fabs (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 = fabs (h (n - 1, n - 2)) + fabs (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_double_t 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 = fabs (p) + fabs (q) + fabs (r);
p /= s;
q /= s;
r /= s;
if (m == e)
break;
a1 = fabs (h (m - 1, m - 2));
a2 = fabs (h (m - 2, m - 2));
a3 = fabs (h (m, m));
if (a1 * (fabs (q) + fabs (r)) <= EPSILON * fabs (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 = fabs (p) + fabs (q) + fabs (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;
}
void qf_poly::roots_to_complex(QVector< std::complex<float> > &roots)
{
roots.clear();
for (unsigned int i=0;i<d;i++) {
roots.append(std::complex<float>(rts[2*i],rts[2*i+1]));
}
}