/// @file grotto/piecewise.hpp /// @brief Horner evaluation of a cubic and a bound-selected piece. /// @details `eval_horner` evaluates one polynomial. `piecewise_eval` selects /// the piece whose upper bound is the first entry of `bounds` /// strictly greater than `x`. /// @author Ryan Henry /// @copyright Copyright (c) 2019-2026 Ryan Henry and [others](@ref authors) /// @license Released under a GNU General Public v2.0 (GPLv2) license; /// see [LICENSE.md](@ref license) for details. #ifndef LIBDPF_INCLUDE_GROTTO_PIECEWISE_HPP__ #define LIBDPF_INCLUDE_GROTTO_PIECEWISE_HPP__ #include #include #include #include "hedley/hedley.h" namespace grotto { namespace polynomials { /// @name Polynomial shapes /// @brief Coefficient arrays, constant term in element 0. Degree is `size - 1`. /// @{ template using poly_constant = std::array; template using poly_linear = std::array; template using poly_quadratic = std::array; template using poly_cubic = std::array; /// @} /// @brief Horner evaluation. The four overloads are degrees 0 through 3. /// @tparam T coefficient type /// @param f coefficients, constant term in `f[0]` /// @param x the evaluation point /// @return the polynomial value /// @see grotto::piecewise_eval /// \complexity Unrolled: 0, 1, 2, or 3 multiplies. `Θ(1)` time and extra space. template HEDLEY_PURE HEDLEY_NO_THROW constexpr auto eval_horner(const poly_constant & f, T x) noexcept { return f[0]; } /// @brief Degree-1 Horner. Constant term in `f[0]`. /// @see grotto::eval_horner /// \complexity One multiply-add. `Θ(1)`. template HEDLEY_PURE HEDLEY_NO_THROW constexpr auto eval_horner(const poly_linear & f, T x) noexcept { return f[1] * x + f[0]; } /// @brief Degree-2 Horner. Constant term in `f[0]`. /// @see grotto::eval_horner /// \complexity Two multiply-adds. `Θ(1)`. template HEDLEY_PURE HEDLEY_NO_THROW constexpr auto eval_horner(const poly_quadratic & f, T x) noexcept { return (f[2] * x + f[1]) * x + f[0]; } /// @brief Degree-3 Horner. Constant term in `f[0]`. /// @see grotto::eval_horner /// \complexity Three multiply-adds. `Θ(1)`. template HEDLEY_PURE HEDLEY_NO_THROW constexpr auto eval_horner(const poly_cubic & f, T x) noexcept { return ((f[3] * x + f[2]) * x + f[1]) * x + f[0]; } /// @brief Select the piece whose upper bound is the first entry of `bounds` strictly greater than `x`, then Horner-evaluate it. /// @tparam T coefficient and bound type /// @tparam D coefficients per piece /// @tparam N1 number of pieces /// @tparam N2 number of bounds /// @param polys one coefficient array per piece, constant term first /// @param bounds upper bounds of the pieces /// @param x the query /// @return `eval_horner` of the selected piece /// @see grotto::eval_horner /// \complexity `upper_bound` on `bounds` (`Θ(log N2)`), then one `eval_horner` (`Θ(1)`, `D` is 1..4). Extra space `Θ(1)`. template HEDLEY_PURE HEDLEY_NO_THROW auto piecewise_eval(const std::array, N1> & polys, const std::array & bounds, T x) noexcept { auto it = std::upper_bound(std::cbegin(bounds), std::cend(bounds), x, [](const T & lhs, const T & rhs){ return lhs < rhs; }); auto i = std::distance(std::cbegin(bounds), it); return eval_horner(polys[i], x); } } // namespace polynomials } // namespace grotto #endif // LIBDPF_INCLUDE_GROTTO_PIECEWISE_HPP__