C语言中的位操作(14)--反转比特位

本篇文章主要讲述几种反转比特位的方法:

将一个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)
};

unsigned int 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;
unsigned char * 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)
*                                                      1000 0000  0010 0000  0000 1000  0000 0010 (0x80200802)
-------------------------------------------------------------------------------------------------
                                            0abc defg  h00a bcde  fgh0 0abc  defg h00a  bcde fgh0
&                                           0000 1000  1000 0100  0100 0010  0010 0001  0001 0000 (0x0884422110)
-------------------------------------------------------------------------------------------------
                                            0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
*                                           0000 0001  0000 0001  0000 0001  0000 0001  0000 0001 (0x0101010101)
-------------------------------------------------------------------------------------------------
                                            0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
                                 0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
                      0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
           0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
0000 d000  h000 0c00  0g00 00b0  00f0 000a  000e 0000
-------------------------------------------------------------------------------------------------
0000 d000  h000 dc00  hg00 dcb0  hgf0 dcba  hgfe dcba  hgfe 0cba  0gfe 00ba  00fe 000a  000e 0000
>> 32
-------------------------------------------------------------------------------------------------
                                            0000 d000  h000 dc00  hg00 dcb0  hgf0 dcba  hgfe dcba  
&                                                                                       1111 1111
-------------------------------------------------------------------------------------------------
                                                                                        hgfe dcba

 5、采用7部操作(非64位)

b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; 
                                                                                                     abcd efgh
*                                                                                          0000 1000 0000 0010
--------------------------------------------------------------------------------------------------------------
                                                                                      0abc defg h00a bcde fgh0  
&                                                                                     0010 0010 0001 0001 0000
--------------------------------------------------------------------------------------------------------------
                                                                                      00b0 00f0 000a 000e 0000       

                                                 
**************************************************************************************************************       

                                                                                                     abcd efgh
*                                                                                          1000 0000 0010 0000
--------------------------------------------------------------------------------------------------------------
                                                                                      defg h00a bcde fgh0 0000  
&                                                                                     1000 1000 0100 0100 0000
--------------------------------------------------------------------------------------------------------------
                                                                                      d000 h000 0c00 0g00 0000

**************************************************************************************************************

                                                                                      00b0 00f0 000a 000e 0000
|                                                                                     d000 h000 0c00 0g00 0000
--------------------------------------------------------------------------------------------------------------
                                                                                      d0b0 h0f0 0c0a 0g0e 0000
*                                                                                     0001 0000 0001 0000 0001
--------------------------------------------------------------------------------------------------------------
                                                                                      d0b0 h0f0 0c0a 0g0e 0000
                                                                            d0b0 h0f0 0c0a 0g0e 0000
                                                                  d0b0 h0f0 0c0a 0g0e 0000
--------------------------------------------------------------------------------------------------------------
                                                                  d0b0 h0f0 dcba hgfe dcba hgfe 0c0a 0g0e 0000 
>>16                                                                                        
--------------------------------------------------------------------------------------------------------------
                                                                                      d0b0 h0f0 dcba hgfe dcba
&                                                                                                    1111 1111
--------------------------------------------------------------------------------------------------------------
                                                                                                     hgfe dcba 

6、并行反转N位数时间复杂度(5 * lg(N))

unsigned int v; // 32位目标数字
// 交换奇偶位比特
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
// 交换连续数对
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
// 一点点的交换 
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
// 交换字节
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
// 交换2字节长数对
v = ( v >> 16             ) | ( v               << 16);

 下面展示的32位变量由ABCD EFGH IJKL MNPQ abcd efgh ijkl mnpq组成

/*((v >> 1) & 0x55555555) */

                                                                       ABCD EFGH IJKL MNPQ abcd efgh ijkl mnpq
>>1
--------------------------------------------------------------------------------------------------------------
                                                                       0ABC DEFG HIJK LMNP Qabc defg hijk lmnp
&                                                                      0101 0101 0101 0101 0101 0101 0101 0101
--------------------------------------------------------------------------------------------------------------
                                                                       0A0C 0E0G 0I0K 0M0P 0a0c 0e0g 0i0k 0m0p

**************************************************************************************************************
/*((v & 0x55555555) << 1)*/

                                                                       ABCD EFGH IJKL MNPQ abcd efgh ijkl mnpq
&                                                                      0101 0101 0101 0101 0101 0101 0101 0101
--------------------------------------------------------------------------------------------------------------
                                                                       0B0D 0F0H 0J0L 0N0Q 0b0d 0f0h 0j0l 0n0q
<<1
--------------------------------------------------------------------------------------------------------------
                                                                       B0D0 F0H0 J0L0 N0Q0 b0d0 f0h0 j0l0 n0q0


**************************************************************************************************************

/*v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);*/
                                                                       0A0C 0E0G 0I0K 0M0P 0a0c 0e0g 0i0k 0m0p       |                                                                      B0D0 F0H0 J0L0 N0Q0 b0d0 f0h0 j0l0 n0q0
--------------------------------------------------------------------------------------------------------------
                                                                       BADC FEHG JILK NMQP badc fehg jilk nmqp

**************************************************************************************************************

/*((v >> 2) & 0x33333333)*/
                                                                       BADC FEHG JILK NMQP badc fehg jilk nmqp
>>2
--------------------------------------------------------------------------------------------------------------
                                                                       00BA DCFE HGJI LKNM QPba dcfe hgji lknm
