| 17 | } |
| 18 | |
| 19 | class bfloat16_t { |
| 20 | public: |
| 21 | bfloat16_t() = default; |
| 22 | bfloat16_t(float f) { |
| 23 | *this = f; |
| 24 | } |
| 25 | |
| 26 | bfloat16_t& operator=(float f) { |
| 27 | auto iraw = bit_cast<std::array<uint16_t, 2>>(f); |
| 28 | switch (std::fpclassify(f)) { |
| 29 | case FP_SUBNORMAL: |
| 30 | case FP_ZERO: |
| 31 | // sign preserving zero (denormal go to zero) |
| 32 | _bits = iraw[1]; |
| 33 | _bits &= 0x8000; |
| 34 | break; |
| 35 | case FP_INFINITE: |
| 36 | _bits = iraw[1]; |
| 37 | break; |
| 38 | case FP_NAN: |
| 39 | // truncate and set MSB of the mantissa force QNAN |
| 40 | _bits = iraw[1]; |
| 41 | _bits |= 1 << 6; |
| 42 | break; |
| 43 | case FP_NORMAL: |
| 44 | // round to nearest even and truncate |
| 45 | const uint32_t rounding_bias = 0x00007FFF + (iraw[1] & 0x1); |
| 46 | const uint32_t int_raw = bit_cast<uint32_t>(f) + rounding_bias; |
| 47 | iraw = bit_cast<std::array<uint16_t, 2>>(int_raw); |
| 48 | _bits = iraw[1]; |
| 49 | break; |
| 50 | } |
| 51 | |
| 52 | return *this; |
| 53 | } |
| 54 | |
| 55 | operator float() const { |
| 56 | std::array<uint16_t, 2> iraw = {{0, _bits}}; |
| 57 | return bit_cast<float>(iraw); |
| 58 | } |
| 59 | |
| 60 | private: |
| 61 | uint16_t _bits; |
| 62 | |
| 63 | // Converts the 32 bits of a normal float or zero to the bits of a bfloat16. |
| 64 | static constexpr uint16_t convert_bits_of_normal_or_zero(const uint32_t bits) { |
| 65 | return uint32_t{bits + uint32_t{0x7FFFU + (uint32_t{bits >> 16} & 1U)}} >> 16; |
| 66 | } |
| 67 | }; |
| 68 | |
| 69 | } |
nothing calls this directly
no test coverage detected