1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
package cbor
func float16to32(f uint16) uint32 {
sign, exp, mant := splitf16(f)
if exp == 0x1f {
return sign | 0xff<<23 | mant // infinity/NaN
}
if exp == 0 { // subnormal
if mant == 0 {
return sign
}
return normalize(sign, mant)
}
return sign | (exp+127-15)<<23 | mant // rebias exp by the difference between the two
}
func splitf16(f uint16) (sign, exp, mantissa uint32) {
const smask = 0x1 << 15 // put sign in float32 position
const emask = 0x1f << 10 // pull exponent as a number (for bias shift)
const mmask = 0x3ff // put mantissa in float32 position
return uint32(f&smask) << 16, uint32(f&emask) >> 10, uint32(f&mmask) << 13
}
// moves a float16 normal into normal float32 space
// to do this we must re-express the float16 mantissa in terms of a normal
// float32 where the hidden bit is 1, e.g.
//
// f16: 0 00000 0001010000 = 0.000101 * 2^(-14), which is equal to
// f32: 0 01101101 01000000000000000000000 = 1.01 * 2^(-18)
//
// this is achieved by shifting the mantissa to the right until the leading bit
// that == 1 reaches position 24, then the number of positions shifted over is
// equal to the offset from the subnormal exponent
func normalize(sign, mant uint32) uint32 {
exp := uint32(-14 + 127) // f16 subnormal exp, with f32 bias
for mant&0x800000 == 0 { // repeat until bit 24 ("hidden" mantissa) is 1
mant <<= 1
exp-- // tracking the offset
}
mant &= 0x7fffff // remask to 23bit
return sign | exp<<23 | mant
}
|