Convert float32 to float16 using IEEE 754 round-to-nearest, ties-to-even. Layout of float32: [S|EEEEEEEE|MMMMMMMMMMMMMMMMMMMMMMM] (1+8+23 bits) Layout of float16: [S|EEEEE|MMMMMMMMMM] (1+5+10 bits) Exponent bias: 127 (f32) vs 15 (f16).
| 28 | // Layout of float16: [S|EEEEE|MMMMMMMMMM] (1+5+10 bits) |
| 29 | // Exponent bias: 127 (f32) vs 15 (f16). |
| 30 | float16_t float16_t::from_float(float f) noexcept { |
| 31 | uint32_t bits; |
| 32 | std::memcpy(&bits, &f, sizeof(bits)); |
| 33 | |
| 34 | const uint32_t sign = bits & 0x80000000u; |
| 35 | const uint32_t exp = (bits >> 23) & 0xFFu; |
| 36 | const uint32_t mantissa = bits & 0x007FFFFFu; |
| 37 | |
| 38 | // NaN or Infinity (f32 exp = 0xFF) |
| 39 | if (exp == 255u) { |
| 40 | if (mantissa == 0u) { |
| 41 | // ±Inf → ±Inf |
| 42 | return from_bits(static_cast<uint16_t>((sign >> 16) | 0x7C00u)); |
| 43 | } |
| 44 | // NaN → quiet NaN; map top 9 bits of f32 payload to f16 payload, |
| 45 | // force quiet bit (bit 9 of f16 fraction). |
| 46 | const uint32_t nan_payload = (mantissa >> 13) & 0x03FFu; |
| 47 | const uint32_t quiet_bit = 0x0200u; |
| 48 | return from_bits(static_cast<uint16_t>((sign >> 16) | 0x7C00u | quiet_bit | |
| 49 | nan_payload)); |
| 50 | } |
| 51 | |
| 52 | // ±0 (also catches -0.0) |
| 53 | if (exp == 0u && mantissa == 0u) { |
| 54 | return from_bits(static_cast<uint16_t>(sign >> 16)); |
| 55 | } |
| 56 | |
| 57 | // Convert exponent bias: 127 → 15 |
| 58 | const int32_t exp16 = static_cast<int32_t>(exp) - 127 + 15; |
| 59 | |
| 60 | // Overflow → ±Inf |
| 61 | if (exp16 >= 31) { |
| 62 | return from_bits(static_cast<uint16_t>((sign >> 16) | 0x7C00u)); |
| 63 | } |
| 64 | |
| 65 | // Underflow: result is a f16 subnormal, or flushes to ±0. |
| 66 | if (exp16 <= 0) { |
| 67 | // Values with exp16 < -10 are too small even for the smallest f16 |
| 68 | // subnormal (2^-24); also handles all f32 subnormal inputs (exp==0). |
| 69 | if (exp16 < -10) { |
| 70 | return from_bits(static_cast<uint16_t>(sign >> 16)); |
| 71 | } |
| 72 | // Assemble f16 subnormal. The f32 normal implicit leading 1 participates |
| 73 | // in the f16 mantissa, so include it explicitly. |
| 74 | const uint32_t full_mantissa = (1u << 23) | mantissa; |
| 75 | // Total right-shift to produce the 10-bit f16 subnormal mantissa: |
| 76 | // 13 bits (to drop from 23 to 10) + (1 - exp16) for subnormal scaling. |
| 77 | const int32_t shift_total = 13 + (1 - exp16); |
| 78 | const uint32_t round_bit = 1u << (shift_total - 1); |
| 79 | const uint32_t sticky_mask = round_bit - 1u; |
| 80 | const bool sticky = (full_mantissa & sticky_mask) != 0u; |
| 81 | const uint32_t mantissa16 = full_mantissa >> shift_total; |
| 82 | // Round-to-nearest, ties-to-even |
| 83 | const uint32_t result = ((full_mantissa & round_bit) != 0u && |
| 84 | (sticky || (mantissa16 & 1u) != 0u)) |
| 85 | ? mantissa16 + 1u |
| 86 | : mantissa16; |
| 87 | // Note: if rounding carries out of the subnormal mantissa the natural |
no outgoing calls
no test coverage detected