41namespace stellarlib::lin::internal
43#define STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(op, arg1, expr)\
46constexpr auto op(const T arg1) noexcept\
47 requires (std::is_arithmetic_v<T>)\
52template <typename T, std::size_t M, std::size_t N>\
54constexpr auto op(const matrix<T, M, N> &(arg1)) noexcept\
59 for (const auto [res, arg1] : std::views::zip(res, arg1)) {\
66#define STELLARLIB_LIN_INTRINSICS_DOUBLE_ARG_OPERATION_IMPL(op, arg1, arg2, expr)\
67template <typename T, typename U>\
69constexpr auto op(const T arg1, const U arg2) noexcept\
70 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)\
75template <typename T, std::size_t M, std::size_t N, typename U>\
77constexpr auto op(const matrix<T, M, N> &(arg1), const U arg2) noexcept\
78 -> matrix<std::common_type_t<T, U>, M, N>\
79 requires (std::is_arithmetic_v<U>)\
81 matrix<std::common_type_t<T, U>, M, N> res;\
83 for (const auto [res, arg1] : std::views::zip(res, arg1)) {\
84 res = op(arg1, arg2);\
90template <typename T, typename U, std::size_t M, std::size_t N>\
92constexpr auto op(const T arg1, const matrix<U, M, N> &(arg2)) noexcept\
93 -> matrix<std::common_type_t<T, U>, M, N>\
94 requires (std::is_arithmetic_v<T>)\
96 matrix<std::common_type_t<T, U>, M, N> res;\
98 for (const auto [res, arg2] : std::views::zip(res, arg2)) {\
99 res = op(arg1, arg2);\
105template <typename T, std::size_t M1, std::size_t N1, typename U, std::size_t M2, std::size_t N2>\
107constexpr auto op(const matrix<T, M1, N1> &(arg1), const matrix<U, M2, N2> &(arg2)) noexcept\
108 -> matrix<std::common_type_t<T, U>, M1, N1>\
109 requires ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2 || M1 == M2 && N1 == N2)\
111 matrix<std::common_type_t<T, U>, M1, N1> res;\
113 for (const auto [res, arg1, arg2] : std::views::zip(res, arg1, arg2)) {\
114 res = op(arg1, arg2);\
120#define STELLARLIB_LIN_INTRINSICS_TRIPLE_ARG_OPERATION_IMPL(op, arg1, arg2, arg3, expr)\
121template <typename T, typename U, typename V>\
123constexpr auto op(const T arg1, const U arg2, const V arg3) noexcept\
124 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U> && std::is_arithmetic_v<V>)\
129template <typename T, std::size_t M, std::size_t N, typename U, typename V>\
131constexpr auto op(const matrix<T, M, N> &(arg1), const U arg2, const V arg3) noexcept\
132 -> matrix<std::common_type_t<T, U, V>, M, N>\
133 requires (std::is_arithmetic_v<U> && std::is_arithmetic_v<V>)\
135 matrix<std::common_type_t<T, U, V>, M, N> res;\
137 for (const auto [res, arg1] : std::views::zip(res, arg1)) {\
138 res = op(arg1, arg2, arg3);\
144template <typename T, typename U, std::size_t M, std::size_t N, typename V>\
146constexpr auto op(const T arg1, const matrix<U, M, N> &(arg2), const V arg3) noexcept\
147 -> matrix<std::common_type_t<T, U, V>, M, N>\
148 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<V>)\
150 matrix<std::common_type_t<T, U, V>, M, N> res;\
152 for (const auto [res, arg2] : std::views::zip(res, arg2)) {\
153 res = op(arg1, arg2, arg3);\
159template <typename T, typename U, typename V, std::size_t M, std::size_t N>\
161constexpr auto op(const T arg1, const U arg2, const matrix<V, M, N> &(arg3)) noexcept\
162 -> matrix<std::common_type_t<T, U, V>, M, N>\
163 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)\
165 matrix<std::common_type_t<T, U, V>, M, N> res;\
167 for (const auto [res, arg3] : std::views::zip(res, arg3)) {\
168 res = op(arg1, arg2, arg3);\
174template <typename T, std::size_t M1, std::size_t N1, typename U, std::size_t M2, std::size_t N2, typename V>\
176constexpr auto op(const matrix<T, M1, N1> &(arg1), const matrix<U, M2, N2> &(arg2), const V arg3) noexcept\
177 -> matrix<std::common_type_t<T, U, V>, M1, N1>\
178 requires (std::is_arithmetic_v<V> && ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2 || M1 == M2 && N1 == N2))\
180 matrix<std::common_type_t<T, U, V>, M1, N1> res;\
182 for (const auto [res, arg1, arg2] : std::views::zip(res, arg1, arg2)) {\
183 res = op(arg1, arg2, arg3);\
189template <typename T, std::size_t M1, std::size_t N1, typename U, typename V, std::size_t M2, std::size_t N2>\
191constexpr auto op(const matrix<T, M1, N1> &(arg1), const U arg2, const matrix<V, M2, N2> &(arg3)) noexcept\
192 -> matrix<std::common_type_t<T, U, V>, M1, N1>\
193 requires (std::is_arithmetic_v<U> && ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2 || M1 == M2 && N1 == N2))\
195 matrix<std::common_type_t<T, U, V>, M1, N1> res;\
197 for (const auto [res, arg1, arg3] : std::views::zip(res, arg1, arg3)) {\
198 res = op(arg1, arg2, arg3);\
204template <typename T, typename U, std::size_t M1, std::size_t N1, typename V, std::size_t M2, std::size_t N2>\
206constexpr auto op(const T arg1, const matrix<U, M1, N1> &(arg2), const matrix<V, M2, N2> &(arg3)) noexcept\
207 -> matrix<std::common_type_t<T, U, V>, M1, N1>\
208 requires (std::is_arithmetic_v<T> && ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2 || M1 == M2 && N1 == N2))\
210 matrix<std::common_type_t<T, U, V>, M1, N1> res;\
212 for (const auto [res, arg2, arg3] : std::views::zip(res, arg2, arg3)) {\
213 res = op(arg1, arg2, arg3);\
219template <typename T, std::size_t M1, std::size_t N1, typename U, std::size_t M2, std::size_t N2, typename V, std::size_t M3, std::size_t N3>\
221constexpr auto op(const matrix<T, M1, N1> &(arg1), const matrix<U, M2, N2> &(arg2), const matrix<V, M3, N3> &(arg3)) noexcept\
222 -> matrix<std::common_type_t<T, U, V>, M1, N1>\
223 requires ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && (M3 == 1 || N3 == 1) && M1 * N1 == M2 * N2 && M2 * N2 == M3 * N3 || M1 == M2 && M2 == M3 && N1 == N2 && N2 == N3)\
225 matrix<std::common_type_t<T, U, V>, M1, N1> res;\
227 for (const auto [res, arg1, arg2, arg3] : std::views::zip(res, arg1, arg2, arg3)) {\
228 res = op(arg1, arg2, arg3);\
234STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(
abs, x, {
235 if constexpr (std::is_constant_evaluated()) {
236 return x < 0 ? -x : x;
243STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(acos, x, {
249constexpr auto all(
const T x)
noexcept
250 requires (std::is_arithmetic_v<T>)
252 return static_cast<bool>(x);
255template <
typename T, std::
size_t M, std::
size_t N>
259 return std::ranges::all_of(x,
static_cast<bool (*)(T)
>(all));
264constexpr auto any(
const T x)
noexcept
265 requires (std::is_arithmetic_v<T>)
267 return static_cast<bool>(x);
270template <
typename T, std::
size_t M, std::
size_t N>
274 return std::ranges::any_of(x,
static_cast<bool (*)(T)
>(any));
277STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(asin, x, {
281STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(atan, x, {
285STELLARLIB_LIN_INTRINSICS_DOUBLE_ARG_OPERATION_IMPL(atan2, y, x, {
286 return std::atan2(y, x);
289STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(ceil, x, {
293STELLARLIB_LIN_INTRINSICS_TRIPLE_ARG_OPERATION_IMPL(clamp, x, min, max, {
294 return SDL_clamp(x, min, max);
297STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(cos, x, {
301STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(cosh, x, {
305template <
typename T,
typename U>
307constexpr auto cross([[maybe_unused]]
const T x, [[maybe_unused]]
const U y)
noexcept
308 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
313template <
typename T, std::
size_t M, std::
size_t N,
typename U>
316 requires (std::is_arithmetic_v<U> && M * N == 3)
321template <
typename T,
typename U, std::
size_t M, std::
size_t N>
323constexpr auto cross(
const T x,
const matrix<U, M, N> &y)
noexcept
324 requires (std::is_arithmetic_v<T> && M * N == 3)
326 return matrix<std::common_type_t<T, U>, M, N>{x * y.z() - x * y.y(), x * y.x() - x * y.z(), x * y.y() - x * y.x()};
329template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2>
331constexpr auto cross(
const matrix<T, M1, N1> &x,
const matrix<U, M2, N2> &y)
noexcept
332 requires (M1 * N1 == 3 && M2 * N2 == 3)
334 return matrix<std::common_type_t<T, U>, M1, N1>{x.y() * y.z() - x.z() * y.y(), x.z() * y.x() - x.x() * y.z(), x.x() * y.y() - x.y() * y.x()};
337STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(degrees, x, {
338 return 180 / std::numbers::pi_v<T> * x;
352 return m[0][0] * m[1][1] - m[0][1] * m[1][0];
359 return m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
364constexpr auto determinant(
const matrix<T, 4, 4> &m)
noexcept
366 return m[0][0] * (m[1][1] * (m[2][2] * m[3][3] - m[2][3] * m[3][2]) - m[1][2] * (m[2][1] * m[3][3] - m[2][3] * m[3][1]) + m[1][3] * (m[2][1] * m[3][2] - m[2][2] * m[3][1])) - m[0][1] * (m[1][0] * (m[2][2] * m[3][3] - m[2][3] * m[3][2]) - m[1][2] * (m[2][0] * m[3][3] - m[2][3] * m[3][0]) + m[1][3] * (m[2][0] * m[3][2] - m[2][2] * m[3][0])) + m[0][2] * (m[1][0] * (m[2][1] * m[3][3] - m[2][3] * m[3][1]) - m[1][1] * (m[2][0] * m[3][3] - m[2][3] * m[3][0]) + m[1][3] * (m[2][0] * m[3][1] - m[2][1] * m[3][0])) - m[0][3] * (m[1][0] * (m[2][1] * m[3][2] - m[2][2] * m[3][1]) - m[1][1] * (m[2][0] * m[3][2] - m[2][2] * m[3][0]) + m[1][2] * (m[2][0] * m[3][1] - m[2][1] * m[3][0]));
369template <
typename T, std::
size_t N>
371constexpr auto determinant(matrix<T, N, N> m)
noexcept
375 for (
const auto i : std::views::iota(std::size_t{}, N)) {
378 for (
const auto j : std::views::iota(i + 1, N)) {
379 if (abs(m[pivot][i]) < abs(m[j][i])) {
385 for (
const auto j : std::views::iota(i, N)) {
386 std::swap(m[i][j], m[pivot][j]);
392 if (!
static_cast<bool>(m[i][i])) {
396 determinant *= m[i][i];
398 for (
const auto j : std::views::iota(i + 1, N)) {
401 for (
const auto k : std::views::iota(i + 1, N)) {
402 m[j][k] -= m[j][i] * m[i][k];
410STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(sqrt, x, {
417 requires (std::is_arithmetic_v<T>)
422template <
typename T, std::
size_t M, std::
size_t N>
425 requires (M == 1 || N == 1)
427 if constexpr (M * N == 2) {
428 return std::hypot(x.x(), x.y());
430 else if constexpr (M * N == 3) {
431 return std::hypot(x.x(), x.y(), x.z());
434 return std::ranges::fold_left(x, 0,
static_cast<T (*)(T, T)
>(std::hypot));
438template <
typename T,
typename U>
440constexpr auto distance(
const T x,
const U y)
noexcept
441 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
446template <
typename T, std::
size_t M, std::
size_t N,
typename U>
449 requires (std::is_arithmetic_v<U> && (M == 1 || N == 1))
451 return length(x - y);
454template <
typename T,
typename U, std::
size_t M, std::
size_t N>
457 requires (std::is_arithmetic_v<T> && (M == 1 || N == 1))
459 return length(x - y);
462template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2>
464constexpr auto distance(
const matrix<T, M1, N1> &x,
const matrix<U, M2, N2> &y)
noexcept
465 requires ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2)
467 return length(x - y);
470template <
typename T,
typename U>
472constexpr auto dot(
const T x,
const U y)
noexcept
473 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
478template <
typename T, std::
size_t M, std::
size_t N,
typename U>
481 requires (std::is_arithmetic_v<U> && (M == 1 || N == 1))
483 return std::ranges::fold_left(x | std::views::transform([y] [[nodiscard]] (
const auto x)
noexcept ->
auto {
488template <
typename T,
typename U, std::
size_t M, std::
size_t N>
490constexpr auto dot(
const T x,
const matrix<U, M, N> &y)
noexcept
491 requires (std::is_arithmetic_v<T> && (M == 1 || N == 1))
493 return std::ranges::fold_left(y | std::views::transform([x] [[nodiscard]] (
const auto y)
noexcept ->
auto {
498template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2>
500constexpr auto dot(
const matrix<T, M1, N1> &x,
const matrix<U, M2, N2> &y)
noexcept
501 requires ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2)
503 return std::ranges::fold_left(std::views::zip(x, y) | std::views::transform([] [[nodiscard]] (
const auto xy)
noexcept ->
auto {
504 return std::get<0>(xy) * std::get<1>(xy);
508template <
typename T,
typename U>
510constexpr auto dst(
const T src0,
const U src1)
noexcept
511 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
516template <
typename T, std::
size_t M, std::
size_t N,
typename U>
519 requires (std::is_arithmetic_v<U> && (M == 1 || N == 1) && M * N == 4)
524template <
typename T,
typename U, std::
size_t M, std::
size_t N>
526constexpr auto dst(
const T src0,
const matrix<U, M, N> &src1)
noexcept
527 requires (std::is_arithmetic_v<T> && (M == 1 || N == 1) && M * N == 4)
529 return matrix<std::common_type_t<T, U>, M, N>{1, src0 * src1.y(), src0, src1.w()};
532template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2>
534constexpr auto dst(
const matrix<T, M1, N1> &src0,
const matrix<U, M2, N2> &src1)
noexcept
535 requires ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == 4 && M2 * N2 == 4)
537 return matrix<std::common_type_t<T, U>, M1, N1>{1, src0.y() * src1.y(), src0.z(), src1.w()};
540STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(exp, x, {
544STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(exp2, x, {
548template <
typename T,
typename U,
typename V>
550constexpr auto faceforward(
const T n,
const U i,
const V ng)
noexcept
551 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U> && std::is_arithmetic_v<V>)
553 return std::common_type_t<T, U, V>{
dot(i, ng) < 0 ? n : -n};
556template <
typename T, std::
size_t M, std::
size_t N,
typename U,
typename V>
558constexpr auto faceforward(
const matrix<T, M, N> &n,
const U i,
const V ng)
noexcept
559 requires (std::is_arithmetic_v<U> && std::is_arithmetic_v<V> && (M == 1 || N == 1))
564template <
typename T,
typename U, std::
size_t M, std::
size_t N,
typename V>
566constexpr auto faceforward(
const T n,
const matrix<U, M, N> &i,
const V ng)
noexcept
567 -> matrix<std::common_type_t<T, U, V>, M, N>
568 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<V> && (M == 1 || N == 1))
570 matrix<std::common_type_t<T, U, V>, M, N> res;
572 if (dot(i, ng) < 0) {
573 for (
auto &res : res) {
578 for (
auto &res : res) {
586template <
typename T,
typename U,
typename V, std::
size_t M, std::
size_t N>
588constexpr auto faceforward(
const T n,
const U i,
const matrix<V, M, N> &ng)
noexcept
589 -> matrix<std::common_type_t<T, U, V>, M, N>
590 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U> && (M == 1 || N == 1))
592 matrix<std::common_type_t<T, U, V>, M, N> res;
594 if (dot(i, ng) < 0) {
595 for (
auto &res : res) {
600 for (
auto &res : res) {
608template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2,
typename V>
610constexpr auto faceforward(
const matrix<T, M1, N1> &n,
const matrix<U, M2, N2> &i,
const V ng)
noexcept
611 requires (std::is_arithmetic_v<V> && (M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2)
613 return matrix<std::common_type_t<T, U, V>, M1, N1>{dot(i, ng) < 0 ? n : -n};
616template <
typename T, std::
size_t M1, std::
size_t N1,
typename U,
typename V, std::
size_t M2, std::
size_t N2>
618constexpr auto faceforward(
const matrix<T, M1, N1> &n,
const U i,
const matrix<V, M2, N2> &ng)
noexcept
619 requires (std::is_arithmetic_v<U> && (M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2)
621 return matrix<std::common_type_t<T, U, V>, M1, N1>{dot(i, ng) < 0 ? n : -n};
624template <
typename T,
typename U, std::
size_t M1, std::
size_t N1,
typename V, std::
size_t M2, std::
size_t N2>
626constexpr auto faceforward(
const T n,
const matrix<U, M1, N1> &i,
const matrix<V, M2, N2> &ng)
noexcept
627 -> matrix<std::common_type_t<T, U, V>, M1, N1>
628 requires (std::is_arithmetic_v<T> && (M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2)
630 matrix<std::common_type_t<T, U, V>, M1, N1> res;
632 if (dot(i, ng) < 0) {
633 for (
auto &res : res) {
638 for (
auto &res : res) {
646template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2,
typename V, std::
size_t M3, std::
size_t N3>
648constexpr auto faceforward(
const matrix<T, M1, N1> &n,
const matrix<U, M2, N2> &i,
const matrix<V, M3, N3> &ng)
noexcept
649 requires ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && (M3 == 1 || N3 == 1) && M1 * N1 == M2 * N2 && M2 * N2 == M3 * N3)
651 return matrix<std::common_type_t<T, U, V>, M1, N1>{dot(i, ng) < 0 ? n : -n};
654STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(floor, x, {
655 return std::floor(x);
658STELLARLIB_LIN_INTRINSICS_TRIPLE_ARG_OPERATION_IMPL(fma, a, b, c, {
659 return std::fma(a, b, c);
662STELLARLIB_LIN_INTRINSICS_DOUBLE_ARG_OPERATION_IMPL(fmod, x, y, {
663 return std::fmod(x, y);
666STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(frac, x, {
670STELLARLIB_LIN_INTRINSICS_DOUBLE_ARG_OPERATION_IMPL(ldexp, x, exp, {
671 return std::ldexp(x,
static_cast<std::int32_t
>(exp));
674STELLARLIB_LIN_INTRINSICS_TRIPLE_ARG_OPERATION_IMPL(lerp, x, y, s, {
675 return std::lerp(x, y, s);
678STELLARLIB_LIN_INTRINSICS_DOUBLE_ARG_OPERATION_IMPL(max, x, y, {
679 return SDL_max(x, y);
682STELLARLIB_LIN_INTRINSICS_DOUBLE_ARG_OPERATION_IMPL(pow, x, y, {
683 return std::pow(x, y);
686template <
typename T,
typename U,
typename V>
688constexpr auto lit(
const T n_dot_l,
const U n_dot_h,
const V m)
noexcept
689 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U> && std::is_arithmetic_v<V>)
691 return matrix<std::common_type_t<T, U, V>, 1, 4>{1,
max(n_dot_l, std::common_type_t<T, U, V>{}), n_dot_l < 0 || n_dot_h < 0 ? 0 :
pow(n_dot_h, m), 1};
694STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(log, x, {
698STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(log10, x, {
699 return std::log10(x);
702STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(log2, x, {
706STELLARLIB_LIN_INTRINSICS_TRIPLE_ARG_OPERATION_IMPL(mad, mvalue, avalue, bvalue, {
707 if constexpr (std::is_constant_evaluated()) {
708 return mvalue * avalue + bvalue;
711 return fma(mvalue, avalue, bvalue);
715STELLARLIB_LIN_INTRINSICS_DOUBLE_ARG_OPERATION_IMPL(min, x, y, {
716 return SDL_min(x, y);
719template <
typename T,
typename U>
721constexpr auto modf(
const T x, U &ip)
noexcept
722 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
724 return std::modf(x, std::addressof(ip));
727template <
typename T,
typename U, std::
size_t M, std::
size_t N>
731 requires (std::is_arithmetic_v<T>)
734 res.front() = modf(x, ip.front());
736 for (
const auto i : std::views::iota(std::size_t{1}, M * N)) {
737 res.std::template array<std::common_type_t<T, U>, M * N>::operator[](i) = res.front();
738 ip.std::template array<U, M * N>::operator[](i) = ip.front();
744template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2>
746constexpr auto modf(
const matrix<T, M1, N1> &x, matrix<U, M2, N2> &ip)
noexcept
747 -> matrix<std::common_type_t<T, U>, M1, N1>
748 requires ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2 || M1 == M2 && N1 == N2)
750 matrix<std::common_type_t<T, U>, M1, N1> res;
752 for (
const auto [res, x, ip] : std::views::zip(res, x, ip)) {
759template <
typename T,
typename U>
761constexpr auto mul(
const T x,
const U y)
noexcept
762 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
767template <
typename T, std::
size_t M, std::
size_t N,
typename U>
770 requires (std::is_arithmetic_v<U>)
775template <
typename T,
typename U, std::
size_t M, std::
size_t N>
778 requires (std::is_arithmetic_v<T>)
783template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2>
785constexpr auto mul(
const matrix<T, M1, N1> &x,
const matrix<U, M2, N2> &y)
noexcept
786 -> matrix<std::common_type_t<T, U>, M1 == 1 || N1 == 1 ? 1 : M1, M2 == 1 || N2 == 1 ? 1 : N2>
787 requires ((M1 == 1 || N1 == 1) && M1 * N1 == M2 || (M2 == 1 || N2 == 1) && M2 * N2 == N1 || N1 == M2)
789 constexpr auto M{M1 == 1 || N1 == 1 ? 1 : M1};
790 constexpr auto N{(M1 == 1 || N1 == 1) && M1 * N1 == M2 ? M2 : N1};
791 constexpr auto P{M2 == 1 || N2 == 1 ? 1 : N2};
792 matrix<std::common_type_t<T, U>, M, P> res{};
794 for (
const auto m : std::views::iota(std::size_t{}, M)) {
795 for (
const auto n : std::views::iota(std::size_t{}, N)) {
796 for (
const auto p : std::views::iota(std::size_t{}, P)) {
797 res.std::template array<T, M * P>::operator[](mad(m, P, p)) += x.std::template array<T, M * N>::operator[](mad(m, N, n)) * y.std::template array<T, N * P>::operator[](mad(n, P, p));
808 requires (std::is_arithmetic_v<T>)
813template <
typename T, std::
size_t M, std::
size_t N>
816 requires (M == 1 || N == 1)
818 return x / length(x);
821STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(radians, x, {
822 return std::numbers::pi_v<T> / 180 * x;
825STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(rcp, x, {
829template <
typename T,
typename U>
831constexpr auto reflect(
const T i,
const U n)
noexcept
832 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
834 return i - std::common_type_t<T, U>{2} * n *
dot(i, n);
837template <
typename T, std::
size_t M, std::
size_t N,
typename U>
840 requires (std::is_arithmetic_v<U> && (M == 1 || N == 1))
842 return i - std::common_type_t<T, U>{2} * n * dot(i, n);
845template <
typename T,
typename U, std::
size_t M, std::
size_t N>
847constexpr auto reflect(
const T i,
const matrix<U, M, N> &n)
noexcept
848 requires (std::is_arithmetic_v<T> && (M == 1 || N == 1))
850 return i - std::common_type_t<T, U>{2} * n * dot(i, n);
853template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2>
855constexpr auto reflect(
const matrix<T, M1, N1> &i,
const matrix<U, M2, N2> &n)
noexcept
856 requires ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2)
858 return i - std::common_type_t<T, U>{2} * n * dot(i, n);
861#define STELLARLIB_LIN_INTRINSICS_REFRACT_IMPL(zero)\
863 const auto n_dot_i{dot(n, i)};\
864 const auto k{1 - eta * eta * (1 - n_dot_i * n_dot_i)};\
870 return eta * i - mad(eta, n_dot_i, sqrt(k)) * n;\
873template <
typename T,
typename U,
typename V>
875constexpr auto refract(
const T i,
const U n,
const V eta)
noexcept
876 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U> && std::is_arithmetic_v<V>)
877STELLARLIB_LIN_INTRINSICS_REFRACT_IMPL((std::common_type_t<T, U, V>{}));
879template <
typename T, std::
size_t M, std::
size_t N,
typename U,
typename V>
881constexpr auto refract(
const matrix<T, M, N> &i,
const U n,
const V eta)
noexcept
882 requires (std::is_arithmetic_v<U> && std::is_arithmetic_v<V> && (M == 1 || N == 1))
883STELLARLIB_LIN_INTRINSICS_REFRACT_IMPL((
matrix<std::common_type_t<T, U, V>, M, N>{}));
885template <
typename T,
typename U, std::
size_t M, std::
size_t N,
typename V>
887constexpr auto refract(
const T i,
const matrix<U, M, N> &n,
const V eta)
noexcept
888 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<V> && (M == 1 || N == 1))
889STELLARLIB_LIN_INTRINSICS_REFRACT_IMPL((
matrix<std::common_type_t<T, U, V>, M, N>{}));
891template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2,
typename V>
893constexpr auto refract(
const matrix<T, M1, N1> &i,
const matrix<U, M2, N2> &n,
const V eta)
noexcept
894 requires (std::is_arithmetic_v<V> && (M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2)
895STELLARLIB_LIN_INTRINSICS_REFRACT_IMPL((matrix<std::common_type_t<T, U, V>, M1, N1>{}));
897STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(round, x, {
898 return std::round(x);
901STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(rsqrt, x, {
905STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(saturate, x, {
906 return clamp(x, T{0}, T{1});
909STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(sign, x, {
910 return static_cast<T
>((0 < x) - (x < 0));
913STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(sin, x, {
917template <
typename T,
typename U,
typename V>
918constexpr void sincos(
const T x, U &s, V &c)
noexcept
919 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U> && std::is_arithmetic_v<V>)
925template <
typename T,
typename U, std::
size_t M, std::
size_t N,
typename V>
927 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<V>)
929 sincos(x, s.front(), c);
931 for (
const auto i : std::views::iota(std::size_t{1}, M * N)) {
932 s.std::template array<U, M * N>::operator[](i) = s.front();
936template <
typename T,
typename U,
typename V, std::
size_t M, std::
size_t N>
937constexpr void sincos(
const T x, U &s, matrix<V, M, N> &c)
noexcept
938 requires (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
940 sincos(x, s, c.front());
942 for (
const auto i : std::views::iota(std::size_t{1}, M * N)) {
943 c.std::template array<V, M * N>::operator[](i) = c.front();
947template <
typename T,
typename U, std::
size_t M1, std::
size_t N1,
typename V, std::
size_t M2, std::
size_t N2>
948constexpr void sincos(
const T x, matrix<U, M1, N1> &s, matrix<V, M2, N2> &c)
noexcept
949 requires (std::is_arithmetic_v<T> && ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && M1 * N1 == M2 * N2 || M1 == M2 && N2 == N1))
951 sincos(x, s.front(), c.front());
953 for (
const auto i : std::views::iota(std::size_t{1}, M1 * N1)) {
954 s.std::template array<U, M1 * N1>::operator[](i) = s.front();
955 c.std::template array<V, M2 * N2>::operator[](i) = c.front();
959template <
typename T, std::
size_t M1, std::
size_t N1,
typename U, std::
size_t M2, std::
size_t N2,
typename V, std::
size_t M3, std::
size_t N3>
960constexpr void sincos(
const matrix<T, M1, N1> &x, matrix<U, M2, N2> &s, matrix<V, M3, N3> &c)
noexcept
961 requires ((M1 == 1 || N1 == 1) && (M2 == 1 || N2 == 1) && (M3 == 1 || N3 == 1) && M1 * N1 == M2 * N2 && M2 * N2 == M3 * N3 || M1 == M2 && M2 == M3 && N1 == N2 && N2 == N3)
963 for (
const auto [x, s, c] : std::views::zip(x, s, c)) {
968STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(sinh, x, {
972STELLARLIB_LIN_INTRINSICS_TRIPLE_ARG_OPERATION_IMPL(smoothstep, min, max, x, {
973 const auto t{saturate((x - min) / (max - min))};
974 return t * t * (3 - 2 * t);
977STELLARLIB_LIN_INTRINSICS_DOUBLE_ARG_OPERATION_IMPL(step, y, x, {
978 return x < y ? (std::common_type_t<T, U>{0}) : (std::common_type_t<T, U>{1});
981STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(tan, x, {
985STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(tanh, x, {
992 requires (std::is_arithmetic_v<T>)
997template <
typename T, std::
size_t M, std::
size_t N>
1004 for (
const auto m : std::views::iota(std::size_t{}, M)) {
1005 for (
const auto n : std::views::iota(std::size_t{}, N)) {
1006 res.std::template array<T, N * M>::operator[](mad(n, M, m)) = x.std::template array<T, M * N>::operator[](mad(m, N, n));
1013STELLARLIB_LIN_INTRINSICS_SINGLE_ARG_OPERATION_IMPL(trunc, x, {
1014 return std::trunc(x);