Learn-to-Compress / headers / Polynomial.tpp
Polynomial.tpp
Raw
#include <cassert>

template<int p_order, typename TYPE, typename PRECISION>
Polynomial<p_order, TYPE, PRECISION>::Polynomial(int n, bool valid) : valid_(valid), data_size_(n) {
  static_assert(p_order >= 0);
  coefficients_.fill(0);
}

template<int p_order, typename TYPE, typename PRECISION>
Polynomial<p_order, TYPE, PRECISION>::Polynomial(std::array<PRECISION, p_order + 1> coefficients, bool valid, int n) :
    valid_(valid), data_size_(n) {
  static_assert(p_order >= 0);
  coefficients_ = coefficients;
}

// Override (), allowing to use polynomial as function that interpolates
template<int p_order, typename TYPE, typename PRECISION>
TYPE Polynomial<p_order, TYPE, PRECISION>::operator()(TYPE x) {
  PRECISION xx = 1;
  PRECISION s = 0;
  for (PRECISION a: coefficients_) {
    s = s + xx * a;
    xx = xx * x;
  }

  // If the "official type" happens to be integer or the like, we need a proper rounding.
  return std::is_integral<TYPE>::value ? (TYPE) std::round((double) s) : (TYPE) s;
}

template<int p_order, typename TYPE, typename PRECISION>
Polynomial<p_order - 1, TYPE, PRECISION> Polynomial<p_order, TYPE, PRECISION>::differentiate() {
  static_assert(p_order > 0);
  Polynomial<p_order - 1, TYPE, PRECISION> diff;
  for (int n = 1; n <= p_order; n++) {
    diff[n - 1] = n * coefficients_[n];
  }
  return diff;
}

template<int p_order, typename TYPE, typename PRECISION>
Polynomial<p_order + 1, TYPE, PRECISION> Polynomial<p_order, TYPE, PRECISION>::integrate(TYPE C) {
  Polynomial<p_order + 1, TYPE, PRECISION> integ;
  for (int n = 1; n <= p_order + 1; n++) {
    integ[n] = coefficients_[n - 1] / (PRECISION) n;
  }
  integ[0] = C;
  return integ;
}

// Define [] to retrieve the coefficients
template<int p_order, typename TYPE, typename PRECISION>
PRECISION &Polynomial<p_order, TYPE, PRECISION>::operator[](int a) {
  return coefficients_.at(a);
}

// Define the iterators for easy loop
template<int p_order, typename TYPE, typename PRECISION>
typename std::array<PRECISION, p_order>::iterator Polynomial<p_order, TYPE, PRECISION>::begin() {
  return coefficients_.begin();
}

template<int p_order, typename TYPE, typename PRECISION>
typename std::array<PRECISION, p_order>::iterator Polynomial<p_order, TYPE, PRECISION>::end() {
  return coefficients_.end();
}

template<int p_order, typename TYPE, typename PRECISION>
int Polynomial<p_order, TYPE, PRECISION>::order() const {
  return p_order;
}

template<int p_order, typename TYPE, typename PRECISION>
int Polynomial<p_order, TYPE, PRECISION>::data_size() const {
  return data_size_;
}

template<int p_order, typename TYPE, typename PRECISION>
PRECISION Polynomial<p_order, TYPE, PRECISION>::residual() const {
  return residual_;
}

template<int p_order, typename TYPE, typename PRECISION>
void Polynomial<p_order, TYPE, PRECISION>::residual(PRECISION residual) {
  residual_ = residual;
}

template<int p_order, typename TYPE, typename PRECISION>
std::string Polynomial<p_order, TYPE, PRECISION>::DebugString() const {
  std::string expression;
  for (int n = p_order; n >= 0; n--) {
    TYPE k = coefficients_.at(n);
    switch (n) {
      case 0:
        expression = expression + std::to_string((float) k);
        break;
      case 1:
        expression = expression + std::to_string((float) k) + " * x + ";
        break;
      default:
        expression = expression + std::to_string((float) k) + " * x^" + std::to_string(n) + " + ";
        break;
    }
  }
  return expression;
}

template<int p_order, typename TYPE, typename PRECISION>
PRECISION Polynomial<p_order, TYPE, PRECISION>::avg_sqdif() const {
  return data_size_ > 0 ? residual_ / data_size_ : NAN;
}