数据压缩的常用手段以及方法

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函数

…详情请参照古月居

猜你喜欢

转载自blog.csdn.net/lovely_yoshino/article/details/128916637
今日推荐