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 std::enable_if_t<
typetraits::TypeInfo<X>::type == detail::LibRapidType::Scalar &&
typetraits::TypeInfo<Lower>::type == detail::LibRapidType::Scalar &&
typetraits::TypeInfo<Upper>::type == detail::LibRapidType::Scalar,
int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE X clamp(X x, Lower lowerLimit, Upper upperLimit) {
LIBRAPID_ASSERT(lowerLimit < upperLimit, "Lower limit must be below upper limit");
if (x < lowerLimit) return static_cast<X>(lowerLimit);
if (x > upperLimit) return static_cast<X>(upperLimit);
return x;
}
template<typename T, typename Lower, typename Upper,
typename std::enable_if_t<
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>,
int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE T lerp(T t, Lower lower, Upper upper) {
if (isNaN(t) || isNaN(lower) || isNaN(upper))
return std::numeric_limits<T>::quiet_NaN();
else if ((t <= T {0} && upper >= T {0}) || (lower >= T {0} && upper <= T {0}))
// ab <= 0 but product could overflow.
#ifndef FMA
return t * upper + (T {1} - t) * lower;
#else
return std::fma(t, upper, (_Float {1} - t) * upper);
#endif
else if (t == T {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 > T {1}) == (upper > lower) ? max(upper, x) : min(upper, x);
}
}
template<typename T, typename Lower, typename Upper,
typename std::enable_if_t<
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>,
int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE T lerp(T t, Lower lower, Upper upper) {
if (isNaN(t) || isNaN(lower) || isNaN(upper)) return std::numeric_limits<T>::quiet_NaN();
if (t < T {0}) return lower;
if (t > T {1}) return upper;
return static_cast<T>(lower) + (static_cast<T>(upper) - static_cast<T>(lower)) * t;
}
template<typename T, typename Lower = T, typename Upper = T,
typename std::enable_if_t<
typetraits::TypeInfo<T>::type == detail::LibRapidType::Scalar &&
typetraits::TypeInfo<Lower>::type == detail::LibRapidType::Scalar &&
typetraits::TypeInfo<Upper>::type == detail::LibRapidType::Scalar,
int> = 0>
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE T smoothStep(T t, Lower lowerEdge = 0,
Upper upperEdge = 1) {
T tt = clamp((t - lowerEdge) / (upperEdge - lowerEdge), 0.0, 1.0);
return tt * tt * tt * (tt * (tt * T(6) - T(15)) + T(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