常用位运算

检测一个无符号数是不为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 &brvbary)+(x&y)

x-y = x + ~y + 1 = (x ¦~y)-(~x&y)

x^y = (x &brvbary)-(x&y)

x &brvbary = (x&~y)+y

x&y = (~x &brvbary)-~x

 

x==y:    ~(x-y &brvbary-x)

x!=y:    x-y &brvbary-x

x < y:    (x-y)^((x^y)&((x-y)^x))

x <=y:    (x ¦~y)&((x^y) ¦~(y-x))

x < y:    (~x&y) ¦((~x &brvbary)&(x-y))//无符号x,y比较

x <=y:    (~x &brvbary)&((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 &brvbarx &brvbar0x7f7f7f7f) ;

    return table[y*0x00204081 >> 28] ;//乘法可用移位和加完成

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值