Program Listing for File ema.hpp

Return to documentation for file (rcppsw/math/ema.hpp)

#pragma once

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include <cmath>

#include "rcppsw/math/expression.hpp"

/*******************************************************************************
 * Namespaces/Decls
 ******************************************************************************/
namespace rcppsw::math {

/*******************************************************************************
 * Class Definitions
 ******************************************************************************/
template <class T>
class ema final : public expression<T> {
 public:
  using expression<T>::v;
  using expression<T>::eval;

  explicit ema(double alpha) : m_alpha(alpha) {}
  ema(double alpha, const T& result) : expression<T>(result), m_alpha(alpha) {}

  double alpha(void) const { return m_alpha; }

  T calc(const T& measure) { return operator()(measure); }
  ema& calc(const ema& other) {
    this->calc(other.v());
    return *this;
  }

  T operator()(const T& measure) {
    /*
     * Cast to T because depending on what the type is, we may get floating
     * point -> integer conversion warnings, so be explicit
     */
    return eval(static_cast<T>((1 - m_alpha) * v() + m_alpha * measure));
  }

  ema& operator()(const ema& other) {
    this->eval(other.v());
    return *this;
  }

  ema& operator+=(const ema& other) {
    this->eval(this->v() + other.v());
    return *this;
  }

  ema operator+(const ema& other) const {
    ema r(this->alpha());
    r.eval(this->v() + other.v());
    return r;
  }
  ema operator-(const ema& other) const {
    ema r(this->alpha());
    r.eval(this->v() - other.v());
    return r;
  }

  ema operator/(const ema& other) const {
    ema r(this->alpha());
    r.eval(this->v() / other.v());
    return r;
  }

  template <typename U = T,
            RCPPSW_SFINAE_DECLDEF(!(std::is_floating_point<T>::value))>
  bool operator==(const ema& other) const {
    return this->v() == other.v();
  }

 private:
  /* clang-formatt off */
  double m_alpha;
  /* clang-formatt on */
};

/*******************************************************************************
 * Non-Member Functions
 ******************************************************************************/
template <typename T, RCPPSW_SFINAE_DECLDEF(!(std::is_floating_point<T>::value))>
bool operator==(const T& v, const ema<T>& rhs) {
  return v == rhs.v();
}

template <class T, class U>
ema<T> operator-(const ema<T>& lhs, const U& rhs) {
  ema<T> r(lhs.alpha());
  r.eval(static_cast<T>(lhs.v() - rhs));
  return r;
}

template <class T, class U>
ema<T> operator-(const U& lhs, const ema<T>& rhs) {
  ema<T> r(rhs.alpha());
  r.eval(static_cast<T>(lhs - rhs.v()));
  return r;
}

template <class T, class U>
ema<T> operator*(const ema<T>& lhs, const U& rhs) {
  ema<T> r(lhs.alpha());
  r.eval(lhs.v() * rhs);
  return r;
}

template <class T, class U>
ema<T> operator*(const U& lhs, const ema<T>& rhs) {
  ema<T> r(rhs.alpha());
  r.eval(rhs.v() * lhs);
  return r;
}

template <class T, class U>
ema<T> operator/(const U& lhs, const ema<T>& rhs) {
  ema<T> r(rhs.alpha());
  r.eval(lhs.v() / rhs);
  return r;
}

/* Always want to make sure we do division with doubles */
template <class T>
ema<T> operator/(const ema<T>& lhs, const double& rhs) {
  ema<T> r(lhs.alpha());
  r.eval(lhs.v() / rhs);
  return r;
}

} /* namespace rcppsw::math */