无符号整形压缩与解压缩的一种实现

无符号整形的压缩与解压缩算法。

今天浏览公司的私有协议的实现,在将数据序列化的代码中发现对无符号整形做了一些特殊的处理,了解下才发现是无符号整形压缩跟解压缩算法的一种。
于是上网了解了下相关的内容,记录下。

对于无符号整形数字,在其二进制形式上可以将其看成两部分,实际能够表示其大小以及填充的零部分.
举几个例子:

                          uint32_t  num = 1;

二进制形式 :   | 0000 0000 | 0000 0000 | 0000 0000 | 0000 0001 |
                         真正能够表示其大小的是最后一位,其余的31位0都是做为填充位。

                          uint32_t num = 3543;

二进制形式 :   | 0000 0000 | 0000 0000 | 0000 1101 | 1101 0111 |
                          真正能够表示其大小的是后面12位 1101 1101 0111,其余的20位0都是做为填充位。

                         uint32_t num = -1;

二进制形式 :   | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 |
              不存在填充的0,也就是填充的位数是0个,需要所有的位数才能表示出其实际的大小。

需要对数据进行压缩,只要把能表示出数字实际大小的部分的信息表示出来即可,填充的0部分的信息可以全部或者部分舍弃。


现在提供一种无符号整形的压缩算法:
         将无符号整形的数据每七位数字保存在压缩后的一位字节中,压缩字节的剩余一位做为标记位,用来表示该字节是不是数据的最后一个字节,为1表示该字节不是压缩后的数据的最后一位,后面还有数据,为0表示该字节已经是压缩后的数据的最后一位,后面已经没有数据。

则对于前面的几个数字的压缩可以表示为:
                            uint32_t  num = 1;
           压缩前:    | 0000 0000 | 0000 0000 | 0000 0000 | 0000 0001 |
           压缩后:    | 0000 0001 |
           
                            uint32_t num = 3543;
          压缩前:     | 0000 0000 | 0000 0000 | 0000 1101 | 1101 0111 |     
          压缩后:     | 1101 0111 | 0001 1011 |    
          
                            uint32_t num = -1;
          压缩前 :    | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 |   
          压缩后 :    | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 0000 1111 |
          

          从上面可以看出,对于比较小的无符号整形数字,压缩之后优势越大,占用的空间越小,对于比较大的数据压缩之后占用的空间可能反而会更大。

代码实现:

//压缩无符号16位整形到buf中, 正确返回占用buffer的长度,失败返回-1.
int32_t unint16_compress(uint16_t u16, uint8_t *buf, int32_t size)
{
	uint8_t *p = buf;
	int32_t left = size;

	while (left > 0)
	{
		p[0] = (uint8_t)(u16 & 0x7f);
		u16 >>= 7;
		p[0] |= (u16 == 0 ? 0x00 : 0x80);
		p++;
		left--;
		if (u16 == 0)
		{
			return size - left;
		}
	}
	return -1;
}

//压缩无符号32位整形到buf中, 正确返回占用buffer的长度,失败返回-1.
int32_t unint32_compress(uint32_t u32, uint8_t *buf, int32_t size)
{
	uint8_t *p   = buf;
	int32_t left = size;

	while (left > 0)
	{
		p[0] = (uint8_t)(u32 & 0x7f);
		u32 >>= 7;
		p[0] |= (u32 == 0 ? 0x00 : 0x80);
		p++;
		left--;
		if (u32 == 0)
		{
			return size - left;
		}
	}
	return -1;
}

//压缩无符号64位整形到buf中, 正确返回占用buffer的长度,失败返回-1.
int32_t unint64_compress(uint64_t u64, uint8_t *buf, int32_t size)
{
	uint8_t *p = buf;
	int32_t left = size;

	while (left > 0)
	{
		p[0] = (uint8_t)(u64 & 0x7f);
		u64 >>= 7;
		p[0] |= (u64 == 0 ? 0x00 : 0x80);
		p++;
		left--;
		if (u64 == 0)
		{
			return size - left;
		}
	}
	return -1;
}

//解压缩
int32_t unint16_uncompress(uint16_t *pu16, uint8_t *buf, int32_t size)
{
	uint16_t u16 = 0;
	int32_t shift = 0;
	uint8_t *p = buf;
	int32_t left = size;

	while (left > 0)
	{
		uint8_t n = (uint8_t)(p[0] & 0x7f);
		uint8_t n0 = (uint8_t)(p[0] & 0x80);
		u16 += (uint16_t)((uint16_t)n << (7 * shift));
		p++;
		left--;
		shift++;
		if (0 == n0)
		{
			if (pu16)
			{
				*pu16 = u16;
				return size - left;
			}
			break;
		}
	}

	return -1;
}

//解压缩
int32_t unint32_uncompress(uint32_t *pu32, uint8_t *buf, int32_t size)
{
	uint32_t u32  = 0;
	int32_t shift = 0;
	uint8_t *p = buf;
	int32_t left = size;

	while (left > 0)
	{
		uint8_t n = (uint8_t)(p[0] & 0x7f);
		uint8_t n0 = (uint8_t)(p[0] & 0x80);
		u32 += (uint32_t)((uint32_t)n << (7 * shift));
		p++;
		left--;
		shift++;
		if (0 == n0)
		{
			if (pu32)
			{
				*pu32 = u32;
				return size - left;
			}
			break;
		}
	}

	return -1;
}

//解压缩
int32_t unint64_uncompress(uint64_t *pu64, uint8_t *buf, int32_t size)
{
	uint64_t u64 = 0;
	int32_t shift = 0;
	uint8_t *p = buf;
	int32_t left = size;

	while (left > 0)
	{
		uint8_t n = (uint8_t)(p[0] & 0x7f);
		uint8_t n0 = (uint8_t)(p[0] & 0x80);
		u64 += (uint64_t)(((uint64_t)n) << (7 * shift));
		p++;
		left--;
		shift++;
		if (0 == n0)
		{
			if (pu64)
			{
				*pu64 = u64;
				return size - left;
			}
			break;
		}
	}

	return -1;
}


          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值