Program Listing for File math.hpp¶
↰ Return to documentation for file (include/ripple/math/math.hpp
)
#ifndef RIPPLE_MATH_MATH_HPP
#define RIPPLE_MATH_MATH_HPP
#include <ripple/container/array.hpp>
#include <algorithm>
#include <cmath>
namespace ripple::math {
/*==--- [trig functions] ---------------------------------------------------==*/
template <typename T>
ripple_all constexpr auto tanh(T x) noexcept -> T {
// TOOD: Test performance on the GPU.
return std::tanh(x);
}
template <typename T>
ripple_all constexpr auto cosh(T x) noexcept -> T {
// TOOD: Test performance on the GPU.
return std::cosh(x);
}
template <typename T>
ripple_all constexpr auto fast_exp(T x) noexcept -> T {
#if defined(ripple_gpu_compile)
return __expf(x);
#else
return std::exp(x);
#endif
}
/*==--- [hash] -------------------------------------------------------------==*/
ripple_all constexpr auto
hash(char const* input) noexcept -> unsigned int {
return *input ? static_cast<unsigned int>(*input) + 33 * hash(input + 1)
: 5381;
}
ripple_all constexpr auto
hash_combine(uint32_t a, uint32_t b) noexcept -> uint64_t {
constexpr uint64_t div_factor = 2;
uint64_t x = a, y = b;
return (x + y) * (x + y + uint64_t{1}) / div_factor + y;
}
namespace literals {
ripple_all constexpr auto
operator"" _hash(const char* input, unsigned long) noexcept -> unsigned int {
return hash(input);
}
} // namespace literals
namespace detail {
ripple_all static inline auto xorshift_32() noexcept -> uint32_t {
static uint32_t rand_seed = 123456789;
uint32_t x = rand_seed;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
rand_seed = x;
return x;
}
template <typename T>
ripple_all constexpr auto sign(T x, std::false_type) noexcept -> T {
return T(0) < x;
}
template <typename T>
ripple_all constexpr auto sign(T x, std::true_type) noexcept -> T {
return (T(0) < x) - (x < T(0));
}
} // namespace detail
/*==--- [general] ----------------------------------------------------------==*/
ripple_all constexpr auto log_2(uint32_t value) noexcept -> uint32_t {
// clang-format off
uint32_t result = 0, shift = 0;
result = (value > 0xFFFF) << 4; value >>= result;
shift = (value > 0xFF ) << 3; value >>= shift ; result |= shift;
shift = (value > 0xF ) << 2; value >>= shift ; result |= shift;
shift = (value > 0x3 ) << 1; value >>= shift ; result |= shift;
return result |= (value >> 1);
// clang-format on
}
ripple_all static inline auto
randint(uint32_t start, uint32_t end) noexcept -> uint32_t {
const uint32_t range = end - start;
return (detail::xorshift_32() >> (32 - log_2(range) - 1)) % range + start;
}
template <typename T, non_array_enable_t<T> = 0>
ripple_all constexpr auto sqrt(const T& v) noexcept -> T {
return std::sqrt(v);
}
template <typename Impl, array_enable_t<Impl> = 0>
ripple_all constexpr auto
sqrt(const Array<Impl>& arr) noexcept -> Impl {
auto r = Impl{};
unrolled_for<array_traits_t<Impl>::size>([&](auto _i) {
constexpr auto i = size_t{_i};
r[i] = sqrt(arr[i]);
});
return r;
}
template <typename T>
ripple_all constexpr auto sign(T x) noexcept -> T {
return detail::sign(x, std::is_signed<T>());
}
template <typename T, non_array_enable_t<T> = 0>
ripple_all constexpr auto abs(T x) noexcept -> T {
return sign(x) * x;
}
template <typename Impl, array_enable_t<Impl> = 0>
ripple_all constexpr auto abs(const Array<Impl>& arr) noexcept -> Impl {
auto r = Impl{};
unrolled_for<array_traits_t<Impl>::size>([&](auto _i) {
constexpr auto i = size_t{_i};
r[i] = abs(arr[i]);
});
return r;
}
template <typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
ripple_all constexpr auto isnan(T a) noexcept -> bool {
return std::isnan(a);
}
template <typename Impl, array_enable_t<Impl> = 0>
ripple_all constexpr auto isnan(const Array<Impl>& a) noexcept -> bool {
for (size_t i = 0; i < a.size(); ++i) {
if (std::isnan(a[i])) {
return true;
}
}
return false;
}
template <typename T, typename F = float>
ripple_all auto div_then_ceil(T num, T denom) noexcept -> T {
return static_cast<T>(std::ceil(static_cast<F>(num) / denom));
}
template <typename T, non_array_enable_t<T> = 0>
ripple_all constexpr auto min(const T& a, const T& b) noexcept -> T {
return std::min(a, b);
}
template <typename ImplA, typename ImplB, array_enable_t<ImplA> = 0>
ripple_all constexpr auto
min(const Array<ImplA>& a, const Array<ImplB>& b) noexcept
-> array_impl_t<ImplA, ImplB> {
using Result = array_impl_t<ImplA, ImplB>;
Result r;
unrolled_for_bounded<array_traits_t<ImplA>::size>([&](auto _i) {
constexpr size_t i = _i;
r[i] = std::min(a[i], b[i]);
});
return r;
}
template <typename Impl, typename T, array_enable_t<Impl> = 0>
ripple_all constexpr auto
min(const Array<Impl>& a, T b) noexcept -> Impl {
using Result = Impl;
Result r;
unrolled_for_bounded<array_traits_t<Impl>::size>(
[&](auto i) { r[i] = std::min(a[i], b); });
return r;
}
template <typename Impl, array_enable_t<Impl> = 0>
ripple_all constexpr auto
min(const Array<Impl>& a) noexcept -> typename array_traits_t<Impl>::Value {
using Result = typename array_traits_t<Impl>::Value;
Result r = a[0];
unrolled_for_bounded<array_traits_t<Impl>::size - 1>(
[&](auto i) { r = std::min(r, a[i + 1]); });
return r;
}
template <typename T, non_array_enable_t<T> = 0>
ripple_all constexpr auto max(const T& a, const T& b) noexcept -> T {
return std::max(a, b);
}
template <typename ImplA, typename ImplB, array_enable_t<ImplA> = 0>
ripple_all constexpr auto
max(const Array<ImplA>& a, const Array<ImplB>& b) noexcept
-> array_impl_t<ImplA, ImplB> {
using Result = array_impl_t<ImplA, ImplB>;
Result r;
unrolled_for_bounded<array_traits_t<ImplA>::size>(
[&](auto i) { r[i] = std::max(a[i], b[i]); });
return r;
}
template <typename Impl, typename T, array_enable_t<Impl> = 0>
ripple_all constexpr auto
max(const Array<Impl>& a, T b) noexcept -> Impl {
using Result = Impl;
Result r;
unrolled_for_bounded<array_traits_t<Impl>::size>(
[&](auto i) { r[i] = std::max(a[i], b); });
return r;
}
template <typename Impl, array_enable_t<Impl> = 0>
ripple_all constexpr auto
max(const Array<Impl>& a) noexcept -> typename array_traits_t<Impl>::Value {
using Result = typename array_traits_t<Impl>::Value;
Result r = a[0];
unrolled_for_bounded<array_traits_t<Impl>::size - 1>(
[&](auto i) { r = std::max(r, a[i + 1]); });
return r;
}
template <typename Impl, typename T>
ripple_all auto
clamp(const T& v, const T& lo, const T& hi) noexcept -> const T& {
return std::clamp(v, lo, hi);
}
template <typename Impl, typename T>
ripple_all auto
clamp(Array<Impl>& a, const T& lo, const T& hi) noexcept -> void {
unrolled_for<array_traits_t<Impl>::size>(
[&](auto i) { a[i] = std::clamp(a[i], lo, hi); });
}
/*==--- [vec operations] ---------------------------------------------------==*/
template <typename ImplA, typename ImplB>
ripple_all constexpr auto
dot(const Array<ImplA>& a, const Array<ImplB>& b) noexcept ->
typename array_traits_t<ImplA>::Value {
using Traits = array_traits_t<ImplA>;
using Value = typename Traits::Value;
Value r = 0;
unrolled_for_bounded<Traits::size>(
[&](auto i) { r += static_cast<Value>(a[i]) * static_cast<Value>(b[i]); });
return r;
}
template <typename Impl>
ripple_all constexpr auto
dot2(const Array<Impl>& a) noexcept -> typename array_traits_t<Impl>::Value {
using Traits = array_traits_t<Impl>;
using Value = typename Traits::Value;
Value r = 0;
unrolled_for_bounded<Traits::size>(
[&](auto i) { r += static_cast<Value>(a[i]) * static_cast<Value>(a[i]); });
return r;
}
template <
typename ImplA,
typename ImplB,
array_size_enable_t<ImplA, 2> = 0,
array_size_enable_t<ImplB, 2> = 0>
ripple_all constexpr auto
cross(const Array<ImplA>& a, const Array<ImplB>& b) noexcept ->
typename array_traits_t<ImplA>::Value {
return a[0] * b[1] - b[0] * a[1];
}
template <
typename ImplA,
typename ImplB,
array_size_enable_t<ImplA, 3> = 0,
array_size_enable_t<ImplB, 3> = 0>
ripple_all constexpr auto
cross(const Array<ImplA>& a, const Array<ImplB>& b) noexcept
-> array_impl_t<ImplA, ImplB> {
using Result = array_impl_t<ImplA, ImplB>;
return Result{
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
a[0] * b[1] - a[1] * b[0]};
}
template <typename Impl>
ripple_all auto
length(const Array<Impl>& a) noexcept -> typename array_traits_t<Impl>::Value {
using Value = typename array_traits_t<Impl>::Value;
Value r{0};
unrolled_for_bounded<array_traits_t<Impl>::size>(
[&](auto i) { r += a[i] * a[i]; });
return std::sqrt(r);
}
} // namespace ripple::math
#endif // RIPPLE_MATH_MATH_HPP