blob: 26956d7d56991c92b78075753e4297da47ea64dd (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
#pragma once
#include <limits>
#if defined(max) || defined(min)
#error "stop defining 'min' and 'max' macros, evil people"
#endif
template <class T>
static constexpr T Max() noexcept {
return std::numeric_limits<T>::max();
}
template <class T>
static constexpr T Min() noexcept {
return std::numeric_limits<T>::min();
}
namespace NPrivate {
struct TMax {
template <class T>
constexpr operator T() const {
return Max<T>();
}
};
struct TMin {
template <class T>
constexpr operator T() const {
return Min<T>();
}
};
} // namespace NPrivate
static constexpr ::NPrivate::TMax Max() noexcept {
return {};
}
static constexpr ::NPrivate::TMin Min() noexcept {
return {};
}
namespace NPrivate {
template <unsigned long long N>
static constexpr double MaxFloorValue() {
return N;
}
template <unsigned long long N>
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
}
} // namespace NPrivate
// MaxFloor<T> is the greatest double within the range of T.
//
// 1. If Max<T> is an exact double, MaxFloor<T> = Max<T> = MaxCeil<T>.
// In this case some doubles above MaxFloor<T> cast to T may round
// to Max<T> depending on the rounding mode.
//
// 2. Otherwise Max<T> is between MaxFloor<T> and MaxCeil<T>, and
// MaxFloor<T> is the largest double that does not overflow T.
template <class T>
static constexpr double MaxFloor() noexcept {
return ::NPrivate::MaxFloorValue<Max<T>()>();
}
// MaxCeil<T> is the smallest double not lesser than Max<T>.
//
// 1. If Max<T> is an exact double, MaxCeil<T> = Max<T> = MaxFloor<T>.
//
// 2. Otherwise Max<T> is between MaxFloor<T> and MaxCeil<T>, and
// MaxCeil<T> is the smallest double that overflows T.
template <class T>
static constexpr double MaxCeil() noexcept {
return ::NPrivate::MaxCeilValue<Max<T>()>();
}
|