#ifndef SPLINE_H #define SPLINE_H /** @file * @class SPLINE * @brief Kubické splajny. */ #include "real_fix.h" using namespace FIX; typedef __SIZE_TYPE__ size_t; // Zjištění počtu prvků statického pole. templateconstexpr size_t array_size (T (&) [N]) { return N; } /*! * @class Pair * @brief Prvek vstupní tabulky pro výpočet kubických splajnů. * */ struct Pair { double x, y; }; /*! @class SplineSet @brief Výsledné koeficienty pro výpočet iterace pomocí polynomu 3. řádu. */ struct SplineSet { real x; //!< začátky intervalů x real a; //!< záčátky intervalů y, koeficienty a real b; //!< koeficienty b (x^1) real c; //!< koeficienty c (x^2) real d; //!< koeficienty d (x^3) }; //! V podstatě statický vektor pro SplineSet (bez nutnosti dymanické alokace) template class SPLINE { SplineSet data [N - 1]; // zde jsou schovány koeficienty (privátně) public: //! Konstruktor explicit constexpr SPLINE (const Pair * const p, const bool reverse = false) noexcept { double x [N], y [N]; // přeskupení dat - možnost inverzní funkce při reverse = true if (reverse) {for (int i=0; i= 0; --j) { // zpětný chod c[j] = z [j] - mu[j] * c[j+1]; b[j] = (y[j+1] - y[j]) / h[j] - h[j] * (c[j+1] + 2*c[j]) / 3.0; d[j] = (c[j+1] - c[j]) / (3.0 * h[j]); } for (int i = 0; i < n; ++i) { // závěrečný zápis koeficientů // Pro FIX je potřeba nastavit různé posuny pro koeficienty, rozsah je příliš velký a pak by to bylo nepřesné. data[i].x = to_real(x[i], 16); data[i].a = to_real(y[i], 16); data[i].b = to_real(b[i], 20); data[i].c = to_real(c[i], 28); data[i].d = to_real(d[i], 36); } } const SplineSet & operator[] (const int index) const { return data [index]; } const size_t size () const { return N - 1; } const real interpolate (const real x) const { const unsigned n = range (x); // určíme interval ve kterém budeme počítat const SplineSet & s = data [n]; // koeficienty polynomu v tomto intervalu const real r = x - s.x; // souřadnice x v tomto intervalu return cubic_poly (s, r); // vlastní výpočet } /***************************************************************/ /** @class iterator * @brief pro range-based for () */ class iterator { const SplineSet * ptr; public: iterator(const SplineSet * _ptr) : ptr (_ptr) {} iterator operator++ () { ++ptr; return * this; } bool operator!= (const iterator & other) const { return ptr != other.ptr; } const SplineSet & operator* () const { return * ptr; } }; iterator begin () const { return iterator (data ); } iterator end () const { return iterator (data + N - 1); } protected: const unsigned range (const real x) const { int l=0, r=size() - 1u; while (l <= r) { const int s = (l + r) >> 1; const real x0 = data[s + 0].x; const real x1 = data[s + 1].x; if (x < x0) r = s - 1; else if (x >= x1) l = s + 1; else return s; } return size() - 1u; } const real cubic_poly (const SplineSet & s, const real x) const { real r(s.d); // d => 36 v konstruktoru mull (r, x, 24); // 36+16-24 = 28 == c r += s.c; // c => 28 mull (r, x, 24); // 28+16-24 = 20 == b r += s.b; // b => 20 mull (r, x, 20); // 20+16-20 = 16 == a r += s.a; // a=x => 16 return r; // r=y => 16 } }; #endif // SPLINE_H