7#include "Stroika/Foundation/Common/Concepts.h"
11namespace Stroika::Foundation::Math {
18 template <
floating_po
int T>
21 return numeric_limits<T>::quiet_NaN ();
29 template <
floating_po
int T>
30 constexpr T infinity ()
32 return numeric_limits<T>::infinity ();
41 template <
unsigned_
integral T>
42 constexpr T RoundUpTo_UnSignedHelper_ (T x, T toNearest)
44 return (((x + toNearest - 1u) / toNearest) * toNearest);
46 template <
unsigned_
integral T>
47 constexpr T RoundDownTo_UnSignedHelper_ (T x, T toNearest)
49 return ((x / toNearest) * toNearest);
51 template <
signed_
integral T>
52 constexpr T RoundUpTo_SignedHelper_ (T x, T toNearest)
54 using UNSIGNED_T = make_unsigned_t<T>;
55 Require (toNearest > 0);
57 return (-
static_cast<T
> (RoundDownTo_UnSignedHelper_ (
static_cast<UNSIGNED_T
> (-x),
static_cast<UNSIGNED_T
> (toNearest))));
60 return static_cast<T
> (RoundUpTo_UnSignedHelper_<UNSIGNED_T> (x, toNearest));
63 template <
signed_
integral T>
64 constexpr T RoundDownTo_SignedHelper_ (T x, T toNearest)
66 using UNSIGNED_T = make_unsigned_t<T>;
67 Require (toNearest > 0);
69 return (-
static_cast<T
> (RoundUpTo_UnSignedHelper_ (
static_cast<UNSIGNED_T
> (-x),
static_cast<UNSIGNED_T
> (toNearest))));
72 return (RoundDownTo_UnSignedHelper_ (
static_cast<UNSIGNED_T
> (x),
static_cast<UNSIGNED_T
> (toNearest)));
75 template <
signed_
integral T>
76 constexpr T RoundUpTo_ (T x, T toNearest)
78 return Private::RoundUpTo_SignedHelper_<T> (x, toNearest);
80 template <
unsigned_
integral T>
81 constexpr T RoundUpTo_ (T x, T toNearest)
83 return Private::RoundUpTo_UnSignedHelper_<T> (x, toNearest);
85 template <
signed_
integral T>
86 constexpr T RoundDownTo_ (T x, T toNearest)
88 return Private::RoundDownTo_SignedHelper_<T> (x, toNearest);
90 template <
unsigned_
integral T>
91 constexpr T RoundDownTo_ (T x, T toNearest)
93 return Private::RoundDownTo_UnSignedHelper_<T> (x, toNearest);
96 template <Common::IBuiltinArithmetic T>
97 constexpr T RoundUpTo (T x, T toNearest)
100 return Private::RoundUpTo_ (x, toNearest);
108 template <Common::IBuiltinArithmetic T>
109 constexpr T RoundDownTo (T x, T toNearest)
112 return Private::RoundDownTo_ (x, toNearest);
120 template <
integral INT_TYPE,
floating_po
int FLOAT_TYPE>
121 constexpr INT_TYPE Round (FLOAT_TYPE n)
123 FLOAT_TYPE tmp = ::round (n);
125 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wimplicit-int-float-conversion\"");
126 return tmp >= numeric_limits<INT_TYPE>::max () ? numeric_limits<INT_TYPE>::max () : static_cast<INT_TYPE> (tmp);
127 DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wimplicit-int-float-conversion\"");
130 return tmp <= numeric_limits<INT_TYPE>::min () ? numeric_limits<INT_TYPE>::min () : static_cast<INT_TYPE> (tmp);
133 template <
floating_po
int FLOAT_TYPE>
134 inline FLOAT_TYPE Round (FLOAT_TYPE n,
unsigned int nDigitsOfPrecision)
136 using Common::StdCompat::isinf;
137 using Common::StdCompat::isnan;
138 Require (nDigitsOfPrecision >= 1);
139 if (isnan (n) or isinf (n)) [[unlikely]] {
142 auto absN = fabs (n);
143 unsigned int digitsBeforeDecimal = 0;
145 digitsBeforeDecimal = Trunc<unsigned int> (log10 (absN)) + 1;
147 FLOAT_TYPE pow10Shifter = pow (10,
static_cast<int> (nDigitsOfPrecision) -
static_cast<int> (digitsBeforeDecimal));
148 return round (n * pow10Shifter) / pow10Shifter;
157 void ThrowTruncOfNAN_ ();
159 template <
integral INT_TYPE,
floating_po
int FLOAT_TYPE>
160 constexpr INT_TYPE Trunc (FLOAT_TYPE n)
162 using Common::StdCompat::isnan;
163 if (isnan (n)) [[unlikely]] {
164 Private_::ThrowTruncOfNAN_ ();
166 FLOAT_TYPE tmp = ::trunc (n);
168 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wimplicit-int-float-conversion\"");
169 return tmp >= numeric_limits<INT_TYPE>::max () ? numeric_limits<INT_TYPE>::max () : static_cast<INT_TYPE> (tmp);
170 DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wimplicit-int-float-conversion\"");
173 return tmp <= numeric_limits<INT_TYPE>::min () ? numeric_limits<INT_TYPE>::min () : static_cast<INT_TYPE> (tmp);
182 template <Common::IBuiltinArithmetic T1, Common::IBuiltinArithmetic T2,
typename EPSILON_TYPE>
183 constexpr bool NearlyEquals (T1 l, T2 r, EPSILON_TYPE epsilon)
185 using Common::StdCompat::isinf;
186 using Common::StdCompat::isnan;
187 if (isnan (l) or isnan (r)) [[unlikely]] {
190 else if (isinf (l) or isinf (r)) [[unlikely]] {
196 Require (epsilon >= 0);
197 Assert (not isnan (l) and not isnan (r) and not isinf (l) and not isinf (r));
198 return Abs (diff) <= epsilon;
200 template <Common::IBuiltinArithmetic T1, Common::IBuiltinArithmetic T2>
201 constexpr bool NearlyEquals (T1 l, T2 r)
203 using TC = common_type_t<T1, T2>;
204 if constexpr (floating_point<TC>) {
205 constexpr TC kEpsilon_ = 10000 * numeric_limits<TC>::epsilon ();
208 TC useEpsilon = kEpsilon_ * std::max<TC> ({
static_cast<TC
> (1.0),
static_cast<TC
> (Abs (l)),
static_cast<TC
> (Abs (r))});
209 return NearlyEquals (l, r, useEpsilon);
221 template <
floating_po
int T>
222 constexpr T PinToSpecialPoint (T p, T special)
224 if (Math::NearlyEquals (p, special)) {
229 template <
floating_po
int T>
230 constexpr T PinToSpecialPoint (T p, T special, T epsilon)
232 if (Math::NearlyEquals (p, special, epsilon)) {
243 template <
typename T>
244 [[deprecated (
"Since Stroika v3.0d12 - use std::clamp")]]
constexpr T PinInRange (T initialValue, T lowerBound, T upperBound)
246 Require (lowerBound <= upperBound);
247 auto r = max (lowerBound, min (upperBound, initialValue));
248 auto r2 = clamp (initialValue, lowerBound, upperBound);
258 template <
typename T>
259 constexpr T AtLeast (T initialValue, T lowerBound)
261 return max (initialValue, lowerBound);
269 template <
typename T>
270 constexpr T AtMost (T initialValue, T upperBound)
272 return min (initialValue, upperBound);
280 template <
typename NEW_T,
typename T>
281 constexpr NEW_T PinToMaxForType (T initialValue)
283 using LargerType =
decltype (NEW_T{} + T{});
284 return static_cast<NEW_T
> (min<LargerType> (initialValue, numeric_limits<NEW_T>::max ()));
292 template <Common::IBuiltinArithmetic T,
typename RESULT_TYPE>
293 constexpr RESULT_TYPE Abs (T v)
295 if constexpr (is_unsigned_v<T>) {
299 return v < 0 ? -v : v;
308 template <
integral T>
309 constexpr bool IsOdd (T v)
319 template <
integral T>
320 constexpr bool IsEven (T v)
322 static_assert (integral<T>);
331 template <
integral T>
343 T checkUpTo =
static_cast<T
> (::sqrt (v)) +
static_cast<T
> (1);
345 for (T d = 2; d <= checkUpTo; ++d) {
358 template <
integral T>
359 T PrimeAtLeastThisBig (T v)
361 while (not IsPrime (v)) {
constexpr bool isnan(T v) noexcept