mal-math
C++20 mathematics library.
All Classes Namespaces Files Functions Variables Typedefs Concepts
math-common.hpp
Go to the documentation of this file.
1#pragma once
2#include <array>
3#include <assert.h>
4#include <cmath>
5#include <concepts>
6#include <numbers>
7#include <ostream>
8#include <type_traits>
50namespace mal_math
51{
53 template <typename T>
54 concept Primitive = std::floating_point<T> || std::integral<T>;
55
57 template <size_t L, Primitive T>
58 struct vec;
59
60 namespace _detail
61 {
63 template <size_t L, Primitive T>
64 struct rvec;
65 } // namespace _detail
67 template <size_t rows, size_t columns, Primitive T>
68 struct mat;
69
71 template <size_t rows, size_t columns, Primitive T>
72 struct rmat;
73
74 namespace _detail
75 {
77 template <Primitive T>
79 {
80 public:
82 using type = T;
84 explicit constexpr primitive_reference_wrapper(T &ref) : ptr_{ std::addressof(ref) } {}
85
87 constexpr void set_ptr(T &ref) noexcept
88 {
89 ptr_ = std::addressof(ref);
90 }
91
93 constexpr operator T &() const noexcept
94 {
95 return *ptr_;
96 }
97 // Assignment operators for various types and situations
98 template <Primitive U>
99 constexpr primitive_reference_wrapper<T> &operator=(U const &v) requires(!std::is_const_v<T>)
100 {
101 *ptr_ = static_cast<T>(v);
102 return *this;
103 }
104 template <Primitive U>
105 constexpr primitive_reference_wrapper<T> &operator=(U &&v) requires(!std::is_const_v<T>)
106 {
107 *ptr_ = static_cast<T>(v);
108 return *this;
109 }
110
111 template <Primitive U>
112 constexpr primitive_reference_wrapper<T> &operator=(primitive_reference_wrapper<U> const &v) requires(!std::is_const_v<T>)
113 {
114 *ptr_ = static_cast<T>(*v.ptr_);
115 return *this;
116 }
117 template <Primitive U>
118 constexpr primitive_reference_wrapper<T> &operator=(primitive_reference_wrapper<U> &&v) requires(!std::is_const_v<T>)
119 {
120 *ptr_ = static_cast<T>(*v.ptr_);
121 return *this;
122 }
123
124 private:
126 T *ptr_{};
127
128 public:
129 template <class... Types>
130 constexpr auto operator()(Types &&...args) const
131 noexcept(noexcept(std::invoke(*ptr_, static_cast<Types &&>(args)...)))
132 -> decltype(std::invoke(*ptr_, static_cast<Types &&>(args)...))
133 {
134 return std::invoke(*ptr_, static_cast<Types &&>(args)...);
135 }
136 };
137
139 template <class T>
140 struct is_mat : public std::false_type
141 {};
143 template <size_t a, size_t b, Primitive T>
144 struct is_mat<mat<a, b, T>> : public std::true_type
145 {};
147 template <size_t a, size_t b, Primitive T>
148 struct is_mat<rmat<a, b, T>> : public std::true_type
149 {};
150
152 template <class T>
153 struct is_reference_vec : public std::false_type
154 {};
156 template <size_t size, Primitive T>
157 struct is_reference_vec<_detail::rvec<size, T>> : public std::true_type
158 {};
160 template <class T>
161 struct is_default_vec : public std::false_type
162 {};
164 template <size_t size, Primitive T>
165 struct is_default_vec<vec<size, T>> : public std::true_type
166 {};
167
169 template <class T>
170 constexpr bool is_mat_v = is_mat<T>::value;
171
173 template <class T>
176 template <class T>
179 template <class T>
181 } // namespace _detail
182
184 template <class T>
187 template <class T>
190 template <class T>
193 template <class T>
195
197 template <class T>
198 [[nodiscard]] bool almost_equal(T x, T y, int ulp = 2) requires(!std::numeric_limits<T>::is_integer)
199 {
200 // the machine epsilon has to be scaled to the magnitude of the values used
201 // and multiplied by the desired precision in ULPs (units in the last place)
202 return std::fabs(x - y) <=
203 std::numeric_limits<T>::epsilon() * std::fabs(x + y) * ulp
204 // unless the result is subnormal
205 || std::fabs(x - y) < std::numeric_limits<T>::min();
206 }
208 template <class T>
209 [[nodiscard]] constexpr T radians(T x) noexcept requires(!std::numeric_limits<T>::is_integer)
210 {
211 return (x / 180.0f) * static_cast<float>(std::numbers::pi);
212 }
214 template <Primitive T>
215 [[nodiscard]] inline constexpr T clamp(T x, T min, T max) noexcept { return x < min ? min : x > max ? max : x; }
216
217 template <Primitive T>
218 [[nodiscard]] inline float cos(T x) noexcept { return std::cosf(x); }
219 [[nodiscard]] inline double cos(double x) { return std::cos(x); }
220 [[nodiscard]] inline long double cos(long double x) { return std::cosl(x); }
221 template <Primitive T>
222 [[nodiscard]] inline float sin(T x) noexcept { return std::sinf(x); }
223 [[nodiscard]] inline double sin(double x) { return std::sin(x); }
224 [[nodiscard]] inline long double sin(long double x) { return std::sinl(x); }
225 template <Primitive T>
226 [[nodiscard]] inline float tan(T x) noexcept { return std::tanf(x); }
227 [[nodiscard]] inline double tan(double x) { return std::tan(x); }
228 [[nodiscard]] inline long double tan(long double x) { return std::tanl(x); }
229 template <Primitive T>
230 [[nodiscard]] inline float acos(T x) noexcept { return std::acosf(x); }
231 [[nodiscard]] inline double acos(double x) { return std::acos(x); }
232 [[nodiscard]] inline long double acos(long double x) { return std::acosl(x); }
233 template <Primitive T>
234 [[nodiscard]] inline float asin(T x) noexcept { return std::asinf(x); }
235 [[nodiscard]] inline double asin(double x) { return std::asin(x); }
236 [[nodiscard]] inline long double asin(long double x) { return std::asinl(x); }
237 template <Primitive T>
238 [[nodiscard]] inline float atan(T x) noexcept { return std::atanf(x); }
239 [[nodiscard]] inline double atan(double x) { return std::atan(x); }
240 [[nodiscard]] inline long double atan(long double x) { return std::atanl(x); }
241 template <Primitive T>
242 [[nodiscard]] inline float atan2(T x, T y) noexcept { return std::atan2f(x, y); }
243 [[nodiscard]] inline double atan2(double x, double y) { return std::atan2(x, y); }
244 [[nodiscard]] inline long double atan2(long double x, long double y) { return std::atan2l(x, y); }
245 template <Primitive T>
246 [[nodiscard]] inline float cosh(T x) noexcept { return std::coshf(x); }
247 [[nodiscard]] inline double cosh(double x) { return std::cosh(x); }
248 [[nodiscard]] inline long double cosh(long double x) { return std::coshl(x); }
249 template <Primitive T>
250 [[nodiscard]] inline float sinh(T x) noexcept { return std::sinhf(x); }
251 [[nodiscard]] inline double sinh(double x) { return std::sinh(x); }
252 [[nodiscard]] inline long double sinh(long double x) { return std::sinhl(x); }
253 template <Primitive T>
254 [[nodiscard]] inline float tanh(T x) noexcept { return std::tanhf(x); }
255 [[nodiscard]] inline double tanh(double x) { return std::tanh(x); }
256 [[nodiscard]] inline long double tanh(long double x) { return std::tanhl(x); }
257 template <Primitive T>
258 [[nodiscard]] inline float acosh(T x) noexcept { return std::acoshf(x); }
259 [[nodiscard]] inline double acosh(double x) { return std::acosh(x); }
260 [[nodiscard]] inline long double acosh(long double x) { return std::acoshl(x); }
261 template <Primitive T>
262 [[nodiscard]] inline float asinh(T x) noexcept { return std::asinhf(x); }
263 [[nodiscard]] inline double asinh(double x) { return std::asinh(x); }
264 [[nodiscard]] inline long double asinh(long double x) { return std::asinhl(x); }
265 template <Primitive T>
266 [[nodiscard]] inline float atanh(T x) noexcept { return std::atanhf(x); }
267 [[nodiscard]] inline double atanh(double x) { return std::atanh(x); }
268 [[nodiscard]] inline long double atanh(long double x) { return std::atanhl(x); }
269 template <Primitive T>
270 [[nodiscard]] inline float exp(T x) noexcept { return std::expf(x); }
271 [[nodiscard]] inline double exp(double x) { return std::exp(x); }
272 [[nodiscard]] inline long double exp(long double x) { return std::expl(x); }
273 template <Primitive T>
274 [[nodiscard]] inline float exp2(T x) noexcept { return std::exp2f(x); }
275 [[nodiscard]] inline double exp2(double x) { return std::exp2(x); }
276 [[nodiscard]] inline long double exp2(long double x) { return std::exp2l(x); }
277 template <Primitive T>
278 [[nodiscard]] inline float expm1(T x) noexcept { return std::expm1f(x); }
279 [[nodiscard]] inline double expm1(double x) { return std::expm1(x); }
280 [[nodiscard]] inline long double expm1(long double x) { return std::expm1l(x); }
281 template <Primitive T>
282 [[nodiscard]] inline float log(T x) noexcept { return std::logf(x); }
283 [[nodiscard]] inline double log(double x) { return std::log(x); }
284 [[nodiscard]] inline long double log(long double x) { return std::logl(x); }
285 template <Primitive T>
286 [[nodiscard]] inline float log2(T x) noexcept { return std::log2f(x); }
287 [[nodiscard]] inline double log2(double x) { return std::log2(x); }
288 [[nodiscard]] inline long double log2(long double x) { return std::log2l(x); }
289 template <Primitive T>
290 [[nodiscard]] inline float log10(T x) noexcept { return std::log10f(x); }
291 [[nodiscard]] inline double log10(double x) { return std::log10(x); }
292 [[nodiscard]] inline long double log10(long double x) { return std::log10l(x); }
293 template <Primitive T>
294 [[nodiscard]] inline float log1p(T x) noexcept { return std::log1pf(x); }
295 [[nodiscard]] inline double log1p(double x) { return std::log1p(x); }
296 [[nodiscard]] inline long double log1p(long double x) { return std::log1pl(x); }
297 template <Primitive T>
298 [[nodiscard]] inline float logb(T x) noexcept { return std::logbf(x); }
299 [[nodiscard]] inline double logb(double x) { return std::logb(x); }
300 [[nodiscard]] inline long double logb(long double x) { return std::logbl(x); }
301 template <Primitive T>
302 [[nodiscard]] inline float sqrt(T x) noexcept { return std::sqrtf(x); }
303 [[nodiscard]] inline double sqrt(double x) { return std::sqrt(x); }
304 [[nodiscard]] inline long double sqrt(long double x) { return std::sqrtl(x); }
305 template <Primitive T>
306 [[nodiscard]] inline float inversesqrt(T x) noexcept { return 1.0f / std::sqrtf(x); }
307 [[nodiscard]] inline double inversesqrt(double x) { return 1.0 / std::sqrt(x); }
308 [[nodiscard]] inline long double inversesqrt(long double x) { return 1.0l / std::sqrtl(x); }
309 template <Primitive T>
310 [[nodiscard]] inline T abs(T x) noexcept { return std::abs(x); }
311 template <Primitive T>
312 [[nodiscard]] inline int sign(T x) noexcept { return x < 0 ? -1 : 1; }
313 template <Primitive T>
314 [[nodiscard]] inline T floor(T x) noexcept { return std::floor(x); }
315 template <Primitive T>
316 [[nodiscard]] inline T ceil(T x) noexcept { return std::ceil(x); }
317 template <Primitive T>
318 [[nodiscard]] inline T trunc(T x) noexcept { return std::trunc(x); }
319 template <Primitive T>
320 [[nodiscard]] inline T round(T x) noexcept { return std::round(x); }
321 template <Primitive T>
322 [[nodiscard]] inline T roundEven(T x) noexcept { return std::nearbyint(x); }
323 template <Primitive T>
324 [[nodiscard]] inline T fract(T x) noexcept { return x - std::trunc(x); }
325 template <Primitive T, Primitive U>
326 [[nodiscard]] inline float mod(T x, U y) noexcept { return std::fmodf(x, y); }
327 [[nodiscard]] inline double mod(double x, double y) { return std::fmod(x, y); }
328 [[nodiscard]] inline long double mod(long double x, long double y) { return std::fmodl(x, y); }
329
330 template <Primitive T, Primitive U>
331 [[nodiscard]] inline float pow(T x, U y) noexcept { return std::powf(x, y); }
332 template <Primitive U>
333 [[nodiscard]] inline double pow(double x, U y) { return std::pow(x, y); }
334 template <Primitive U>
335 [[nodiscard]] inline long double pow(long double x, U y) { return std::powl(x, y); }
336} // namespace mal_math
Reference wrapper for primitives which does not allow rebinding after instantiation.
constexpr primitive_reference_wrapper< T > & operator=(U &&v)
constexpr primitive_reference_wrapper< T > & operator=(primitive_reference_wrapper< U > &&v)
constexpr primitive_reference_wrapper< T > & operator=(primitive_reference_wrapper< U > const &v)
T type
Alias for the type of the wrapped primitive.
constexpr primitive_reference_wrapper(T &ref)
Constructor that sets the internal pointer to the given reference.
constexpr void set_ptr(T &ref) noexcept
Method to set the internal pointer (not recommended for common use due to the nature of the class)
constexpr auto operator()(Types &&...args) const noexcept(noexcept(std::invoke(*ptr_, static_cast< Types && >(args)...))) -> decltype(std::invoke(*ptr_, static_cast< Types && >(args)...))
T * ptr_
Pointer to the wrapped primitive.
constexpr primitive_reference_wrapper< T > & operator=(U const &v)
Concept to determine if a type is any kind of matrix.
Concept to determine if a type is any kind of vector.
Concept that ensures a type is either floating point or integral.
Concept to determine if a type is a reference vector.
Concept to determine if a type is a default vector.
constexpr bool is_mat_v
Boolean value which is true if the given type is a matrix.
constexpr bool is_default_vec_v
Boolean value which is true if the given type is a common vector.
constexpr bool is_reference_vec_v
Boolean value which is true if the given type is a reference vector.
constexpr bool is_vec_v
Boolean value which is true if the given type is any vector.
Contains mathematical utility functions and classes.
float atanh(T x) noexcept
float cos(T x) noexcept
constexpr vec< T::size, std::remove_const_t< typename T::type > > max(T const &left, U const max) noexcept
Returns a new vector with each element being the maximum of the corresponding element in left and min...
Definition vec_math.inl:798
float atan2(T x, T y) noexcept
float asin(T x) noexcept
float sin(T x) noexcept
float log1p(T x) noexcept
bool almost_equal(T x, T y, int ulp=2)
Function to determine if two values are almost equal within a certain tolerance.
float acos(T x) noexcept
float acosh(T x) noexcept
float log2(T x) noexcept
float expm1(T x) noexcept
float atan(T x) noexcept
float log10(T x) noexcept
float exp(T x) noexcept
float mod(T x, U y) noexcept
constexpr T clamp(T x, T min, T max) noexcept
Function to clamp a value between a minimum and maximum.
float tanh(T x) noexcept
T roundEven(T x) noexcept
float inversesqrt(T x) noexcept
float log(T x) noexcept
float exp2(T x) noexcept
T abs(T x) noexcept
T trunc(T x) noexcept
float sinh(T x) noexcept
float sqrt(T x) noexcept
T ceil(T x) noexcept
int sign(T x) noexcept
constexpr T radians(T x) noexcept
Function to convert degrees to radians.
T floor(T x) noexcept
float asinh(T x) noexcept
float pow(T x, U y) noexcept
T round(T x) noexcept
float tan(T x) noexcept
float cosh(T x) noexcept
float logb(T x) noexcept
constexpr vec< T::size, std::remove_const_t< typename T::type > > min(T const &left, U const min) noexcept
Returns a new vector with each element being the minimum of the corresponding element in left and max...
Definition vec_math.inl:787
T fract(T x) noexcept
STL namespace.
Trait to determine if a type is a default vector.
Trait to determine if a type is a matrix.
Trait to determine if a type is a reference vector.
Internal detail definition of a reference vector with fixed size L and type T
Definition of matrix with dimensions rows x columns and type T
Definition matnxn.hpp:39
Definition of a reference matrix with dimensions rows x columns and type T
Definition rmatnxn.hpp:45
Definition of the mathematical vector with fixed size L and type T
Definition vecn.hpp:22