一呼百應, "one call, a hundred responses"
Loading...
Searching...
No Matches
bf16.hpp
Go to the documentation of this file.
1#pragma once
2
11#include <bit>
12#include <compare>
13#include <cstdint>
14#include <limits>
16
17namespace ein {
18
19struct bf16 {
20 using underlying_type = __bf16;
21
22 __bf16 content;
23
25 bf16() noexcept = default;
26
28 bf16(float f) noexcept : content(f) {}
29
31 bf16(__bf16 f) noexcept : content(f) {}
32
34 bf16(ein_noescape bf16 const &) noexcept = default;
35
37 bf16(ein_noescape bf16 &&) noexcept = default;
38
40 operator __bf16 (this bf16 self) noexcept { return self.content; }
41
43 operator float (this bf16 self) noexcept { return self.content; }
44
46 bf16 & operator = (ein_noescape bf16 const &) noexcept
47 ein_lifetimebound = default;
48
51 ein_lifetimebound = default;
52
54 friend constexpr bool operator == (bf16 x, bf16 y) noexcept {
55 return x.content == y.content;
56 }
57
59 friend constexpr std::partial_ordering operator <=> (bf16 x, bf16 y) noexcept {
60 return x.content <=> y.content;
61 }
62
64 friend constexpr bool operator != (bf16 x, bf16 y) noexcept {
65 return x.content != y.content;
66 }
67
69 friend constexpr bool operator < (bf16 x, bf16 y) noexcept {
70 return x.content < y.content;
71 }
72
74 friend constexpr bool operator > (bf16 x, bf16 y) noexcept {
75 return x.content > y.content;
76 }
77
79 friend constexpr bool operator <= (bf16 x, bf16 y) noexcept {
80 return x.content <= y.content;
81 }
82
84 friend constexpr bool operator >= (bf16 x, bf16 y) noexcept {
85 return x.content >= y.content;
86 }
87
89 friend constexpr void swap(
92 ) noexcept {
93 using std::swap;
94 swap(x.content,y.content);
95 }
96
98 static constexpr bf16 from_bits(uint16_t data) noexcept {
99 return std::bit_cast<bf16>(data);
100 }
101
103 constexpr uint16_t to_bits(this bf16 self) noexcept {
104 return std::bit_cast<uint16_t>(self.content);
105 }
106};
107
109constexpr bf16 operator""_bf16(long double v) noexcept {
110 return bf16(static_cast<float>(v));
111}
112
114constexpr bf16 fast_to_bf16(float f) noexcept {
115 if consteval {
116 return f;
117 } else {
118 return std::bit_cast<bf16>(static_cast<uint16_t>(std::bit_cast<uint32_t>(f)>>16));
119 }
120}
121
123constexpr bf16 fast_to_bf16(bf16 f) noexcept {
124 return f;
125}
126
127} // namespace ein
128
129namespace std {
131 constexpr bool isnan(ein::bf16 x) noexcept {
132 // Exponent maxed out and fraction non-zero indicates NaN
133 return (x.to_bits() & 0x7FFF) > 0x7F80;
134 }
135
136 template <> class numeric_limits<ein::bf16> {
137 public:
138 static constexpr bool is_specialized = true;
140 static constexpr ein::bf16 min() noexcept {
141 return ein::bf16::from_bits(0x007F);
142 }
144 static constexpr ein::bf16 max() noexcept {
145 return ein::bf16::from_bits(0x7F7F);
146 }
148 static constexpr ein::bf16 lowest() noexcept {
149 return ein::bf16::from_bits(0xFF7F);
150 }
151 static constexpr int digits = 7;
152 static constexpr int digits10 = 2;
153 static constexpr bool is_signed = true;
154 static constexpr bool is_integer = false;
155 static constexpr bool is_exact = false;
156 static constexpr int radix = 2;
158 static constexpr ein::bf16 epsilon() noexcept {
159 return ein::bf16::from_bits(0x3C00);
160 }
162 static constexpr ein::bf16 round_error() noexcept {
163 return ein::bf16::from_bits(0x3F00);
164 }
165 static constexpr int min_exponent = -125;
166 static constexpr int min_exponent10 = -37;
167 static constexpr int max_exponent = 128;
168 static constexpr int max_exponent10 = 38;
169 static constexpr bool has_infinity = true;
170 static constexpr bool has_quiet_NaN = true;
171 static constexpr bool has_signaling_NaN = true;
172 static constexpr float_denorm_style has_denorm = denorm_absent;
173 static constexpr bool has_denorm_loss = false;
175 static constexpr ein::bf16 infinity() noexcept {
176 return ein::bf16::from_bits(0x7F80);
177 }
179 static constexpr ein::bf16 quiet_NaN() noexcept {
180 return ein::bf16::from_bits(0x7FC0);
181 }
183 static constexpr ein::bf16 signaling_NaN() noexcept {
184 return ein::bf16::from_bits(0x7FC0);
185 }
187 static constexpr ein::bf16 denorm_min() noexcept {
188 return ein::bf16{};
189 }
190 static constexpr bool is_iec559 = false;
191 static constexpr bool is_bounded = false;
192 static constexpr bool is_modulo = false;
193 static constexpr bool traps = false;
194 static constexpr bool tinyness_before = false;
195 static constexpr float_round_style round_style = round_to_nearest;
196 };
197
198 extern template class numeric_limits<ein::bf16>;
199
200} // namespace std
201
202#if defined(EIN_TESTING) || defined(EIN_TESTING_BF16)
203TEST_CASE("bf16","[bf16]") {
204 using namespace ein;
205
206 SECTION("bf16 default constructors and conversion") {
207 CHECK(bf16(0.5f).content == Catch::Approx(0.5f));
208 CHECK(0.25_bf16 .content == Catch::Approx(0.25f));
209 CHECK(static_cast<float>(1.0_bf16) == Catch::Approx(1.0f));
210 }
211
212 SECTION("bf16 comparison operators") {
213 CHECK(0.5_bf16 == 0.5_bf16);
214 CHECK(0.1_bf16 < 0.2_bf16);
215 CHECK(0.3_bf16 > 0.2_bf16);
216 CHECK(0.2_bf16 <= 0.2_bf16);
217 CHECK(0.2_bf16 >= 0.2_bf16);
218
219 // Negative checks for inequality
220 CHECK_FALSE(0.5_bf16 < 0.5_bf16);
221 CHECK_FALSE(0.3_bf16 < 0.2_bf16);
222 CHECK_FALSE(0.1_bf16 > 0.2_bf16);
223 CHECK_FALSE(0.3_bf16 <= 0.2_bf16);
224 CHECK_FALSE(0.1_bf16 >= 0.2_bf16);
225 }
226
227 SECTION("bf16 swap function") {
228 bf16 x(1.0_bf16), y(2.0_bf16);
229 swap(x, y);
230 CHECK(x == 2.0_bf16);
231 CHECK(y == 1.0_bf16);
232 }
233
234 SECTION("bf16 bit operations") {
235 bf16 val = bf16::from_bits(0x3F00);
236 CHECK(val.to_bits() == 0x3F00);
237 CHECK(bf16::from_bits(0x7F80) == std::numeric_limits<bf16>::infinity());
238 }
239
240 SECTION("bf16 isnan function") {
241 CHECK(std::isnan(bf16::from_bits(0x7FC0)));
242 CHECK_FALSE(std::isnan(1.0_bf16));
243 }
244
245 SECTION("bf16 numeric_limits") {
246 using nl = std::numeric_limits<bf16>;
247
248 CHECK(nl::is_specialized);
249 CHECK(nl::is_signed);
250 CHECK(nl::digits == 7);
251 CHECK(nl::epsilon() == bf16::from_bits(0x3C00));
252 CHECK(nl::round_error() == bf16::from_bits(0x3F00));
253 CHECK(nl::min() == bf16::from_bits(0x007F));
254 CHECK(nl::max() == bf16::from_bits(0x7F7F));
255 CHECK(nl::lowest() == bf16::from_bits(0xFF7F));
256 CHECK(nl::infinity() == bf16::from_bits(0x7F80));
257 CHECK(std::isnan(nl::quiet_NaN()));
258 CHECK(std::isnan(nl::signaling_NaN()));
259 CHECK(nl::denorm_min() == bf16::from_bits(0));
260 }
261}
262#endif
static constexpr ein::bf16 infinity() noexcept
Definition bf16.hpp:175
static constexpr ein::bf16 epsilon() noexcept
Definition bf16.hpp:158
static constexpr ein::bf16 quiet_NaN() noexcept
Definition bf16.hpp:179
static constexpr ein::bf16 round_error() noexcept
Definition bf16.hpp:162
static constexpr ein::bf16 denorm_min() noexcept
Definition bf16.hpp:187
static constexpr ein::bf16 lowest() noexcept
Definition bf16.hpp:148
static constexpr ein::bf16 max() noexcept
Definition bf16.hpp:144
static constexpr ein::bf16 min() noexcept
Definition bf16.hpp:140
static constexpr ein::bf16 signaling_NaN() noexcept
Definition bf16.hpp:183
#define ein_reinitializes
[[clang::reinitializes]]
Definition common.hpp:418
#define ein_artificial
[[artificial]].
Definition common.hpp:220
#define ein_inline
inline [[always_inline]]
Definition common.hpp:188
#define ein_lifetimebound
[[lifetimebound]]
Definition common.hpp:137
#define ein_noescape
portable __attribute__((noescape))
Definition common.hpp:151
#define ein_nodiscard
C++17 [[nodiscard]].
Definition common.hpp:165
#define ein_const
[[const]] is not const
Definition common.hpp:84
Definition cpuid.cpp:16
constexpr bf16 fast_to_bf16(float f) noexcept
Definition bf16.hpp:114
Definition bf16.cpp:11
constexpr bool isnan(ein::bf16 x) noexcept
Definition bf16.hpp:131
constexpr bf16(bf16 &&) noexcept=default
__bf16 underlying_type
Definition bf16.hpp:20
constexpr bf16(__bf16 f) noexcept
Definition bf16.hpp:31
friend constexpr bool operator<(bf16 x, bf16 y) noexcept
Definition bf16.hpp:69
constexpr bf16(bf16 const &) noexcept=default
static constexpr bf16 from_bits(uint16_t data) noexcept
Definition bf16.hpp:98
constexpr uint16_t to_bits(this bf16 self) noexcept
Definition bf16.hpp:103
friend constexpr std::partial_ordering operator<=>(bf16 x, bf16 y) noexcept
Definition bf16.hpp:59
friend constexpr bool operator<=(bf16 x, bf16 y) noexcept
Definition bf16.hpp:79
friend constexpr bool operator>=(bf16 x, bf16 y) noexcept
Definition bf16.hpp:84
friend constexpr bool operator!=(bf16 x, bf16 y) noexcept
Definition bf16.hpp:64
friend constexpr bool operator>(bf16 x, bf16 y) noexcept
Definition bf16.hpp:74
friend constexpr void swap(bf16 &x, bf16 &y) noexcept
Definition bf16.hpp:89
constexpr bf16() noexcept=default
ein_reinitializes constexpr bf16 & operator=(bf16 const &) noexcept=default
__bf16 content
Definition bf16.hpp:22