当float类型绝对值小于5.9604644e-8(0x33800000)时
当float值为5.9604644e-8(0x33800000),转换后的half值位5.97e-8(0x0001),因此当float值绝对值小于这个数值时,转换后的half就是0.0。
当float类型绝对值大于0x477fffc0并小于0x7f800000时
当float类型绝对值最大为0x477fffc0时,转换的half值位65504(0x7bff),是half类型浮点数能表示的最大值,因此更大的float值转换为half后就是INF(但float绝对值大于0x7f800000时为NAN,转换成half也是NAN)。
当float类型的指数位数值大于0x70时
当float类型转换为half类型时,指数值需要减去0x70,并且由于相减后的结果仍然大于0,因此小数位只需要右移13bit即可。
当float类型的指数位数值小于或等于0x70时
由于half指数位最小只能表示2^-14,因此当float指数位小于或等于0x70(并且float的bit数值大于0x33800000)时,转换为half后指数位必为0,而右移13bit后的小数位需要先在第10bit位补1,然后再右移(0x70 - float指数位数值 + 1) bit。
代码
half f32_to_f16(float __x) {
unsigned int x = *((unsigned int *)&__x);
unsigned int sign = x & 0x80000000;
unsigned int exponent_f32 = (x & 0x7f800000) >> 23;
unsigned int mantissa_f32 = x & 0x007fffff;
unsigned short y = (unsigned short)(sign >> 16);
unsigned int exponent_f16;
unsigned int mantissa_f16;
unsigned int hx;
hx = x & 0x7fffffff;
if (hx < 0x33800000) {
return *((half *)&y);
}
if (hx > 0x7f800000) {
y = 0x7e00;
return *((half *)&y);
}
if (hx >= 0x477fffff) {
y |= 0x7c00;
return *((half *)&y);
}
mantissa_f16 = mantissa_f32 >> 13;
if (exponent_f32 > 0x70) {
exponent_f16 = exponent_f32 - 0x70;
} else {
exponent_f16 = 0;
mantissa_f16 |= 0x400;
mantissa_f16 = mantissa_f16 >> (0x71 - exponent_f32);
}
y = y | (unsigned short)(exponent_f16 << 10) | (unsigned short)mantissa_f16;
return *((half *)&y);
}