// figure out how much more efficient chebyshev nodes are than equally // spaced nodes where you interpolate between the middle nodes #include "bigfloat.h" // polynomials, with addition and multiplication and evaluation // _a has _len terms, for x^^0 .. x^^(_len-1) class Poly { public: Poly() { Zero(); } Poly(const Poly& p) { Copy(p); } Poly(const BigFloat& v1, const BigFloat& v2) { Set(v1, v2); } ~Poly() {} Poly& Zero() { for (int i=0; i= _len) for (; _len<=index; ++_len) _a[_len].Zero(); _a[index].Copy(d); while (_a[_len-1].IsZero() && _len > 0) --_len; return *this; } Poly& Set(const BigFloat& v1, const BigFloat& v2) { _len = 2; _a[0].Copy(v1); _a[1].Copy(v2); return *this; } int Length() const { return _len; } const BigFloat& At(int index) const { return index < _len ? _a[index] : BigFloat::ConstZero(); } BigFloat Eval(const BigFloat& x) const { BigFloat result(0); for (int i=_len; i--;) { result.Mult(x); result.Add(_a[i]); } return result; } Poly& Copy(const Poly& p) { _len = p._len; for (int i=0; i<_len; ++i) _a[i].Copy(p._a[i]); return *this; } Poly& Add(const Poly& p) { if (_len < p._len) for (int i=_len; i 0) { BigFloat relevance(_p.At(0)); relevance.Add(_p.At(_p.Length()-1)); if (relevance.Compare(_p.At(0)) != 0) break; _p.SetAt(_p.Length()-1, BigFloat::ConstZero()); } } virtual ~Lagrange() { delete[] _s; delete[] _v; delete[] _o; } virtual void DefineSupport() = 0; // Given n points (a[i],v[i]), set *(p[i]) to the ith Lagrange polynomial void Ortho() { BigFloat minusOne(-1); for (int i=0; i<=_n; i++) { _o[i].One(); for (int j=0; j<=_n; j++) { if (i==j) continue; Poly q(_s[j], minusOne); _o[i].Mult(q); } BigFloat scale(_v[i]); _o[i].Mult(scale.Div(_o[i].Eval(_s[i]))); } } // Interpolate f(x) BigFloat Eval(const BigFloat& x) const { // convert x (between _start and _finish) to x2 (between -1 and 1) BigFloat range(_finish); range.Sub(_start); BigFloat x2(x); x2.Sub(_start).Mult(2).Div(range).Sub(1); // interpolate the value for x2 return _p.Eval(x2); } // absolute value of difference between interpolation and f at x BigFloat Delta(const BigFloat& x) const { BigFloat delta(Eval(x)); delta.Sub((*_f)(x)); if (delta.Compare(BigFloat::ConstZero()) < 0) delta.Negate(); return delta; } // sample several points in the interval and return the worst delta seen BigFloat WorstDelta() const { static const int c_deltas = 13; BigFloat q[c_deltas]; BigFloat inRange(_finish); inRange.Sub(_start).Div(2).Add(_start); q[0].Copy(Delta(inRange)); int k = 1; for (int i=3; i<=7; i+=2) { for (int j=1; j 0) worstDelta.Copy(q[i]); return worstDelta; } // get the actual interpolation polynomial const Poly& GetPoly() const { return _p; } protected: BigFloat (*_f)(const BigFloat&); // the function to interpolate BigFloat _start; // start of interval BigFloat _finish; // end of interval int _n; // degree of interpolation polynomial BigFloat *_s; // indexes of n+1 support points BigFloat *_v; // values of n+1 support points Poly *_o; // orthogonal polynomials for n+1 support points Poly _p; // the Lagrange polynomial for this interval }; // _n+1 Chebyshev nodes between -1 and 1 class Chebyshev : public Lagrange { public: Chebyshev(BigFloat (*f)(const BigFloat&), const BigFloat& start, const BigFloat& finish, int n) { Init(f, start, finish, n); } ~Chebyshev() {} void DefineSupport() { for (int i=0; i<=_n; ++i) { BigFloat pii(i); pii.Mult(BigFloat::Pi()).Div(_n).Cos().Negate(); _s[i].Copy(pii); } } }; // Equally spaced nodes, two apart, centered on 0 class EqualSpacing : public Lagrange { public: EqualSpacing(BigFloat (*f)(const BigFloat&), const BigFloat& start, const BigFloat& finish, int n) { Init(f, start, finish, n); } ~EqualSpacing() {} // generate _n+1 equally-spaced nodes, each 2 apart, centered on 0 void DefineSupport() { for (int i=0; i<=_n; ++i) { BigFloat si(i); si.Mult(2).Sub(_n); _s[i].Copy(si); } } }; void Driver(const BigFloat& start, const BigFloat& finish, BigFloat (*f)(const BigFloat&), const char* name) { int n; BigFloat cWorst(0); BigFloat eWorst(0); for (n=1; n<30; ++n) { EqualSpacing e(f, start, finish, n); eWorst.Copy(e.WorstDelta()); Chebyshev c(f, start, finish, n); cWorst.Copy(c.WorstDelta()); printf("Degree %2d %s, Chebyshev=%g, EqualSpacing=%g ", n, name, cWorst.ToDouble(), eWorst.ToDouble()); const Poly& p = c.GetPoly(); BigFloat relevant(p.At(0)); relevant.Add(p.At(n)); if (relevant.Compare(p.At(0)) == 0) printf("c pointless "); const Poly& q = e.GetPoly(); relevant.Copy(q.At(0)).Add(q.At(n)); if (relevant.Compare(q.At(0)) == 0) printf("degree %d", q.Length()-1); else { BigFloat third(finish); third.Sub(start).Div(3).Add(start); EqualSpacing h(f, start, third, n); BigFloat hWorst(h.WorstDelta()); printf(", ThirdSpacing=%g", hWorst.ToDouble()); } printf("\n"); } } BigFloat Ranga(const BigFloat& x) { BigFloat r(x); r.Mult(r); return x.IsNegative() ? r : r.Negate(); } BigFloat Runge(const BigFloat& x) { BigFloat r(x); return r.Mult(r).Add(25).Invert(); } BigFloat Sine(const BigFloat& x) { BigFloat r(x); return r.Sin(); } BigFloat Exp(const BigFloat& x) { BigFloat r(x); return r.Exp(); } int main() { BigFloat pi(BigFloat::Pi()); pi.PrintHex(); printf("\n"); /* BigFloat a(-1); a.Div(100); BigFloat b(1); b.Div(100); try { Driver(a, b, &Exp, "exp"); Driver(a, b, &Sine, "sine"); Driver(a, b, &Runge, "Runge"); Driver(a, b, &Ranga, "Ranga"); } catch( const std::exception & ex ) { fprintf(stderr, "%s\n", ex.what()); } */ }