aboutsummaryrefslogtreecommitdiff
path: root/src/ootx_decoder.c
diff options
context:
space:
mode:
authorJosh Allen <axlecrusher@gmail.com>2017-02-16 06:23:12 -0500
committerJosh Allen <axlecrusher@gmail.com>2017-02-16 06:23:12 -0500
commitcbbf33778e288856e48f7bcd23b1b1a8c2707d59 (patch)
treecac6d97878307f20140096c3302bc7ef0080f31f /src/ootx_decoder.c
parenta35428f2125279252c26a645f9ee8f0818b3204c (diff)
downloadlibsurvive-cbbf33778e288856e48f7bcd23b1b1a8c2707d59.tar.gz
libsurvive-cbbf33778e288856e48f7bcd23b1b1a8c2707d59.tar.bz2
full implementation of half float to single float
Diffstat (limited to 'src/ootx_decoder.c')
-rw-r--r--src/ootx_decoder.c54
1 files changed, 39 insertions, 15 deletions
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) {