zigzag算法

原码

我们用第一个位表示符号(0为非负数,1为负数),剩下的位表示值。比如:

[+8] = [00001000]原

[-8] = [10001000]原

反码

我们用第一位表示符号(0为非负数,1为负数),剩下的位,非负数保持不变,负数按位求反。比如:

[+8] = [00001000]原 = [0000 1000]反

[-8] = [10001000]原 = [1111 0111]反

如果我们用原码或者补码来表示整数的二进制,有什么问题么?表面上看,似乎挺好的。不过仔细思考就会发现两个问题:

第一、0居然用两个编码(+0和-0)来表示了:

原码:[0000 0000]原 = [1000 0000]原

反码:[0000 0000]反 = [1111 1111]反

第二、计算机要理解符号位的存在,否则符号位参与运算,就会出现诡异的现象:

原码:

1 + (-1)

= [00000001]原 + [1000 0001]原

= [10000010]原

= -2

明显是不对的!

反码:

1 + (-1)

= [00000001]反 + [1111 1110]反

= [1111 1111]反

= -0

表现的好诡异!

为了解决这些问题,我们在计算机体系中引入了补码。

补码

我们用第一位表示符号(0为非负数,1为负数),剩下的位非负数保持不变,负数按位求反末位加一。

[+8] = [00001000]原 = [0000 1000]补

[-8] = [10001000]原 = [1111 1000]补

那我们再看看,把符号放进去做运算会有什么样的效果呢?

1 + (-1)

= [00000001]补 + [1111 1111]补

= [0000 0000]补

= 0

很明显,通过这样的方式,计算机进行运算的时候,就不用关心符号这个问题,而只需要按照统一的逢二进一的原则进行运算就可以了。

zigzag算法:

//负数右移后高位全变成1,再与左移一位后的值进行异或,就把高位那些无用的1全部变成0了,巧妙!
int int_to_zigzag(int n) {
	return (n << 1) ^ (n >> 31);
}

//我们还原的代码就反过来写就可以了。不过这里要注意一点,就是右移的时候,需要用不带符号的移动,否则如
//果第一位数据位是1的话,就会补1
int zigzag_to_int(int n) {
	return (((unsigned int)n) >> 1) ^ -(n & 1);
}

 

字节自表示方法

zigzag引入了一个方法,就是用字节自己表示自己

/*

(~0x7f)16=(11111111_11111111_11111111_10000000)补
他就是从倒数第八位开始,高位全为1的数。他的作用,就是看除开最后七位后,还有没有信息。

我们把zigzag值传递给这个函数,这个函数就将这个值从低位到高位切分成每7bits一组,如果高位还有有效信息,则给这7bits补上1个bit的1(0x80)。如此反复 直到全是前导0,便结束算法。
*/

int write_to_buffer(int z, byte* buf, int size) 
{
	int ret = 0;

	for (int i = 0; i < size; i++) 
	{
		if ((z & (~0x7f)) == 0) {
			buf[i] = (byte)z;
			ret = i + 1;
			break;
		}
		else
		{
			buf[i] = (byte)((z & 0x7f) | 0x80);
			z = ((unsigned int)z) >> 7;
		}
	}

	return ret;
}


/*
整个过程就和压缩的时候是逆向的:对于每一个字节,先看最高一位是否有1(0x80)。如果有,就说明不是最后一个数据字节包,那取这个字节的最后七位进行拼装。否则,说明就是已经到了最后一个字节了,那直接拼装后,跳出循环,算法结束。最终得到4字节的整数。
*/
int read_from_buffer(byte* buf, int max_size)
{
	int ret = 0;

	int offset = 0;

	for (int i = 0; i < max_size; i++, offset += 7)
	{
		byte n = buf[i];

		if ((n & 0x80) != 0x80)
		{
			ret |= (n << offset);
			break;
		}
		else
		{
			ret |= ((n & 0x7f) << offset);
		}
	}

	return ret;
}



原文:

https://blog.csdn.net/zgwangbo/article/details/51590186 

https://blog.csdn.net/lzcaqde/article/details/81061590

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值