您的位置:首页 > 其它

位操作实用技巧大全

2012-01-03 16:02 330 查看
检测一个无符号数是不是2^n-1(^为幂):
x&(x+1)


将最右侧0位改为1位:
x | (x+1)

获得最右侧的0

(x | (x+1))^x


将最右侧的1位改为0位
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:

x ^= y ; y ^= x ; x ^= y ;
x = x+y ; y = x-y ; x = x-y ;
x = x-y ; y = y+x ; x = y-x ;
x = y-x ; x = y-x ; x = x+y ;


双值交换:

if (x==a) x = b;

else x = a;

//常规编码为x = ( x==a ? b :a) ;

x = a+b-x ;
x = a^b^x ;


//下舍入到2的k次方的倍数:
x & ((-1)<<k)
(((unsigned)x)>>k)<<k

//上舍入:
 t = (1<<k)-1 ; x = (x+t)&~t ;
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] ;//乘法可用移位和加完成
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: