MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
core/mtcore/math/core.hpp
Go to the documentation of this file.
1/*
2
3Copyright 2025 Matthew Tolman
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17*/
18
19#ifndef MTCORE_MATH_CORE_HPP
20#define MTCORE_MATH_CORE_HPP
21
22#include <type_traits>
23
27
31namespace mtcore::math {
40 template<typename T, typename R = double>
41 constexpr R floor_constexpr(T num) noexcept {
42 // Check to see if we're at our maximum supported radix range
43 // If we are, then the number we received is an integer since all the significant digits
44 // have to be positive at this point
45 const T max = static_cast<T>(static_cast<uint64_t>(1) << static_cast<uint64_t>(std::numeric_limits<T>::digits - 1));
46 if (num >= max || num <= -max) {
47 return static_cast<R>(num);
48 }
49 const auto a = static_cast<T>(static_cast<int64_t>(num));
50 return (num < 0 && num != a) ? static_cast<R>(a - 1) : static_cast<R>(a);
51 }
52
61 template<typename T, typename R = double>
62 constexpr R ceil_constexpr(T num) noexcept {
63 // Check to see if we're at our maximum supported radix range
64 // If we are, then the number we received is an integer since all the significant digits
65 // have to be positive at this point
66 const T max = static_cast<T>(static_cast<uint64_t>(1) << static_cast<uint64_t>(std::numeric_limits<T>::digits - 1));
67 if (num >= max || num <= -max) {
68 return num;
69 }
70 const auto a = static_cast<T>(static_cast<int64_t>(num));
71 return (num > 0 && num != a) ? static_cast<R>(a + 1) : static_cast<R>(a);
72 }
73
81 template<typename T, typename R = T>
82 constexpr R floor(T num) noexcept {
83 if constexpr (std::is_integral<T>::value) {
84 return static_cast<R>(num);
85 }
86 else if (std::is_constant_evaluated()) {
87 return floor_constexpr<T, R>(num);
88 }
89 else {
90 return static_cast<R>(std::floor(num));
91 }
92 }
93
94
102 template<typename T, typename R = T>
103 constexpr R ceil(T v) noexcept {
104 if constexpr (std::is_integral_v<T>) {
105 return static_cast<R>(v);
106 }
107 else if (std::is_constant_evaluated()) {
108 return ceil_constexpr<T, R>(v);
109 }
110 else {
111 return static_cast<R>(std::ceil(v));
112 }
113 }
114
127 template<typename L, typename R, typename Res = L>
128 constexpr Res mod(L left, R right) noexcept {
129 if (std::is_integral_v<L> || std::is_integral_v<R>) {
130 return static_cast<Res>(mod(static_cast<long double>(left), static_cast<long double>(right)));
131 }
132 else {
133 return static_cast<Res>(left - right * math::floor(left / right));
134 }
135 }
136
141 template<typename T>
142 constexpr auto mod_range(T x, i64 a, i64 b) noexcept -> T {
143 return a == b ? x : a + mod(x - a, b - a);
144 }
145
150 template<typename L, typename R, typename Res = L>
151 constexpr auto amod(L x, R y) noexcept -> Res {
152 return static_cast<Res>(y + mod(x, -y));
153 }
154
160 template<typename T, typename R = T>
161 constexpr auto approx_eq(T x, R y, T epsilon = T{0.000001}) noexcept -> bool {
162 return (x <= y + epsilon) & (x >= y - epsilon);
163 }
164
170 template<typename T>
171 constexpr int sign(const T &v) {
172 if (v < 0) {
173 return -1;
174 }
175 if (v > 0) {
176 return 1;
177 }
178 return 0;
179 }
180
187 template<typename L>
188 constexpr L abs(L l) {
189 return l * static_cast<L>(sign(l));
190 }
191
199 template<typename T>
200 constexpr T int_pow(T val, int exp) {
201 if (exp < 0) {
202 return int_pow(1 / val, -exp);
203 }
204 else if (exp == 0) {
205 return 1;
206 }
207 else if ((exp & 1) == 0) {
208 return int_pow(val * val, exp / 2);
209 }
210 else {
211 return val * int_pow(val * val, (exp - 1) / 2);
212 }
213 }
214
222 template<std::integral T>
223 constexpr T gcd(T a, T b) {
224 if (b == 0) {
225 return a;
226 }
227 return gcd(b, mod(a, b));
228 }
229
237 template<std::integral T>
238 constexpr T lcm(T a, T b) {
239 return abs(a) * (abs(b) / gcd(a, b));
240 }
241} // namespace mtcore::math
242
243#endif // MTCORE_MATH_CORE_HPP
constexpr auto approx_eq(T x, R y, T epsilon=T{0.000001}) noexcept -> bool
Checks if two numbers are approximately equal (within epsilon distance)
constexpr R floor(T num) noexcept
Floors a number with support for constexpr and fast runtime compilation.
constexpr R ceil_constexpr(T num) noexcept
Constexpr ceil function.
constexpr R ceil(T v) noexcept
Ceils a number with support for constexpr and fast runtime compilation.
constexpr Res mod(L left, R right) noexcept
Calculates the mathematical mod of two numbers.
constexpr auto amod(L x, R y) noexcept -> Res
x mod [1..y]
constexpr auto mod_range(T x, i64 a, i64 b) noexcept -> T
x mod [a..b)
constexpr R floor_constexpr(T num) noexcept
Constexpr floor function.
constexpr T lcm(T a, T b)
Calculates the LCM (Least Common Multiple) of two integer numbers.
constexpr int sign(const T &v)
Gets the sign (1 for positive, -1 for negative, 0 for zero)
constexpr L abs(L l)
Gets absolute value of a number.
constexpr T int_pow(T val, int exp)
Raises to an integer power (positive or negative)
constexpr T gcd(T a, T b)
Calculates the GCD (Greatest Common Divisor) of two integer numbers.
int64_t i64
Alias for 64-bit ints.
Math utilities, often with constexpr support.