#pragma once #include #if defined(max) || defined(min) #error "stop defining 'min' and 'max' macros, evil people" #endif template static constexpr T Max() noexcept { return std::numeric_limits::max(); } template static constexpr T Min() noexcept { return std::numeric_limits::min(); } namespace NPrivate { struct TMax { template constexpr operator T() const { return Max(); } }; struct TMin { template constexpr operator T() const { return Min(); } }; } static constexpr ::NPrivate::TMax Max() noexcept { return {}; } static constexpr ::NPrivate::TMin Min() noexcept { return {}; } namespace NPrivate { template static constexpr double MaxFloorValue() { return N; } template static constexpr double MaxCeilValue() { return N; } template <> constexpr double MaxFloorValue<0x7FFF'FFFF'FFFF'FFFFull>() { return 9223372036854774784.0; // 0x7FFFFFFFFFFFFC00p0 } template <> constexpr double MaxCeilValue<0x7FFF'FFFF'FFFF'FFFFull>() { return 9223372036854775808.0; // 0x8000000000000000p0 } template <> constexpr double MaxFloorValue<0xFFFF'FFFF'FFFF'FFFFull>() { return 18446744073709549568.0; // 0xFFFFFFFFFFFFF800p0 } template <> constexpr double MaxCeilValue<0xFFFF'FFFF'FFFF'FFFFull>() { return 18446744073709551616.0; // 0x10000000000000000p0 } } // MaxFloor is the greatest double within the range of T. // // 1. If Max is an exact double, MaxFloor = Max = MaxCeil. // In this case some doubles above MaxFloor cast to T may round // to Max depending on the rounding mode. // // 2. Otherwise Max is between MaxFloor and MaxCeil, and // MaxFloor is the largest double that does not overflow T. template static constexpr double MaxFloor() noexcept { return ::NPrivate::MaxFloorValue()>(); } // MaxCeil is the smallest double not lesser than Max. // // 1. If Max is an exact double, MaxCeil = Max = MaxFloor. // // 2. Otherwise Max is between MaxFloor and MaxCeil, and // MaxCeil is the smallest double that overflows T. template static constexpr double MaxCeil() noexcept { return ::NPrivate::MaxCeilValue()>(); }