18 concept arithmetic = std::is_arithmetic_v<T>;
20#ifdef __cpp_lib_constexpr_cmath
37 [[nodiscard]]
constexpr bool isnan(std::integral
auto f)
noexcept {
return false; }
38 [[nodiscard]]
constexpr bool isnan(
float f) {
39 if (std::is_constant_evaluated())
40 return (std::bit_cast<uint32_t>(f) & 0x7FFFFFFFu) > 0x7F800000u;
44 [[nodiscard]]
constexpr bool isnan(
double f) {
45 if (std::is_constant_evaluated())
46 return (std::bit_cast<uint64_t>(f) & 0x7FFFFFFFFFFFFFFFull) > 0x7FF0000000000000ull;
50 [[nodiscard]]
constexpr bool isfinite(std::integral
auto f)
noexcept {
return true; }
51 [[nodiscard]]
constexpr bool isfinite(
float f) {
52 if (std::is_constant_evaluated())
53 return (std::bit_cast<uint32_t>(f) & 0x7F800000u) != 0x7F800000u;
55 return std::isfinite(f);
57 [[nodiscard]]
constexpr bool isfinite(
double f) {
58 if (std::is_constant_evaluated())
59 return (std::bit_cast<uint64_t>(f) & 0x7FF0000000000000ull) != 0x7FF0000000000000ull;
61 return std::isfinite(f);
66 template <std::
floating_po
int T,
typename RESULT = T>
67 [[nodiscard]]
constexpr RESULT floor(T num)
noexcept
69 if (std::is_constant_evaluated())
71 if (num == -std::numeric_limits<T>::infinity())
72 return static_cast<RESULT
>(-std::numeric_limits<T>::infinity());
73 else if (num == std::numeric_limits<T>::infinity())
74 return static_cast<RESULT
>(std::numeric_limits<T>::infinity());
76 return static_cast<RESULT
>(std::numeric_limits<T>::quiet_NaN());
78 const auto res =
static_cast<int64_t
>(num);
79 return static_cast<RESULT
>((res > num) ? res - 1 : res);
82 return std::floor(num);
86 requires std::is_signed_v<T>
87 [[nodiscard]]
constexpr bool signbit(T num)
89 if (std::is_constant_evaluated())
91 if constexpr (std::floating_point<T> && std::numeric_limits<T>::is_iec559)
94 if constexpr (
sizeof(T) ==
sizeof(uint64_t))
95 return (std::bit_cast<uint64_t>(num) & 0x8000000000000000ull) != 0;
96 else if constexpr (
sizeof(T) ==
sizeof(uint32_t))
97 return (std::bit_cast<uint32_t>(num) & 0x80000000u) != 0;
98 else if constexpr (
sizeof(T) ==
sizeof(uint16_t))
99 return (std::bit_cast<uint16_t>(num) & 0x8000u) != 0;
100 else if constexpr (
sizeof(T) ==
sizeof(uint8_t))
101 return (std::bit_cast<uint8_t>(num) & 0x80u) != 0;
103 static_assert(
sizeof(T) ==
sizeof(uint8_t),
"unsupported floating point type");
111 return std::signbit(num);
114 template <
typename T>
115 requires (!std::is_signed_v<T>)
116 [[nodiscard]]
constexpr bool signbit(T val)
noexcept
121 template <
typename T>
122 [[nodiscard]]
constexpr int sign(T val)
124 return (T{} < val) - (val < T{});
134 template <std::
floating_po
int T,
typename RESULT = T>
135 [[nodiscard]]
constexpr RESULT ceil(T num)
noexcept
137 if (std::is_constant_evaluated())
139 if (num == -std::numeric_limits<T>::infinity())
140 return static_cast<RESULT
>(-std::numeric_limits<T>::infinity());
141 else if (num == std::numeric_limits<T>::infinity())
142 return static_cast<RESULT
>(std::numeric_limits<T>::infinity());
143 else if (::ghassanpl::cem::isnan(num))
144 return static_cast<RESULT
>(std::numeric_limits<T>::quiet_NaN());
146 const auto res =
static_cast<int64_t
>(num);
147 return static_cast<RESULT
>((res >= num) ? res : res + 1);
150 return std::ceil(num);
153 template <std::
floating_po
int T,
typename RESULT = T>
154 [[nodiscard]]
constexpr RESULT trunc(T num)
noexcept
156 if (std::is_constant_evaluated())
157 return num < T{} ? -::ghassanpl::cem::floor<T, RESULT>(-num) : ::ghassanpl::cem::floor<T, RESULT>(num);
159 return std::trunc(num);
164 template <arithmetic T>
165 [[nodiscard]]
constexpr auto abs(T num)
167 if (std::is_constant_evaluated())
168 return ::ghassanpl::cem::signbit(num) ? -num : num;
169 else if constexpr (std::is_signed_v<T>)
170 return std::abs(num);
175 template <arithmetic T, arithmetic U, arithmetic V>
176 [[nodiscard]]
constexpr auto fma(T a, U b, V c)
noexcept
178 if (std::is_constant_evaluated())
182 using CT = std::conditional_t<
183 std::floating_point<T> || std::floating_point<U> || std::floating_point<V>,
187 return std::fma((CT)a, (CT)b, (CT)c);
191 template <arithmetic T, arithmetic U>
192 [[nodiscard]]
constexpr auto fmod(T a, U b)
noexcept
194 using CT = std::conditional_t<
195 std::floating_point<T> || std::floating_point<U>,
196 decltype(fma(trunc(a / b), -b, a)),
199 if (std::is_constant_evaluated())
202 return std::numeric_limits<CT>::quiet_NaN();
205 else if (a == std::numeric_limits<T>::infinity() || a == -std::numeric_limits<T>::infinity())
206 return std::numeric_limits<CT>::quiet_NaN();
207 else if (b == std::numeric_limits<U>::infinity() || b == -std::numeric_limits<U>::infinity())
209 else if (::ghassanpl::cem::isnan(a) || ::ghassanpl::cem::isnan(b))
210 return std::numeric_limits<CT>::quiet_NaN();
212 return ::ghassanpl::cem::fma(::ghassanpl::cem::trunc((CT)a / (CT)b), -(CT)b, (CT)a);
215 return std::fmod((CT)a, (CT)b);
219 #include "constexpr_math.inl"
221 template <arithmetic T>
222 [[nodiscard]]
constexpr auto sqrt(T value)
noexcept
224 using CT = std::conditional_t<std::floating_point<T>, T,
double>;
225 if (std::is_constant_evaluated())
227 static_assert(std::numeric_limits<double>::is_iec559,
"sqrt only works for IEEE 754 floating point types");
228 return (CT)::ghassanpl::cem::detail::sqrt_impl((
double)value);
231 return (CT)std::sqrt(value);
234 template <arithmetic T, arithmetic U>
235 [[nodiscard]]
constexpr auto pow(T base, U exponent)
noexcept
237 using CT =
decltype(base * exponent);
238 if (std::is_constant_evaluated())
240 if constexpr (std::integral<T> && std::integral<U>)
242 CT result =
static_cast<CT
>(1);
243 while (exponent-- > 0)
244 result = result * base;
249 static_assert(std::numeric_limits<double>::is_iec559,
"pow only works for IEEE 754 floating point types");
250 return (CT)::ghassanpl::cem::detail::pow_impl((
double)base, (
double)exponent);
254 return (CT)std::pow(base, exponent);
257 template <std::
integral T>
258 [[nodiscard]]
constexpr unsigned ilog2(T val)
noexcept
261 if (val >= (1ULL << 32)) { result += 32; val >>= 32ULL; }
262 if (val >= (1ULL << 16)) { result += 16; val >>= 16ULL; }
263 if (val >= (1ULL << 8)) { result += 8; val >>= 8ULL; }
264 if (val >= (1ULL << 4)) { result += 4; val >>= 4ULL; }
265 if (val >= (1ULL << 2)) { result += 2; val >>= 2ULL; }
266 if (val >= (1ULL << 1)) result += 1;
270 [[nodiscard]]
constexpr inline double unlerp(
const double a,
const double b,
const double t)
noexcept
273 return (t - a) / (b - a);
Primary namespace for everything in this library.