#include "machdefs.h" #include "poly.h" #include "linfit.h" //++ // Class Poly // Lib Outils++ // include poly.h // // Classe de calcul sur polynômes à une variable. //-- //++ // Links Parents // OVector //-- //++ // Titre Constructeurs //-- //++ // Poly::Poly(int degre=0) // // Crée un nouveau polynôme, en allouant de la place pour // le degré spécifié. //-- Poly::Poly(int degre) : OVector(degre+1), dirty(0), deg(0) { END_CONSTRUCTOR } void Poly::UpdateDeg() const { int i = nalloc-1; while (data[i] == 0 && i>0) i--; (int&) deg = i; // bientot mutable dans ANSI C++ (int&) dirty = 0; } //++ // Titre Méthodes //-- //++ // double& Poly::operator[](int i) // Permet d'accéder au coefficient de degré i (avec version // const). //-- //++ double Poly::operator()(double x) const // // Calcule la valeur du polynôme au point x. //-- { UpdateDegIfDirty(); double res = data[deg]; for (int i=deg-1; i>=0; i--) { res *= x; res += data[i]; } return res; } //++ void Poly::Derivate() // // Remplace le polynôme par le polynôme dérivé. //-- { UpdateDegIfDirty(); if (deg == 0) { data[0] = 0; return;} for (int i=1; i<=deg; i++) data[i-1] = data[i]*i; data[deg] = 0; deg--; } //++ void Poly::Derivate(Poly& der) const // // Retourne dans der le polynôme dérivé. //-- { UpdateDegIfDirty(); der.Realloc(deg); // der.Zero(); // on sait que Realloc met a zero le reste. for (int i=1; i<=deg; i++) der.data[i-1] = data[i]*i; } //++ int Poly::Roots(OVector& roots) const // // Retourne dans roots les racines réelles, si on sait // les calculer. Retourne le nombre de racines. //-- { UpdateDegIfDirty(); switch (deg) { case 0 : // degre 0 return 0; case 1 : // degre 1 roots.Realloc(1); return Root1(roots(0)); case 2 : // degre 2 roots.Realloc(2); return Root2(roots(0),roots(1)); default : THROW(parmErr); } } //++ int Poly::Root1(double& r) const // // Seulement si le polynôme est de degré 1: retourne // la racine dans "r". Retourne 1 (nombre de racines). //-- { UpdateDegIfDirty(); if (deg != 1) THROW(sizeMismatchErr); if (data[1] == 0) return 0; r = -data[0]/data[1]; return 1; } //++ int Poly::Root2(double& r1, double& r2) const // // Seulement si le polynôme est de degre 2: retourne // les racines dans "r1" et "r2". Retourne 0, 1 ou 2 // (nombre de racines). //-- { UpdateDegIfDirty(); if (deg != 2) THROW(sizeMismatchErr); double delta = data[1]*data[1] - 4*data[0]*data[2]; if (delta < 0) return 0; if (delta == 0) { r1 = r2 = -data[1]/2/data[0]; return 1; } r1 = (-data[1] - sqrt(delta))/2/data[0]; r2 = (-data[1] + sqrt(delta))/2/data[0]; return 2; } //++ Poly& Poly::operator = (Poly const& a) // // Opérateur d'affectation. //-- { if (this == &a) return *this; OVector::operator=(a); UpdateDeg(); return *this; } //++ // Titres Opérations sur polynômes //-- //++ Poly& Poly::operator += (Poly const& b) // //-- { UpdateDegIfDirty(); b.UpdateDegIfDirty(); if (b.deg > deg) Realloc(b.deg); int n = (deg > b.deg) ? deg : b.deg; for (int i=0; i<=n; i++) data[i] += b.data[i]; UpdateDeg(); return *this; } //++ Poly& Poly::operator -= (Poly const& b) // //-- { UpdateDegIfDirty(); b.UpdateDegIfDirty(); if (b.deg > deg) Realloc(b.deg); int n = (deg > b.deg) ? deg : b.deg; for (int i=0; i<=n; i++) data[i] -= b.data[i]; UpdateDeg(); return *this; } //++ Poly operator+ (Poly const& a, Poly const& b) // //-- #if HAS_NAMED_RETURN return c((a.deg > b.deg)?(a.deg+1):(b.deg+1)) #endif { #if !HAS_NAMED_RETURN Poly c((a.deg > b.deg)?(a.deg+1):(b.deg+1)); #endif c = a; c += b; #if !HAS_NAMED_RETURN return c; #endif } //++ Poly operator- (Poly const& a, Poly const& b) // //-- #if HAS_NAMED_RETURN return c((a.deg > b.deg)?(a.deg+1):(b.deg+1)) #endif { #if !HAS_NAMED_RETURN Poly c((a.deg > b.deg)?(a.deg+1):(b.deg+1)); #endif c = a; c -= b; #if !HAS_NAMED_RETURN return c; #endif } //++ Poly operator* (Poly const& a, Poly const& b) // //-- //#if HAS_NAMED_RETURN // return c(a.deg + b.deg) //#endif { //#if !HAS_NAMED_RETURN Poly c(a.deg + b.deg); //#endif a.UpdateDegIfDirty(); b.UpdateDegIfDirty(); c.deg = a.deg + b.deg; for (int i=0; i<=c.deg; i++) { c[i] = 0; int kmin = (i <= a.deg) ? 0 : i - a.deg; int kmax = (i <= a.deg) ? i : a.deg; for (int k=kmin; k<=kmax; k++) c[i] += a[k] * b[i-k]; } //#if !HAS_NAMED_RETURN return c; //#endif } //++ Poly& Poly::operator *= (double a) // //-- { UpdateDegIfDirty(); for (int i=0; i<=deg; i++) data[i] *= a; return *this; } //++ Poly operator* (double a, Poly const& b) // //-- #if HAS_NAMED_RETURN return c(b) #endif { #if !HAS_NAMED_RETURN Poly c(b); #endif c *= a; #if !HAS_NAMED_RETURN return c; #endif } void Poly::ReadSelf(PInPersist& s) { int_4 dg; s >> dg; Realloc(dg, true); #ifdef DEBUG int r = nr; int c = nc; #endif OVector::ReadSelf(s); #ifdef DEBUG DBASSERT(r == nr && c == nc); #endif UpdateDeg(); #ifdef DEBUG DBASSERT(dg == deg); #endif } void Poly::WriteSelf(POutPersist& s) const { UpdateDegIfDirty(); ((Poly*)(this))->Realloc(deg, true); s << deg; OVector::WriteSelf(s); } //++ void Poly::Print(ostream& s) const // // Impresssion. //-- { UpdateDegIfDirty(); int nz=0; for (int i = deg; i>=0; i--) { if ((*this)[i] != 0) { nz = 1; if (i < deg && (*this)[i] > 0) s << "+"; s << (*this)[i]; if (i == 1) s << "*X "; if (i > 1) s << "*X^" << i << " "; } } if (!nz) s << " 0 "; } //++ ostream& operator << (ostream& s, const Poly& a) // // Impressions sur le stream "s". //-- { a.Print(s); return s; } //++ double Poly::Fit(OVector const& x, OVector const& y, int degre) // // Ajustement polynomial par moindre carrés. Un polynôme de // degré "degre" est ajusté sur les données "x" et "y", et stocké dans // l'objet courant. Retourne le chi2. //-- { int n = x.NElts(); if (n != y.NElts()) THROW(sizeMismatchErr); Realloc(degre); OMatrix a(degre+1, n); for (int c=0; c degX) (int&)degX = dx; if (dy > degY) (int&)degY = dy; if (dx+dy > deg) (int&)deg = dx+dy; } (int&)dirty = 0; } //++ // int Poly2::DegX() const // Degré partiel en X. // int Poly2::DegY() const // Degré partiel en Y // int Poly2::MaxDegX() const // Degré partiel maximum (alloué) en X // int Poly2::MaxDegY() const // Degré partiel maximum (alloué) en Y // int Poly2::Deg() const // Degré total. //-- //++ // double& Poly2::Coef(int dx, int dy) // Retourne le coefficient de x^dx y^dy // (avec aussi version const). //-- //++ double Poly2::operator()(double x, double y) const // // Retourne la valeur en (x,y). //-- { UpdateDegIfDirty(); double res = 0; double xPow = 1; for (int dx=0; dx<=maxDegX; dx++) { double yPow = 1; for (int dy=0; dy<=maxDegY; dy++) { res += Coef(dx,dy) * xPow * yPow; yPow *= y; } xPow *= x; } return res; } //++ double Poly2::Fit(OVector const& x, OVector const& y, OVector const& z, int degreX, int degreY) // // Ajustement par moindre carrés z = P(x,y), degrés partiels imposés. //-- { int n = x.NElts(); if (n != y.NElts()) THROW(sizeMismatchErr); if (n != z.NElts()) THROW(sizeMismatchErr); Realloc(degreX, degreY); OMatrix a((degreX+1)*(degreY+1), n); for (int c=0; c> dgx >> dgy; Realloc(dgx, dgy); #ifdef DEBUG int r = nr; int c = nc; #endif OVector::ReadSelf(s); #ifdef DEBUG DBASSERT(r == nr && c == nc); #endif UpdateDeg(); } void Poly2::WriteSelf(POutPersist& s) const { s << maxDegX << maxDegY; OVector::WriteSelf(s); } //++ void Poly2::Print(ostream& s) const // // Impression sur stream s. //-- { UpdateDegIfDirty(); int nz=0; int notfirst=0; for (int dx = degX; dx>=0; dx--) for (int dy= degY; dy>=0; dy--) { double c = Coef(dx,dy); if (c != 0) { nz = 1; if (notfirst && c > 0) { s << "+"; notfirst = 1; } s << c << " "; if (dx == 1) s << "* X "; if (dx > 1) s << "* X^" << dx << " "; if (dy == 1) s << "* Y "; if (dy > 1) s << "* Y^" << dy << " "; s << endl; } } if (!nz) s << " 0 "; } //++ ostream& operator << (ostream& s, const Poly2& a) // // Impression sur stream s. //-- { a.Print(s); return s; } //++ // Titre Opérations //-- //++ Poly2& Poly2::operator += (Poly2 const& b) // //-- { if (maxDegX < b.DegX() || maxDegY < b.DegY()) Realloc(b.DegX(),b.DegY()); UpdateDegIfDirty(); int mx = b.DegX(); int my = b.DegY(); for (int i=0; i<= mx; i++) for (int j=0; j<= my; j++) Coef(i,j) += b.Coef(i,j); UpdateDeg(); return *this; } //++ Poly2& Poly2::operator -= (Poly2 const& b) // //-- { if (maxDegX < b.DegX() || maxDegY < b.DegY()) Realloc(b.DegX(),b.DegY()); UpdateDegIfDirty(); int mx = b.DegX(); int my = b.DegY(); for (int i=0; i<= mx; i++) for (int j=0; j<= my; j++) Coef(i,j) -= b.Coef(i,j); UpdateDeg(); return *this; } //++ Poly2 operator+ (Poly2 const& a, Poly2 const& b) // //-- #if HAS_NAMED_RETURN return c(a) #endif { #if !HAS_NAMED_RETURN Poly2 c(a); #endif c += b; #if !HAS_NAMED_RETURN return c; #endif } //++ Poly2 operator- (Poly2 const& a, Poly2 const& b) // //-- #if HAS_NAMED_RETURN return c(a) #endif { #if !HAS_NAMED_RETURN Poly2 c(a); #endif c -= b; #if !HAS_NAMED_RETURN return c; #endif } //++ Poly2& Poly2::operator *= (double a) // //-- { for (int i=0; i