二进制位操作技巧

收集的位操作技巧N个,希望新人捧场,高手斧正,大虾补充       /******************************************************************/    检测一个无符号数是不为2^n-1(^为幂):   x&(x+1)       将最右侧0位改为1位:   x   |   (x+1)       二进制补码运算公式:    -x   =   ~x   +   1   =   ~(x-1)    ~x   =   -x-1      -(~x)   =   x+1    ~(-x)   =   x-1    x+y   =   x   -   ~y   -   1   =   (x|y)+(x&y)      x-y   =   x   +   ~y   +   1   =   (x|~y)-(~x&y)      x^y   =   (x|y)-(x&y)    x|y   =   (x&~y)+y    x&y   =   (~x|y)-~x       x==y:         ~(x-y|y-x)    x!=y:         x-y|y-x    x<   y:         (x-y)^((x^y)&((x-y)^x))    x<=y:         (x|~y)&((x^y)|~(y-x))    x<   y:         (~x&y)|((~x|y)&(x-y))//无符号x,y比较    x<=y:         (~x|y)&((x^y)|~(y-x))//无符号x,y比较          使用位运算的无分支代码:       计算绝对值    int   abs(   int   x   )      {         int   y   ;        y   =   x   >>   31   ;        return   (x^y)-y   ;//or:   (x+y)^y    }       符号函数:sign(x)   =   -1,   x<0;   0,   x   ==   0   ;   1,   x   >   0    int   sign(int   x)    {        return   (x>>31)   |   (unsigned(-x))>>31   ;//x=-2^31时失败(^为幂)    }       三值比较:cmp(x,y)   =   -1,   x<y;   0,   x==y;   1,   x   >   y    int   cmp(   int   x,   int   y   )    {        return   (x>y)-(x-y)   ;    }       doz=x-y,   x>=y;   0,   x<y    int   doz(int   x,   int   y   )    {        int   d   ;        d   =   x-y   ;        return   d   &   ((~(d^((x^y)&(d^x))))>>31)   ;    }       int   max(int   x,   int   y   )      {        int   m   ;        m   =   (x-y)>>31   ;          return   y   &   m   |   x   &   ~m   ;    }       不使用第三方交换x,y:    1.x   ^=   y   ;   y   ^=   x   ;   x   ^=   y   ;    2.x   =   x+y   ;   y   =   x-y   ;   x   =   x-y   ;    3.x   =   x-y   ;   y   =   y+x   ;   x   =   y-x   ;    4.x   =   y-x   ;   x   =   y-x   ;   x   =   x+y   ;         双值交换:x   =   a,   x==b;   b,   x==a//常规编码为x   =   x==a   ?   b   :a   ;    1.x   =   a+b-x   ;    2.x   =   a^b^x   ;       下舍入到2的k次方的倍数:    1.x   &   ((-1)<<k)    2.(((unsigned)x)>>k)<<k    上舍入:    1.   t   =   (1<<k)-1   ;   x   =   (x+t)&~t   ;    2.t   =   (-1)<<k   ;   x   =   (x-t-1)&t   ;       位计数,统计1位的数量:    1.    int   pop(unsigned   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   &   0x0000003f   ;    }    2.    int   pop(unsigned   x)   {        static   char   table[256]   =   {   0,1,1,2,   1,2,2,3,   ....,   6,7,7,8   }   ;        return   table[x&0xff]+table[(x>>8)&0xff]+table[(x>>16)&0xff]+table[(x>>24)]   ;    }       奇偶性计算:    x   =   x   ^   (   x>>1   )   ;    x   =   x   ^   (   x>>2   )   ;    x   =   x   ^   (   x>>4   )   ;    x   =   x   ^   (   x>>8   )   ;    x   =   x   ^   (   x>>16   )   ;    结果中位于x最低位,对无符号x,结果的第i位是原数第i位到最左侧位的奇偶性          位反转:    unsigned   rev(unsigned   x)    {        x   =   (x   &   0x55555555)   <<   1   |   (x>>1)   &   0x55555555   ;        x   =   (x   &   0x33333333)   <<   2   |   (x>>2)   &   0x33333333   ;        x   =   (x   &   0x0f0f0f0f)   <<   4   |   (x>>4)   &   0x0f0f0f0f   ;        x   =   (x<<24)   |   ((x&0xff00)<<8)   |   ((x>>8)   &   0xff00)   |   (x>>24)   ;        return   x   ;    }       递增位反转后的数:    unsigned   inc_r(unsigned   x)    {        unsigned   m   =   0x80000000   ;        x   ^=   m   ;        if(   (int)x   >=   0   )          do   {   m   >>=   1   ;   x   ^=   m   ;   }   while(   x   <   m   )   ;        return   x   ;    }       混选位:    abcd   efgh   ijkl   mnop   ABCD   EFGH   IJKL   MNOP->aAbB   cCdD   eEfF   gGhH   iIjJ   kKlL   mMnN   oOpP    unsigned   ps(unsigned   x)    {        unsigned   t   ;        t   =   (x   ^   (x>>8))   &   0x0000ff00;   x   =   x   ^   t   ^   (t<<8)   ;        t   =   (x   ^   (x>>4))   &   0x00f000f0;   x   =   x   ^   t   ^   (t<<4)   ;        t   =   (x   ^   (x>>2))   &   0x0c0c0c0c;   x   =   x   ^   t   ^   (t<<2)   ;        t   =   (x   ^   (x>>1))   &   0x22222222;   x   =   x   ^   t   ^   (t<<1)   ;        return   x   ;    }       位压缩:    选择并右移字x中对应于掩码m的1位的位,如:compress(abcdefgh,01010101)=0000bdfh    compress_left(x,m)操作与此类似,但结果位在左边:   bdfh0000.    unsigned   compress(unsigned   x,   unsigned   m)    {        unsigned   mk,   mp,   mv,   t   ;        int   i   ;           x   &=   m   ;        mk   =   ~m   <<   1   ;        for(   i   =   0   ;   i   <   5   ;   ++i   )   {            mp   =   mk   ^   (   mk   <<   1)   ;            mp   ^=   (   mp   <<   2   )   ;            mp   ^=   (   mp   <<   4   )   ;            mp   ^=   (   mp   <<   8   )   ;            mp   ^=   (   mp   <<   16   )   ;            mv   =   mp   &   m   ;            m   =   m   ^   mv   |   (mv   >>   (1<<i)   )   ;            t   =   x   &   mv   ;            x     =   x   ^   t   |   (   t   >>   (   1<<i)   )   ;            mk   =   mk   &   ~mp   ;         }        return   x   ;    }          位置换:    用32个5位数表示从最低位开始的位的目标位置,结果是一个32*5的位矩阵,    将该矩阵沿次对角线转置后用5个32位字p[5]存放。    SAG(x,m)   =   compress_left(x,m)   |   compress(x,~m)   ;    准备工作:    void   init(   unsigned   *p   )   {         p[1]   =   SAG(   p[1],   p[0]   )   ;        p[2]   =   SAG(   SAG(   p[2],   p[0]),   p[1]   )   ;        p[3]   =   SAG(   SAG(   SAG(   p[3],   p[0]   ),   p[1]),   p[2]   )   ;        p[4]   =   SAG(   SAG(   SAG(   SAG(   p[4],   p[0]   ),   p[1])   ,p[2]),   p[3]   )   ;    }    实际置换:    int   rep(   unsigned   x   )   {         x   =   SAG(x,p[0]);        x   =   SAG(x,p[1]);        x   =   SAG(x,p[2]);        x   =   SAG(x,p[3]);        x   =   SAG(x,p[4]);        return   x   ;    }       二进制码到GRAY码的转换:    unsigned   B2G(unsigned   B   )    {        return   B   ^   (B>>1)   ;    }    GRAY码到二进制码:    unsigned   G2B(unsigned   G)    {        unsigned   B   ;        B   =   G   ^   (G>>1)   ;        B   =   G   ^   (G>>2)   ;        B   =   G   ^   (G>>4)   ;        B   =   G   ^   (G>>8)   ;        B   =   G   ^   (G>>16)   ;        return   B   ;    }       找出最左0字节的位置:    int   zbytel(   unsigned   x   )    {        static   cahr   table[16]   =   {   4,3,2,2,   1,1,1,1,   0,0,0,0,   0,0,0,0   }   ;        unsigned   y   ;        y   =   (x&0x7f7f7f7f)   +   0x7f7f7f7f   ;        y   =   ~(y|x|0x7f7f7f7f)   ;        return   table[y*0x00204081   >>   28]   ;//乘法可用移位和加完成    }       /******************************************************************/ 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值