本篇文章主要讲述几种反转比特位的方法:
将一个32位数:abcd efgh 转置为hgfe dcba
1、常规方法
unsigned int v; //目标待转置数
unsigned int r = v; //r保存反转后的结果,开始获取v的最低有效位
int s = sizeof(v) * CHAR_BIT - 1; //剩余需要移位的比特位
for (v >>= 1; v; v >>= 1)
{
r<<= 1;
r|= v & 1;
s--;
}
r<<= s; //当v的最高位为0的时候进行移位
原理:
通过循环对v进行逻辑右移,每右移一位,通过v & 1取v的最低位,加到r的最低位,r左移
最后对v的最高位进行判断,若原来v的最高位为0,则此时s=1,则再将v左移一位,若v的最高位为1,则s=0,则不进行任何操作。
2、查表
static const unsigned char BitReverseTable256[256] ={
# define R2(n) n, n+ 2*64, n + 1*64, n + 3*64# define R4(n) R2(n), R2(n+ 2*16), R2(n + 1*16), R2(n + 3*16)
# define R6(n) R4(n), R4(n+ 2*4 ), R4(n + 1*4 ), R4(n + 3*4)
R6(0), R6(2), R6(1), R6(3)
};
unsignedint v; //反转32位数,每次8位
unsigned int c; //c保存结果
操作一:
c = (BitReverseTable256[v & 0xff] << 24) |(BitReverseTable256[(v>> 8) & 0xff] << 16) |(BitReverseTable256[(v>> 16) & 0xff] << 8) |(BitReverseTable256[(v>> 24) & 0xff]);
原理:
通过嵌套宏定义构造一张表,BitReverseTable256[i]保存0~255进过反转后的值,再分别取v中的第1~8、9~16、17~24、25~32位的值通过查表得到相应的反转之后的值,在结合保存在r中
操作二:
unsigned char * p = (unsigned char *) &v;
unsignedchar * q = (unsigned char *) &c;
q[3] = BitReverseTable256[p[0]];
q[2] = BitReverseTable256[p[1]];
q[1] = BitReverseTable256[p[2]];
q[0] = BitReverseTable256[p[3]];
原理较简单,和操作一类似,这里采用指针进行。
3、64位乘法与模除法
unsigned char b; //reverse this (8-bit) byte
b= (b * 0x0202020202ULL & 0x010884422010ULL) % 1023;
原理:
0x0202020202ULL: 0000 0010 0000 0010 0000 0010 0000 0010 0000 0010
0x010884422010ULL: 0000 0001 0000 1000 1000 0100 0100 0010 0010 0000 0001 0000
00000001 0000100010 0001000100 0010001000 0000010000
进行b * 0x0202020202ULL操作,变为: b0 b0 b0 b0 b0
乘法(*)操作产生将8位字节模式复制5份到64位的输出端
AND(&)操作选择正确位置(反转),相关联到每10位一组
乘法与“逻辑与”操作将源字中待反转的比特位与10位一组的比特位相一致
通过模除2^10-1,作用是结合64位数中的每10位组合(位置:0-9,10-19,20-29,……)
4、64位乘法(无除法)
unsigned char b; //目标反转数
b = ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
下面展示的bool变量a,b,c,d,e,f,g 和h,每一个由8位字节组成,注意第一个乘法是怎样通过乘法复制将位模式展开,而最后的乘法将它们从右边起每五字节一次地融合到一起
abcd efgh (->hgfe dcba)