From cbbf33778e288856e48f7bcd23b1b1a8c2707d59 Mon Sep 17 00:00:00 2001 From: Josh Allen Date: Thu, 16 Feb 2017 06:23:12 -0500 Subject: full implementation of half float to single float --- src/ootx_decoder.c | 54 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 15 deletions(-) (limited to 'src/ootx_decoder.c') diff --git a/src/ootx_decoder.c b/src/ootx_decoder.c index 3823beb..8ec16f2 100644 --- a/src/ootx_decoder.c +++ b/src/ootx_decoder.c @@ -166,30 +166,54 @@ uint8_t* get_ptr(uint8_t* data, uint8_t bytes, uint16_t* idx) { return x; } -float _half_to_float(uint8_t* data) { - //this will not handle denormalized floats +/* simply doing: +float f = 0; +uint32_t *ftmp = (uint32_t*)&f; //use the allocated floating point memory +This can cause problem when strict aliasing (-O2) is used. +Reads and writes to f and ftmp would be considered independent and could be +be reordered by the compiler. A union solves that problem. +*/ +union iFloat { + uint32_t i; + float f; +}; +float _half_to_float(uint8_t* data) { uint16_t x = *(uint16_t*)data; - float f = 0; - - uint32_t *ftmp = (uint32_t*)&f; //use the allocated floating point memory + union iFloat fnum; + fnum.f = 0; //sign - *ftmp = x & 0x8000; - *ftmp <<= 16; - - if ((x & 0x7FFF) == 0) return f; //signed zero + fnum.i = (x & 0x8000)<<16; + + if ((x & 0x7FFF) == 0) return fnum.f; //signed zero + + if ((x & 0x7c00) == 0) { + //denormalized + x = (x&0x3ff)<<1; //only mantissa, advance intrinsic bit forward + uint8_t e = 0; + //shift until intrinsic bit of mantissa overflows into exponent + //increment exponent each time + while ((x&0x0400) == 0) { + x<<=1; + e++; + } + fnum.i |= ((uint32_t)(112-e))<<23; //bias exponent to 127, half floats are biased 15 so only need to go 112 more. + fnum.i |= ((uint32_t)(x&0x3ff))<<13; //insert mantissa + return fnum.f; + } if((x&0x7c00) == 0x7c00) { - //for infinity, fraction is 0 (just copy in 0 bits) - //for NaN, fraction is anything non zero (copy in bits, no need to shift) - *ftmp |= 0x7f800000 | (x & 0x3ff); - return f; + //for infinity, fraction is 0 + //for NaN, fraction is anything non zero + //we could just copy in bits and not shift, but the mantissa of a NaN can have meaning + fnum.i |= 0x7f800000 | ((uint32_t)(x & 0x3ff))<<13; + return fnum.f; } - *ftmp += ((((uint32_t)(x & 0x7fff)) + 0x1c000u) << 13); + fnum.i |= ((((uint32_t)(x & 0x7fff)) + 0x1c000u) << 13); - return f; + return fnum.f; } void init_lighthouse_info_v6(lighthouse_info_v6* lhi, uint8_t* data) { -- cgit v1.2.3