一些位运算的技巧整理

扩展阅读:

 

1.判断符号是否相同(Math.Sign)

a^b >= 0

 

2.求两个整数的平均值

(x + y) >> 1;

 

3.判断基偶(比%2要快)

a & 1

结果0为偶数,为1是基数

 

4.判断一个数是不是2的幂

((x&(x-1))==0)&&(x!=0)

 

5.对一个32位数快速sign,正数为1负数为-1

x>>31 | 1

 

6.借助德布莱英序列(DeBruijn),从右取当前Mask第一个1的位数(注意传入值必须是uint,否则出错):

int[] multiplyDeBruijnBitPosition = new int[32]
{
    0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
    31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};

uint x = 1 << 7;
uint magicNumber = 0x077CB531;
int bitPosition = multiplyDeBruijnBitPosition[((x & (uint) -x) * magicNumber) >> 27];
Debug.Log("bitPosition: " + bitPosition);//7

 

7.左位移和右位移的非2次方数字乘除法规则

(出处:https://www.cnblogs.com/xiaoyaodijun/p/6744057.html)

向左位移,相当于当前参数乘以2的位移次方

3<<1   等于 3*(2的一次方) 等于 3*2
3<<2   等于 3*(2的2次方)  等于 3*4
3<<3   等于 3*(2的3次方)  等于 3*8
3<<4   等于 3*(2的4次方)  等于 3*16
向右位移,相当于当前参数除以2的位移次方

16>>1   等于 16/(2的一次方) 等于 16/2
16>>2   等于 16/(2的2次方)  等于 16/4
16>>3   等于 16/(2的3次方)  等于 16/8
16>>4   等于 16/(2的4次方)  等于 16/16

 

8.循环位移

即: 0000 0001  0000 >> 0000 1000 0000

需要借助另一个变量才可实现,如byte要转到int里再做位移。

实现思路是在高位上做一个镜像来标记,位移完做mask,这时外面移进来的镜像值刚好被mask到,从而实现循环。

代码:

private byte BitLoopShift(byte x, bool leftOrRight)
{
    uint y = x;
    y <<= 8;

    if (leftOrRight)
    {
        y |= x;
        y <<= 1;
    }
    else
    {
        uint x2 = (uint)x << 16;
        y |= x2;
        y >>= 1;
    }

    uint mask = 0b_0000_0000____0000_0000____1111_1111____0000_0000;
    y &= mask;

    y >>= 8;

    return (byte)y;
}

Unity下测试:

private void Start()
{
    for (byte i = 0, j = 1; i < 16; i++)
    {
        byte shiftBefore = j;
        byte shiftAfter = BitLoopShift(shiftBefore, true);
        j = shiftAfter;
        Debug.Log("[<<] i: " + i + " shiftBefore:" + Convert.ToString(shiftBefore, 2) + " shiftAfter: " + Convert.ToString(shiftAfter, 2));
    }

    for (byte i = 0, j = 0b_1000; i < 16; i++)
    {
        byte shiftBefore = j;
        byte shiftAfter = BitLoopShift(shiftBefore, false);
        j = shiftAfter;
        Debug.Log("[>>] i: " + i + " shiftBefore:" + Convert.ToString(shiftBefore, 2) + " shiftAfter: " + Convert.ToString(shiftAfter, 2));
    }
}

 

 

9.去掉二进制数最右边的1

11 > 10

1010 > 1000

0 > 0

x & (x - 1)

如果一个可存叠加状态的state变量,2个8位分别存2个叠加状态,清理低位数据时刚好可以用这个功能。

 

10.快速隔离二进制数最右边的1

1010 > 10

x & (-x)

这个配合希尔伯特曲线或者z曲线,可以做高效的范围查询。

 

11.快速判断二进制位是否每一位都是1

if ((i & (i + 1)) == 0)//11111
{
    //每一位都是1
}

 

12.从最右侧的一个1向右侧填充所有1

101000 > 101111

1010 > 1011

1111 > 1111

i | (i - 1)

 

13.异或可以实现二进制加法

100 xor 010 = 110

4 + 2 = 6

posted @ 2016-12-28 00:18  HONT  阅读(255)  评论(0编辑  收藏  举报