unsigned short hs_floatToHalf (float f) {
  union { float d; unsigned int i; } u = { f };
  int s =  (u.i >> 16) & 0x8000;
  int e = ((u.i >> 23) & 0xff) - 112;
  int m =          u.i & 0x7fffff;
  if (e <= 0) {
    if (e < -10) return s; /* underflowed */
    /* force leading 1 and round */
    m |= 0x800000;
    int t = 14 - e;
    int a = (1 << (t - 1)) - 1;
    int b = (m >> t) & 1;
    return s | ((m + a + b) >> t);
  } 
  if (e == 143) {
    if (m == 0) return s | 0x7c00; /* +/- infinity */

    /* NaN, m == 0 forces us to set at least one bit and not become an infinity */
    m >>= 13;
    return s | 0x7c00 | m | (m == 0); 
  }
  
  /* round the normalized float */
  m = m + 0xfff + ((m >> 13) & 1);

  /* significand overflow */
  if (m & 0x800000) {
     m =  0;
     e += 1;
  }

  /* exponent overflow */
  if (e > 30) return s | 0x7c00;

  return s | (e << 10) | (m >> 13);
}

int hs_halfToFloatRep (unsigned short c) {
  int s = (c >> 15) & 0x001;
  int e = (c >> 10) & 0x01f;
  int m =         c & 0x3ff;
  if (e == 0) {
    if (m == 0) /* +/- 0 */ return s << 31;
    /* denormalized, renormalize it */
    while (!(m & 0x400)) {
      m <<= 1;
      e -=  1;
    }
    e += 1;
    m &= ~0x400;
  } else if (e == 31) return (s << 31) | 0x7f800000 | (m << 13); /* NaN or +/- infinity */
  e += 112;
  m <<= 13;
  return (s << 31) | (e << 23) | m;
}

float hs_halfToFloat (unsigned short c) {
  union { float d; unsigned int i; } u;
  u.i = hs_halfToFloatRep(c);
  return u.d;
}