&                                                                      0011 0011 0011 0011 0011 0011 0011 0011
--------------------------------------------------------------------------------------------------------------
                                                                       00BA 00FE 00JI 00NM 00ba 00fe 00ji 00nm

**************************************************************************************************************

/*((v & 0x33333333) << 2);*/

                                                                       BADC FEHG JILK NMQP badc fehg jilk nmqp
&                                                                      0011 0011 0011 0011 0011 0011 0011 0011
--------------------------------------------------------------------------------------------------------------
                                                                       00DC 00HG 00LK 00QP 00dc 00hg 00lk 00qp
<<2
--------------------------------------------------------------------------------------------------------------
                                                                       DC00 HG00 LK00 QP00 dc00 hg00 lk00 qp00

**************************************************************************************************************

/*((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);*/
                                                                       00BA 00FE 00JI 00NM 00ba 00fe 00ji 00nm       |                                                                      DC00 HG00 LK00 QP00 dc00 hg00 lk00 qp00
--------------------------------------------------------------------------------------------------------------
                                                                       DCBA HGFE LKJI QPNM dcba hgfe lkji qpnm


**************************************************************************************************************

/*((v >> 4) & 0x0F0F0F0F) */

                                                                       DCBA HGFE LKJI QPNM dcba hgfe lkji qpnm
>>4
--------------------------------------------------------------------------------------------------------------
                                                                       0000 DCBA HGFE LKJI QPNM dcba hgfe lkji
&                                                                      0000 1111 0000 1111 0000 1111 0000 1111
--------------------------------------------------------------------------------------------------------------
                                                                       0000 DCBA 0000 LKJI 0000 dcba 0000 lkji


**************************************************************************************************************

/*((v & 0x0F0F0F0F) << 4);*/

                                                                       DCBA HGFE LKJI QPNM dcba hgfe lkji qpnm
&                                                                      0000 1111 0000 1111 0000 1111 0000 1111
--------------------------------------------------------------------------------------------------------------
                                                                       0000 HGFE 0000 QPNM 0000 hgfe 0000 qpnm
<<4
--------------------------------------------------------------------------------------------------------------
                                                                       HGFE 0000 QPNM 0000 hgfe 0000 qpnm 0000
 

**************************************************************************************************************

/*((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);*/
                                                                       0000 DCBA 0000 LKJI 0000 dcba 0000 lkji
|                                                                      HGFE 0000 QPNM 0000 hgfe 0000 qpnm 0000
--------------------------------------------------------------------------------------------------------------
                                                                       HGFE DCBA QPNM LKJI hgfe dcba qpnm lkji

**************************************************************************************************************

/*((v >> 8) & 0x00FF00FF */

                                                                       HGFE DCBA QPNM LKJI hgfe dcba qpnm lkji
>>8
--------------------------------------------------------------------------------------------------------------
                                                                       0000 0000 HGFE DCBA QPNM LKJI hgfe dcba
&                                                                      0000 0000 1111 1111 0000 0000 1111 1111
--------------------------------------------------------------------------------------------------------------
                                                                       0000 0000 HGFE DCBA 0000 0000 hgfe dcba


**************************************************************************************************************

/*((v & 0x00FF00FF << 8);*/

                                                                       HGFE DCBA QPNM LKJI hgfe dcba qpnm lkji
&                                                                      0000 0000 1111 1111 0000 0000 1111 1111
--------------------------------------------------------------------------------------------------------------
                                                                       0000 0000 QPNM LKJI 0000 0000 qpnm lkji
<<8
--------------------------------------------------------------------------------------------------------------
                                                                       QPNM LKJI 0000 0000 qpnm lkji 0000 0000
 

**************************************************************************************************************

/*((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);*/
                                                                       0000 0000 HGFE DCBA 0000 0000 hgfe dcba
|                                                                      QPNM LKJI 0000 0000 qpnm lkji 0000 0000
--------------------------------------------------------------------------------------------------------------
                                                                       QPNM LKJI HGFE DCBA qpnm lkji hgfe dcba


**************************************************************************************************************

/*v = ( v >> 16             ) | ( v               << 16);*/

                                                                       QPNM LKJI HGFE DCBA qpnm lkji hgfe dcba
>>16                                                                   
--------------------------------------------------------------------------------------------------------------
                                                                       0000 0000 0000 0000 QPNM LKJI HGFE DCBA


                                                                       QPNM LKJI HGFE DCBA qpnm lkji hgfe dcba
<<16                                                                   
--------------------------------------------------------------------------------------------------------------
                                                                       qpnm lkji hgfe dcba 0000 0000 0000 0000 

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

                                                                       0000 0000 0000 0000 QPNM LKJI HGFE DCBA
|                                                                      qpnm lkji hgfe dcba 0000 0000 0000 0000
--------------------------------------------------------------------------------------------------------------
                                                                       qpnm lkji hgfe dcba QPNM LKJI HGFE DCBA


下面的变版本时间复杂度也是O(lg(N)),但是需要更多的操作来反转V

unsigned int s = sizeof(v) * CHAR_BIT; // 数的位数; 必须为2的幂 
unsigned int mask = ~0;         
while ((s >>= 1) > 0) 
{
  mask ^= (mask << s);
  v = ((v >> s) & mask) | ((v << s) & ~mask);
}
原文地址:https://www.cnblogs.com/xueda120/p/3151354.html