Line data Source code
1 : #include "float16.h" 2 : /* 3 : float16 implementation 4 : 5 : Note that this is IEEE half-precision 16-bit float, *not* bfloat16 6 : 7 : algorithm with thanks to libcanard: 8 : https://github.com/dronecan/libcanard 9 : */ 10 : 11 : 12 58 : float Float16_t::get(void) const 13 : { 14 : union FP32 { 15 : uint32_t u; 16 : float f; 17 : }; 18 58 : const union FP32 magic = { (254UL - 15UL) << 23U }; 19 58 : const union FP32 was_inf_nan = { (127UL + 16UL) << 23U }; 20 : union FP32 out; 21 : 22 58 : out.u = (v16 & 0x7FFFU) << 13U; 23 58 : out.f *= magic.f; 24 58 : if (out.f >= was_inf_nan.f) { 25 12 : out.u |= 255UL << 23U; 26 : } 27 58 : out.u |= (v16 & 0x8000UL) << 16U; 28 : 29 58 : return out.f; 30 : } 31 : 32 54 : void Float16_t::set(float value) 33 : { 34 : union FP32 35 : { 36 : uint32_t u; 37 : float f; 38 : }; 39 : 40 54 : const union FP32 f32inf = { 255UL << 23U }; 41 54 : const union FP32 f16inf = { 31UL << 23U }; 42 54 : const union FP32 magic = { 15UL << 23U }; 43 54 : const uint32_t sign_mask = 0x80000000UL; 44 54 : const uint32_t round_mask = 0xFFFFF000UL; 45 : 46 : union FP32 in; 47 54 : in.f = value; 48 54 : uint32_t sign = in.u & sign_mask; 49 54 : in.u ^= sign; 50 : 51 54 : v16 = 0; 52 : 53 54 : if (in.u >= f32inf.u) 54 : { 55 6 : v16 = (in.u > f32inf.u) ? (uint16_t)0x7FFFU : (uint16_t)0x7C00U; 56 : } 57 : else 58 : { 59 48 : in.u &= round_mask; 60 48 : in.f *= magic.f; 61 48 : in.u -= round_mask; 62 48 : if (in.u > f16inf.u) 63 : { 64 2 : in.u = f16inf.u; 65 : } 66 48 : v16 = (uint16_t)(in.u >> 13U); 67 : } 68 : 69 54 : v16 |= (uint16_t)(sign >> 16U); 70 54 : }