0. 简介
之前我们在《经典文献阅读之–R-PCC(基于距离图像的点云压缩方法)》中提到了,我们可以通过一些算法层面来完成数据的压缩,而其实更简单或者说更直接的方法就是使用half这种形式来完成数据压缩。
1. half和float
Half是用16位表示浮点数的一种数据类型,在IEEE 754中也有规定,这种数据类型在深度学习系统中的应用比较广泛。但是在当前主流cpu上,不支持half类型数据的计算和输出,所以需要half和float两个数据类型之间的转换。
图1是16位浮点表示的标准,其中包括了1个符号位,5个指数位和10个尾数位。对于正常的数值,其结果如下表示。
图2是32位浮点数表示的标准,其中包括1个符号位,8个指数位和23个尾数位。对于正常的数值,其结果如下表示。
所以对于half和float之间的转换,除了不同部分的移位之外,还要做注意指数的基数之间的差别(15和127)。要把half类型转换为float类型,主要进行以下几步操作。
- 符号位左移16位。
- 指数部分加112(127与15之间的差距),左移13位(右对齐)。
- 尾数部分左移13位(左对齐)。
2. half与float参考代码
下面是对应的参考代码:
typedef unsigned short ushort;//占用2个字节
typedef unsigned int uint; //占用4个字节
uint as_uint(const float x) {
return *(uint*)&x;
}
float as_float(const uint x) {
return *(float*)&x;
}
float half_to_float(const ushort x) { // IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
const uint e = (x&0x7C00)>>10; // exponent
const uint m = (x&0x03FF)<<13; // mantissa
const uint v = as_uint((float)m)>>23; // evil log2 bit hack to count leading zeros in denormalized format
return as_float((x&0x8000)<<16 | (e!=0)*((e+112)<<23|m) | ((e==0)&(m!=0))*((v-37)<<23|((m<<(150-v))&0x007FE000))); // sign : normalized : denormalized
}
ushort float_to_half(const float x) { // IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
const uint b = as_uint(x)+0x00001000; // round-to-nearest-even: add last bit after truncated mantissa
const uint e = (b&0x7F800000)>>23; // exponent
const uint m = b&0x007FFFFF; // mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
return (b&0x80000000)>>16 | (e>112)*((((e-112)<<10)&0x7C00)|m>>13) | ((e<113)&(e>101))*((((0x007FF000+m)>>(125-e))+1)>>1) | (e>143)*0x7FFF; // sign : normalized : denormalized : saturate
}
//下面的demo中,yolov5_outputs[0].buf是void *类型的,void *类型不能++,因此先转换成ushort*类型。
float *data0 = (float*)malloc(4 * output_attrs[0].n_elems);
float *data1 = (float*)malloc(4 * output_attrs[1].n_elems);
float *data2 = (float*)malloc(4 * output_attrs[2].n_elems);
unsigned short *temp0 = (ushort*)yolov5_outputs[0].buf;
unsigned short *temp1 = (ushort*)yolov5_outputs[1].buf;
unsigned short *temp2 = (ushort*)yolov5_outputs[2].buf;
for(int i=0; i < output_attrs[0].n_elems;i++)
{
data0[i] = half_to_float(temp0[i]);
}
for(int i=0; i < output_attrs[1].n_elems;i++)
{
data1[i] = half_to_float(temp1[i]);
}
for(int i=0; i < output_attrs[2].n_elems;i++)
{
data2[i] = half_to_float(temp2[i]);
3. float与uint16
求在串口通信时常常会被用到,串口只能以字符型(char)进行通信
atof():将字符串转换为双精度浮点型值。
atoi():将字符串转换为整型值。
浮点转uint16函数