19 concept arithmetic = std::is_arithmetic_v<T>;
21#ifdef __cpp_lib_constexpr_cmath
34 constexpr bool isnan(std::integral
auto f)
noexcept {
return false; }
35 constexpr bool isnan(
float f) {
36 if (std::is_constant_evaluated())
37 return (std::bit_cast<uint32_t>(
f) & 0x7FFFFFFFu) > 0x7F800000u;
41 constexpr bool isnan(
double f) {
42 if (std::is_constant_evaluated())
43 return (std::bit_cast<uint64_t>(
f) & 0x7FFFFFFFFFFFFFFFull) > 0x7FF0000000000000ull;
47 constexpr bool isfinite(
float f) {
48 if (std::is_constant_evaluated())
49 return (std::bit_cast<uint32_t>(
f) & 0x7F800000u) != 0x7F800000u;
51 return std::isfinite(
f);
53 constexpr bool isfinite(
double f) {
54 if (std::is_constant_evaluated())
55 return (std::bit_cast<uint64_t>(
f) & 0x7FF0000000000000ull) != 0x7FF0000000000000ull;
57 return std::isfinite(
f);
62 template <std::
floating_po
int T,
typename RESULT = T>
65 if (std::is_constant_evaluated())
67 if (
num == -std::numeric_limits<T>::infinity())
68 return static_cast<RESULT>(-std::numeric_limits<T>::infinity());
69 else if (
num == std::numeric_limits<T>::infinity())
70 return static_cast<RESULT>(std::numeric_limits<T>::infinity());
72 return static_cast<RESULT>(std::numeric_limits<T>::quiet_NaN());
78 return std::floor(
num);
82 requires std::is_signed_v<T>
85 if (std::is_constant_evaluated())
87 if constexpr (std::floating_point<T> && std::numeric_limits<T>::is_iec559)
90 if constexpr (
sizeof(T) ==
sizeof(
uint64_t))
91 return (std::bit_cast<uint64_t>(
num) & 0x8000000000000000ull) != 0;
92 else if constexpr (
sizeof(T) ==
sizeof(
uint32_t))
93 return (std::bit_cast<uint32_t>(
num) & 0x80000000u) != 0;
94 else if constexpr (
sizeof(T) ==
sizeof(
uint16_t))
95 return (std::bit_cast<uint16_t>(
num) & 0x8000u) != 0;
96 else if constexpr (
sizeof(T) ==
sizeof(
uint8_t))
97 return (std::bit_cast<uint8_t>(
num) & 0x80u) != 0;
99 static_assert(
sizeof(T) ==
sizeof(
uint8_t),
"unsupported floating point type");
107 return std::signbit(
num);
110 template <
typename T>
111 requires (!std::is_signed_v<T>)
117 template <
typename T>
118 constexpr int sign(T
val)
120 if (::ghassanpl::cem::signbit(
val))
130 template <std::
floating_po
int T,
typename RESULT = T>
133 if (std::is_constant_evaluated())
135 if (
num == -std::numeric_limits<T>::infinity())
136 return static_cast<RESULT>(-std::numeric_limits<T>::infinity());
137 else if (
num == std::numeric_limits<T>::infinity())
138 return static_cast<RESULT>(std::numeric_limits<T>::infinity());
139 else if (::ghassanpl::cem::isnan(
num))
140 return static_cast<RESULT>(std::numeric_limits<T>::quiet_NaN());
146 return std::ceil(
num);
149 template <std::
floating_po
int T,
typename RESULT = T>
152 if (std::is_constant_evaluated())
155 return std::trunc(
num);
160 template <arithmetic T>
163 if (std::is_constant_evaluated())
164 return ::ghassanpl::cem::signbit(
num) ? -
num :
num;
165 else if constexpr (std::is_signed_v<T>)
166 return std::abs(
num);
171 template <arithmetic T, arithmetic U, arithmetic V>
172 constexpr auto fma(T a,
U b,
V c)
noexcept
174 if (std::is_constant_evaluated())
178 using CT = std::conditional_t<
179 std::floating_point<T> || std::floating_point<U> || std::floating_point<V>,
183 return std::fma((
CT)a, (
CT)b, (
CT)c);
187 template <arithmetic T, arithmetic U>
188 constexpr auto fmod(T a,
U b)
noexcept
190 using CT = std::conditional_t<
191 std::floating_point<T> || std::floating_point<U>,
192 decltype(fma(trunc(a / b), -b, a)),
195 if (std::is_constant_evaluated())
198 return std::numeric_limits<CT>::quiet_NaN();
201 else if (a == std::numeric_limits<T>::infinity() || a == -std::numeric_limits<T>::infinity())
202 return std::numeric_limits<CT>::quiet_NaN();
203 else if (b == std::numeric_limits<U>::infinity() || b == -std::numeric_limits<U>::infinity())
205 else if (::ghassanpl::cem::isnan(a) || ::ghassanpl::cem::isnan(b))
206 return std::numeric_limits<CT>::quiet_NaN();
208 return ::ghassanpl::cem::fma(::ghassanpl::cem::trunc((
CT)a / (
CT)b), -(
CT)b, (
CT)a);
211 return std::fmod((
CT)a, (
CT)b);
215 #include "constexpr_math.inl"
217 template <arithmetic T>
218 constexpr auto sqrt(T value)
noexcept
220 using CT = std::conditional_t<std::floating_point<T>, T,
double>;
221 if (std::is_constant_evaluated())
223 static_assert(std::numeric_limits<double>::is_iec559,
"sqrt only works for IEEE 754 floating point types");
224 return (
CT)::ghassanpl::cem::detail::sqrt_impl((
double)value);
227 return (
CT)std::sqrt(value);
230 template <arithmetic T, arithmetic U>
231 constexpr auto pow(T base,
U exponent)
noexcept
234 if (std::is_constant_evaluated())
236 if constexpr (std::integral<T> && std::integral<U>)
238 CT result =
static_cast<CT>(1);
240 result = result * base;
245 static_assert(std::numeric_limits<double>::is_iec559,
"pow only works for IEEE 754 floating point types");
246 return (
CT)::ghassanpl::cem::detail::pow_impl((
double)base, (
double)
exponent);
253 template <std::
integral T>
254 constexpr unsigned ilog2(T
val)
noexcept
257 if (
val >= (1ULL << 32)) { result += 32;
val >>= 32ULL; }
258 if (
val >= (1ULL << 16)) { result += 16;
val >>= 16ULL; }
259 if (
val >= (1ULL << 8)) { result += 8;
val >>= 8ULL; }
260 if (
val >= (1ULL << 4)) { result += 4;
val >>= 4ULL; }
261 if (
val >= (1ULL << 2)) { result += 2;
val >>= 2ULL; }
262 if (
val >= (1ULL << 1)) result += 1;
constexpr auto bit_count
Equal to the number of bits in the type.
constexpr bool signbit(T num)
can throw
constexpr RESULT floor(T num) noexcept
Shamelessly stolen from https://gist.github.com/Redchards/7f1b357bf3e686b55362.
constexpr auto abs(T num)
TODO: round.
constexpr RESULT ceil(T num) noexcept
TODO: sign return num > 0 ? 1 : (num < 0 ? -1 : 0);.
Primary namespace for everything in this library.