• Docs >
  • Program Listing for File math.hpp
Shortcuts

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

Docs

Access comprehensive developer documentation for Ripple

View Docs

Tutorials

Get tutorials to help with understand all features

View Tutorials

Examples

Find examples to help get started

View Examples