Program Listing for File utilityFunctions.hpp#

Return to documentation for file (librapid/include/librapid/math/utilityFunctions.hpp)

#ifndef LIBRAPID_MATH_UTLIITY_FUNCTIONS_HPP
#define LIBRAPID_MATH_UTLIITY_FUNCTIONS_HPP

namespace librapid {
    template<typename X, typename Lower, typename Upper,
             typename ST = typetraits::ScalarReturnType<X>>
        requires(typetraits::TypeInfo<X>::type == detail::LibRapidType::Scalar &&
                 typetraits::TypeInfo<Lower>::type == detail::LibRapidType::Scalar &&
                 typetraits::TypeInfo<Upper>::type == detail::LibRapidType::Scalar)
    LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE ST clamp(X x, Lower lowerLimit, Upper upperLimit) {
        LIBRAPID_ASSERT(lowerLimit < upperLimit, "Lower limit must be below upper limit");
        if (x < lowerLimit) return static_cast<ST>(lowerLimit);
        if (x > upperLimit) return static_cast<ST>(upperLimit);
        return x;
    }

    template<typename T, typename Lower, typename Upper,
             typename ST = typetraits::ScalarReturnType<T>>
        requires(typetraits::TypeInfo<T>::type == detail::LibRapidType::Scalar &&
                 typetraits::TypeInfo<Lower>::type == detail::LibRapidType::Scalar &&
                 typetraits::TypeInfo<Upper>::type == detail::LibRapidType::Scalar &&
                 std::is_floating_point_v<T> && std::is_floating_point_v<Lower> &&
                 std::is_floating_point_v<Upper>)
    LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE ST lerp(T t, Lower lower, Upper upper) {
        if (isNaN(t) || isNaN(lower) || isNaN(upper))
            return std::numeric_limits<T>::quiet_NaN();
        else if ((t <= ST {0} && upper >= Upper {0}) || (lower >= Lower {0} && upper <= Upper {0}))
        // ab <= 0 but product could overflow.
#ifndef FMA
            return t * upper + (ST {1} - t) * lower;
#else
            return std::fma(t, upper, (_Float {1} - t) * upper);
#endif
        else if (t == ST {1})
            return upper;
        else { // monotonic near t == 1.
#ifndef FMA
            const auto x = lower + t * (upper - lower);
#else
            const auto x = std::fma(t, upper - lower, lower);
#endif
            return (t > ST {1}) == (upper > lower) ? max(upper, x) : min(upper, x);
        }
    }

    template<typename T, typename Lower, typename Upper,
             typename ST = typetraits::ScalarReturnType<T>>
        requires(typetraits::TypeInfo<T>::type == detail::LibRapidType::Scalar &&
                   typetraits::TypeInfo<Lower>::type == detail::LibRapidType::Scalar &&
                   typetraits::TypeInfo<Upper>::type == detail::LibRapidType::Scalar &&
                   !std::is_floating_point_v<T> ||
                 !std::is_floating_point_v<Lower> || !std::is_floating_point_v<Upper>)
    LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE ST lerp(T t, Lower lower, Upper upper) {
        if (isNaN(t) || isNaN(lower) || isNaN(upper)) return std::numeric_limits<ST>::quiet_NaN();
        return static_cast<ST>(lower) + (static_cast<ST>(upper) - static_cast<ST>(lower)) * t;
    }

    template<typename T, typename Lower = T, typename Upper = T,
             typename ST = typetraits::ScalarReturnType<T>>
        requires(typetraits::TypeInfo<T>::type == detail::LibRapidType::Scalar &&
                 typetraits::TypeInfo<Lower>::type == detail::LibRapidType::Scalar &&
                 typetraits::TypeInfo<Upper>::type == detail::LibRapidType::Scalar)
    LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE ST smoothStep(T t, Lower lowerEdge = 0,
                                                            Upper upperEdge = 1) {
        ST tt = clamp((t - lowerEdge) / (upperEdge - lowerEdge), 0.0, 1.0);
        return tt * tt * tt * (tt * (tt * T(6) - ST(15)) + ST(10));
    }

    template<typename V1, typename V2, typename T = double>
    LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE bool
    isClose(const V1 &val1, const V2 &val2, const T &absTol = 1e-5, const T &relTol = 1e-5) {
        return ::librapid::abs(val2 - val1) <=
               ::librapid::max(
                 relTol * ::librapid::max(::librapid::abs(val1), ::librapid::abs(val2)), absTol);
    }
} // namespace librapid

#endif // LIBRAPID_MATH_UTLIITY_FUNCTIONS_HPP