如何交换一个整形数的二进制表示的其中两位.
比如要把a,与b进行交换。那么方法如下:x表示任意值。
xxxx xxxx xxxx xaxx xxxx xxbx xxxx xxxx
分为两步:
第一步:首先要求得
xxxx xxxx xxxx x0xx xxxx xx0x xxxx xxxx
第二步:在第一步的基础上加上:
0000 0000 0000 0b00 0000 00a0 0000 0000
第一步的代码可以写做:两位置值表示为x, y。数值表示为v
ret = v & (~(1<<x)) & (~(1<<y))
第二步代码:
ret = ret | (((v>>y)&1)<<x) | (((v>>x)&1)<<y);
总结一下代码,写做
这里粘个代码
void _swap(unsigned int &v, int x, int y)
{
//思路:第一步先减去0000x0000,再减去00000y0000;
// 第二步先加上000y0000,再加上0000x0000;
// 可以一句话完成.
//说明思路的代码:
//unsigned int x_pos = ((v>>y)&1)<<x;
//unsigned int y_pos = ((v>>x)&1)<<y;
//unsigned int x_value = ((v>>x)&1)<<x;
//unsigned int y_value = ((v>>y)&1)<<y;
//v -= (x_value + y_value);
//v += (x_pos + y_pos);
//print_int(v);
//终极版:
//一句话也可以完成。
v = v & (~(1<<x)) & (~(1<<y)) | (((v>>y)&1)<<x) | (((v>>x)&1)<<y);
}
如何把二进制位按中间对折
比如100对折之后成为001。
不过这里的长度要求是32位的。也就是31位与0位互换,以此类推。
这里就不多说了,《代码之美》一书中提供了一种分治的思想来进行1位计数。这里同样利用这种分治思想来处理
unsigned int bit_reverse(unsigned int n)
{
n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
return n;
}
看一下对char的处理
unsigned char ReverseBits(unsigned char ch)
{
ch = (ch &0x55) <<1| (ch >>1) &0x55;
ch = (ch &0x33) <<2| (ch >>2) &0x33;
ch = (ch &0x0F) <<4| (ch >>4) &0x0F;
return ch;
}
先看看0x55,0x33,0x0F的二进制
0x55 -> 01010101 B
0x33 -> 00110011 B
0x0F -> 00001111 B
从中可以看出,是先将相连的两bits对调实现相连2 bits数据翻转;
接着两个相连的“2 bits组合”对调实现相连4 bits数据翻转;
再下来就是将两个相连的“4 bits组合”对调即可以完成对一个字符8 bits的翻转。
对于更多bytes 的数据做同样的处理。单数个bits呢,这个就需要思考一下了。
如何对整形数计算1的个数
《编程之美》上面的代码其实并不高效,这里给个《代码之美》中猛的代码
int cnt(unsigned int x)
{
x = x - ((x>>1)&0x55555555);
x = (x & 0x33333333) + ((x>>2)&0x33333333);
x = (x + (x>>4)) & 0x0f0f0f0f;
x = (x + (x>>8));
x = (x + (x>>16));
return x&0x3f;
}
做这个处理有一个经典的方法,分治策略( divide and conquer strategy ),该方法来源于Henry S.Warren 的《Hacker's Delight》对Reversing Bits 的介绍。