type restrictions of basic math functions

This commit is contained in:
BlackMATov
2020-11-26 20:06:57 +07:00
parent 4d62fd034a
commit bba60b0aad
6 changed files with 204 additions and 67 deletions

View File

@@ -510,7 +510,7 @@ namespace vmath_hpp
template < typename T, std::size_t Size > template < typename T, std::size_t Size >
T angle(const vec<T, Size>& x, const vec<T, Size>& y) { T angle(const vec<T, Size>& x, const vec<T, Size>& y) {
return acos(dot(x, y) * invsqrt(length2(x) * length2(y))); return acos(dot(x, y) * rsqrt(length2(x) * length2(y)));
} }
// rotate // rotate

View File

@@ -15,31 +15,94 @@
namespace vmath_hpp namespace vmath_hpp
{ {
template < typename T > template < typename T >
constexpr T radians(T degrees) noexcept { std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr radians(T degrees) noexcept {
return degrees * T(0.01745329251994329576923690768489); return degrees * T(0.01745329251994329576923690768489);
} }
template < typename T > template < typename T >
constexpr T degrees(T radians) noexcept { std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr degrees(T radians) noexcept {
return radians * T(57.295779513082320876798154814105); return radians * T(57.295779513082320876798154814105);
} }
using ::std::sin; template < typename T >
using ::std::cos; std::enable_if_t<std::is_floating_point_v<T>, T>
using ::std::tan; sin(T x) noexcept {
return std::sin(x);
}
using ::std::asin; template < typename T >
using ::std::acos; std::enable_if_t<std::is_floating_point_v<T>, T>
using ::std::atan; cos(T x) noexcept {
using ::std::atan2; return std::cos(x);
}
using ::std::sinh; template < typename T >
using ::std::cosh; std::enable_if_t<std::is_floating_point_v<T>, T>
using ::std::tanh; tan(T x) noexcept {
return std::tan(x);
}
using ::std::asinh; template < typename T >
using ::std::acosh; std::enable_if_t<std::is_floating_point_v<T>, T>
using ::std::atanh; asin(T x) noexcept {
return std::asin(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
acos(T x) noexcept {
return std::acos(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
atan(T x) noexcept {
return std::atan(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
atan2(T y, T x) noexcept {
return std::atan2(y, x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
sinh(T x) noexcept {
return std::sinh(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
cosh(T x) noexcept {
return std::cosh(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
tanh(T x) noexcept {
return std::tanh(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
asinh(T x) noexcept {
return std::asinh(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
acosh(T x) noexcept {
return std::acosh(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
atanh(T x) noexcept {
return std::atanh(x);
}
} }
// //
@@ -48,15 +111,45 @@ namespace vmath_hpp
namespace vmath_hpp namespace vmath_hpp
{ {
using ::std::pow; template < typename T >
using ::std::exp; std::enable_if_t<std::is_floating_point_v<T>, T>
using ::std::log; pow(T x, T y) noexcept {
using ::std::exp2; return std::pow(x, y);
using ::std::log2; }
using ::std::sqrt;
template < typename T > template < typename T >
T invsqrt(T x) noexcept { std::enable_if_t<std::is_floating_point_v<T>, T>
exp(T x) noexcept {
return std::exp(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
log(T x) noexcept {
return std::log(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
exp2(T x) noexcept {
return std::exp2(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
log2(T x) noexcept {
return std::log2(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
sqrt(T x) noexcept {
return std::sqrt(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
rsqrt(T x) noexcept {
return T(1) / sqrt(x); return T(1) / sqrt(x);
} }
} }
@@ -80,48 +173,92 @@ namespace vmath_hpp
} }
template < typename T > template < typename T >
constexpr T sign(T x) noexcept { std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr sign(T x) noexcept {
return static_cast<T>((T(0) < x) - (x < T(0))); return static_cast<T>((T(0) < x) - (x < T(0)));
} }
using ::std::floor; template < typename T >
using ::std::trunc; std::enable_if_t<std::is_floating_point_v<T>, T>
using ::std::round; floor(T x) noexcept {
using ::std::ceil; return std::floor(x);
}
template < typename T > template < typename T >
T fract(T x) noexcept { std::enable_if_t<std::is_floating_point_v<T>, T>
trunc(T x) noexcept {
return std::trunc(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
round(T x) noexcept {
return std::round(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
ceil(T x) noexcept {
return std::ceil(x);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
fract(T x) noexcept {
return x - floor(x); return x - floor(x);
} }
using ::std::fmod; template < typename T >
using ::std::modf; std::enable_if_t<std::is_floating_point_v<T>, T>
fmod(T x, T y) noexcept {
using ::std::min; return std::fmod(x, y);
using ::std::max; }
template < typename T > template < typename T >
constexpr T clamp(T x, T min_x, T max_x) noexcept { std::enable_if_t<std::is_floating_point_v<T>, T>
modf(T x, T* y) noexcept {
return std::modf(x, y);
}
template < typename T >
std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr min(T x, T y) noexcept {
return std::min(x, y);
}
template < typename T >
std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr max(T x, T y) noexcept {
return std::max(x, y);
}
template < typename T >
std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr clamp(T x, T min_x, T max_x) noexcept {
return min(max(x, min_x), max_x); return min(max(x, min_x), max_x);
} }
template < typename T > template < typename T >
constexpr T saturate(T x) noexcept { std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr saturate(T x) noexcept {
return clamp(x, T(0), T(1)); return clamp(x, T(0), T(1));
} }
template < typename T > template < typename T >
constexpr T lerp(T x, T y, T a) noexcept { std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr lerp(T x, T y, T a) noexcept {
return x * (T(1) - a) + y * a; return x * (T(1) - a) + y * a;
} }
template < typename T > template < typename T >
constexpr T step(T edge, T x) noexcept { std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr step(T edge, T x) noexcept {
return x < edge ? T(0) : T(1); return x < edge ? T(0) : T(1);
} }
template < typename T > template < typename T >
constexpr T smoothstep(T edge0, T edge1, T x) noexcept { std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr smoothstep(T edge0, T edge1, T x) noexcept {
const T t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1)); const T t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1));
return t * t * (T(3) - T(2) * t); return t * t * (T(3) - T(2) * t);
} }
@@ -129,16 +266,24 @@ namespace vmath_hpp
using ::std::isnan; using ::std::isnan;
using ::std::isinf; using ::std::isinf;
using ::std::isfinite; using ::std::isfinite;
using ::std::isnormal;
template < typename T > template < typename T >
bool issubnormal(T x) noexcept { std::enable_if_t<std::is_floating_point_v<T>, T>
return std::fpclassify(x) == FP_SUBNORMAL; fma(T x, T y, T z) noexcept {
return std::fma(x, y, z);
} }
using ::std::fma; template < typename T >
using ::std::frexp; std::enable_if_t<std::is_floating_point_v<T>, T>
using ::std::ldexp; frexp(T x, int* exp) noexcept {
return std::frexp(x, exp);
}
template < typename T >
std::enable_if_t<std::is_floating_point_v<T>, T>
ldexp(T x, int exp) noexcept {
return std::ldexp(x, exp);
}
} }
// //
@@ -174,7 +319,7 @@ namespace vmath_hpp
template < typename T > template < typename T >
T normalize(T x) noexcept { T normalize(T x) noexcept {
return x * invsqrt(dot(x, x)); return x * rsqrt(dot(x, x));
} }
template < typename T > template < typename T >

View File

@@ -6,13 +6,11 @@
#pragma once #pragma once
#include <cassert>
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <iterator>
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@@ -45,6 +43,10 @@ namespace vmath_hpp
using size2 = vec<std::size_t, 2>; using size2 = vec<std::size_t, 2>;
using size3 = vec<std::size_t, 3>; using size3 = vec<std::size_t, 3>;
using size4 = vec<std::size_t, 4>; using size4 = vec<std::size_t, 4>;
using ptrdiff2 = vec<std::ptrdiff_t, 2>;
using ptrdiff3 = vec<std::ptrdiff_t, 3>;
using ptrdiff4 = vec<std::ptrdiff_t, 4>;
} }
namespace vmath_hpp namespace vmath_hpp
@@ -75,4 +77,8 @@ namespace vmath_hpp
using size2x2 = mat<std::size_t, 2>; using size2x2 = mat<std::size_t, 2>;
using size3x3 = mat<std::size_t, 3>; using size3x3 = mat<std::size_t, 3>;
using size4x4 = mat<std::size_t, 4>; using size4x4 = mat<std::size_t, 4>;
using ptrdiff2x2 = mat<std::ptrdiff_t, 2>;
using ptrdiff3x3 = mat<std::ptrdiff_t, 3>;
using ptrdiff4x4 = mat<std::ptrdiff_t, 4>;
} }

View File

@@ -370,8 +370,8 @@ namespace vmath_hpp
} }
template < typename T, std::size_t Size > template < typename T, std::size_t Size >
vec<T, Size> invsqrt(const vec<T, Size>& xs) { vec<T, Size> rsqrt(const vec<T, Size>& xs) {
return map([](T x) { return invsqrt(x); }, xs); return map([](T x) { return rsqrt(x); }, xs);
} }
} }
@@ -529,16 +529,6 @@ namespace vmath_hpp
return map([](T x) { return isfinite(x); }, xs); return map([](T x) { return isfinite(x); }, xs);
} }
template < typename T, std::size_t Size >
vec<bool, Size> isnormal(const vec<T, Size>& xs) {
return map([](T x) { return isnormal(x); }, xs);
}
template < typename T, std::size_t Size >
vec<bool, Size> issubnormal(const vec<T, Size>& xs) {
return map([](T x) { return issubnormal(x); }, xs);
}
template < typename T, std::size_t Size > template < typename T, std::size_t Size >
vec<T, Size> fma(const vec<T, Size>& as, const vec<T, Size>& bs, const vec<T, Size>& cs) { vec<T, Size> fma(const vec<T, Size>& as, const vec<T, Size>& bs, const vec<T, Size>& cs) {
return zip([](T a, T b, T c) { return fma(a, b, c); }, as, bs, cs); return zip([](T a, T b, T c) { return fma(a, b, c); }, as, bs, cs);
@@ -611,7 +601,7 @@ namespace vmath_hpp
template < typename T, std::size_t Size > template < typename T, std::size_t Size >
vec<T, Size> normalize(const vec<T, Size>& xs) { vec<T, Size> normalize(const vec<T, Size>& xs) {
return xs * invsqrt(dot(xs, xs)); return xs * rsqrt(dot(xs, xs));
} }
template < typename T, std::size_t Size > template < typename T, std::size_t Size >

View File

@@ -47,7 +47,7 @@ TEST_CASE("vmath/fun") {
(void)exp2(2.f); (void)exp2(2.f);
(void)log2(2.f); (void)log2(2.f);
(void)sqrt(2.f); (void)sqrt(2.f);
(void)invsqrt(2.f); (void)rsqrt(2.f);
} }
SECTION("Common Functions") { SECTION("Common Functions") {
@@ -98,8 +98,6 @@ TEST_CASE("vmath/fun") {
REQUIRE_FALSE(isnan(1.f)); REQUIRE_FALSE(isnan(1.f));
REQUIRE_FALSE(isinf(1.f)); REQUIRE_FALSE(isinf(1.f));
REQUIRE(isfinite(1.f)); REQUIRE(isfinite(1.f));
REQUIRE(isnormal(1.f));
REQUIRE_FALSE(issubnormal(1.f));
REQUIRE(fma(2.f, 3.f, 4.f) == approx(10.f)); REQUIRE(fma(2.f, 3.f, 4.f) == approx(10.f));

View File

@@ -95,7 +95,7 @@ TEST_CASE("vmath/vec_fun") {
(void)exp2(float2(1.f)); (void)exp2(float2(1.f));
(void)log2(float2(1.f)); (void)log2(float2(1.f));
(void)sqrt(float2(1.f)); (void)sqrt(float2(1.f));
(void)invsqrt(float2(1.f)); (void)rsqrt(float2(1.f));
} }
SECTION("Common Functions") { SECTION("Common Functions") {
@@ -144,8 +144,6 @@ TEST_CASE("vmath/vec_fun") {
REQUIRE_FALSE(isnan(float2(1.f)).x); REQUIRE_FALSE(isnan(float2(1.f)).x);
REQUIRE_FALSE(isinf(float2(1.f)).x); REQUIRE_FALSE(isinf(float2(1.f)).x);
REQUIRE(isfinite(float2(1.f)).x); REQUIRE(isfinite(float2(1.f)).x);
REQUIRE(isnormal(float2(1.f)).x);
REQUIRE_FALSE(issubnormal(float2(1.f)).x);
REQUIRE_FALSE(fma(float2(2.f), float2(3.f), float2(4.f)).x == Approx(12.f)); REQUIRE_FALSE(fma(float2(2.f), float2(3.f), float2(4.f)).x == Approx(12.f));