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#if (defined(__clang_major__) && !defined(__APPLE__) && (__clang_major__ >= 10)) ||                                                        \ 
  126    (defined(__clang_major__) && defined(__APPLE__) && (__clang_major__ >= 13)) 
  127            DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wimplicit-int-float-conversion\""); 
 
  129            return tmp >= numeric_limits<INT_TYPE>::max () ? numeric_limits<INT_TYPE>::max () : static_cast<INT_TYPE> (tmp);
 
  130#if (defined(__clang_major__) && !defined(__APPLE__) && (__clang_major__ >= 10)) ||                                                        \ 
  131    (defined(__clang_major__) && defined(__APPLE__) && (__clang_major__ >= 13)) 
  132            DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wimplicit-int-float-conversion\"");
 
  136            return tmp <= numeric_limits<INT_TYPE>::min () ? numeric_limits<INT_TYPE>::min () : static_cast<INT_TYPE> (tmp);
 
  139    template <
floating_po
int FLOAT_TYPE>
 
  140    inline FLOAT_TYPE Round (FLOAT_TYPE n, 
unsigned int nDigitsOfPrecision)
 
  142        using Common::StdCompat::isinf;
 
  143        using Common::StdCompat::isnan;
 
  144        Require (nDigitsOfPrecision >= 1);
 
  145        if (isnan (n) or isinf (n)) [[unlikely]] {
 
  148        auto         absN                = fabs (n);
 
  149        unsigned int digitsBeforeDecimal = 0;
 
  151            digitsBeforeDecimal = Trunc<unsigned int> (log10 (absN)) + 1;
 
  153        FLOAT_TYPE pow10Shifter = pow (10, 
static_cast<int> (nDigitsOfPrecision) - 
static_cast<int> (digitsBeforeDecimal));
 
  154        return round (n * pow10Shifter) / pow10Shifter;
 
  163        void ThrowTruncOfNAN_ ();
 
  165    template <
integral INT_TYPE, 
floating_po
int FLOAT_TYPE>
 
  166    constexpr INT_TYPE Trunc (FLOAT_TYPE n)
 
  168        using Common::StdCompat::isnan;
 
  169        if (isnan (n)) [[unlikely]] {
 
  170            Private_::ThrowTruncOfNAN_ ();
 
  172        FLOAT_TYPE tmp = ::trunc (n);
 
  174#if (defined(__clang_major__) && !defined(__APPLE__) && (__clang_major__ >= 10)) ||                                                        \ 
  175    (defined(__clang_major__) && defined(__APPLE__) && (__clang_major__ >= 13)) 
  176            DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wimplicit-int-float-conversion\""); 
 
  178            return tmp >= numeric_limits<INT_TYPE>::max () ? numeric_limits<INT_TYPE>::max () : static_cast<INT_TYPE> (tmp);
 
  179#if (defined(__clang_major__) && !defined(__APPLE__) && (__clang_major__ >= 10)) ||                                                        \ 
  180    (defined(__clang_major__) && defined(__APPLE__) && (__clang_major__ >= 13)) 
  181            DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wimplicit-int-float-conversion\"");
 
  185            return tmp <= numeric_limits<INT_TYPE>::min () ? numeric_limits<INT_TYPE>::min () : static_cast<INT_TYPE> (tmp);
 
  194    template <Common::IBuiltinArithmetic T1, Common::IBuiltinArithmetic T2, 
typename EPSILON_TYPE>
 
  195    constexpr bool NearlyEquals (T1 l, T2 r, EPSILON_TYPE epsilon)
 
  197        using Common::StdCompat::isinf;
 
  198        using Common::StdCompat::isnan;
 
  199        if (isnan (l) or isnan (r)) [[unlikely]] {
 
  202        else if (isinf (l) or isinf (r)) [[unlikely]] {
 
  208        Require (epsilon >= 0); 
 
  209        Assert (not isnan (l) and not isnan (r) and not isinf (l) and not isinf (r));
 
  210        return Abs (diff) <= epsilon;
 
  212    template <Common::IBuiltinArithmetic T1, Common::IBuiltinArithmetic T2>
 
  213    constexpr bool NearlyEquals (T1 l, T2 r)
 
  215        using TC = common_type_t<T1, T2>;
 
  216        if constexpr (floating_point<TC>) {
 
  217            constexpr TC kEpsilon_ = 10000 * numeric_limits<TC>::epsilon (); 
 
  220            TC useEpsilon = kEpsilon_ * std::max<TC> ({
static_cast<TC
> (1.0), 
static_cast<TC
> (Abs (l)), 
static_cast<TC
> (Abs (r))});
 
  221            return NearlyEquals (l, r, useEpsilon);
 
  233    template <
floating_po
int T>
 
  234    constexpr T PinToSpecialPoint (T p, T special)
 
  236        if (Math::NearlyEquals (p, special)) {
 
  241    template <
floating_po
int T>
 
  242    constexpr T PinToSpecialPoint (T p, T special, T epsilon)
 
  244        if (Math::NearlyEquals (p, special, epsilon)) {
 
  255    template <
typename T>
 
  256    [[deprecated (
"Since Stroika v3.0d12 - use std::clamp")]] 
constexpr T PinInRange (T initialValue, T lowerBound, T upperBound)
 
  258        Require (lowerBound <= upperBound);
 
  259        auto r  = max (lowerBound, min (upperBound, initialValue));
 
  260        auto r2 = clamp (initialValue, lowerBound, upperBound);
 
  270    template <
typename T>
 
  271    constexpr T AtLeast (T initialValue, T lowerBound)
 
  273        return max (initialValue, lowerBound);
 
  281    template <
typename T>
 
  282    constexpr T AtMost (T initialValue, T upperBound)
 
  284        return min (initialValue, upperBound);
 
  292    template <
typename NEW_T, 
typename T>
 
  293    constexpr NEW_T PinToMaxForType (T initialValue)
 
  295        using LargerType = 
decltype (NEW_T{} + T{}); 
 
  296        return static_cast<NEW_T
> (min<LargerType> (initialValue, numeric_limits<NEW_T>::max ()));
 
  304    template <Common::IBuiltinArithmetic T, 
typename RESULT_TYPE>
 
  305    constexpr RESULT_TYPE Abs (T v)
 
  307#if __cplusplus >= kStrokia_Foundation_Common_cplusplus_23 
  308        if constexpr (Common::IAnyOf<T, int, intmax_t>) {
 
  311        else if constexpr (Common::IAnyOf<T, long>) {
 
  312            return std::labs (v);
 
  314        else if constexpr (Common::IAnyOf<T, long long>) {
 
  315            return std::llabs (v);
 
  318        return v < 0 ? -v : v;
 
  326    template <
integral T>
 
  327    constexpr bool IsOdd (T v)
 
  337    template <
integral T>
 
  338    constexpr bool IsEven (T v)
 
  340        static_assert (integral<T>);
 
  349    template <
integral T>
 
  361        T checkUpTo = 
static_cast<T
> (::sqrt (v)) + 
static_cast<T
> (1);
 
  363        for (T d = 2; d <= checkUpTo; ++d) {
 
  376    template <
integral T>
 
  377    T PrimeAtLeastThisBig (T v)
 
  379        while (not IsPrime (v)) {
 
constexpr bool isnan(T v) noexcept