位操作

位操作基础

符号

 描述

 运算规则                        by MoreWindows

&      

 与

两个位都为1时,结果才为1

|  

 或    

两个位都为0时,结果才为0

^    

异或

两个位相同为0,相异为1

~   

取反

0变1,1变0

<< 

左移

各二进位全部左移若干位,高位丢弃,低位补0

>> 

右移

各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

常用位操作小技巧

判断奇偶
只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数。

// 下面程序将输出0到100之间的所有奇数。
private void Start()
{
    for (int i = 0; i < 100; i++)
    {
       if(((i&1)==0?false:true))
       {
           Console.WriteLine(i);
       }
    }
}

交换两数
一般的写法是:

private void Swap(ref int a,ref int b)
{
    int c=a;
    a=b;
    b=c;
}

用位操作来实现交换两数而不用第三方变量:

private void Swap(ref int a,ref int b)
{
    a^=b;
    b^=a;
    a^=b;
}

变换符号
如对于-11和11,可以通过下面的变换方法将-11变成11
1111 0101(二进制) –取反-> 0000 1010(二进制) –加1-> 0000 1011(二进制)

同样可以这样的将11变成-11
0000 1011(二进制) –取反-> 0000 0100(二进制) –加1-> 1111 0101(二进制)

因此变换符号只需要取反后加1即可。完整代码如下:

private static int SignReversal(int a)
{
    return ~a + 1;
}

求绝对值
位操作也可以用来求绝对值,对于负数可以通过对其取反后加1来得到正数。对-6可以这样:
1111 1010(二进制) –取反->0000 0101(二进制) -加1-> 0000 0110(二进制)来得到6。
因此先移位来取符号位,int i = a >> 31;要注意如果a为正数,i等于0,为负数,i等于-1。然后对i进行判断——如果i等于0,直接返回。否之,返回~a+1。完整代码如下:

private int ABS(int num)
{
    int i = num >> 31;
    return i == 0 ? num : (~num + 1);
}

现在再分析下。对于任何数,与0异或都会保持不变,与-1即0xFFFFFFFF异或就相当于取反。因此,a与i异或后再减i(因为i为0或-1,所以减i即是要么加0要么加1)也可以得到绝对值。所以可以对上面代码优化下:

int my_abs(int a)
{
	int i = a >> 31;
	return ((a ^ i) - i);
}

求平均数
求平均数 (x+y)/2 这样吗?考虑过 x+y可能超过int的范围吗?正确的姿势是 (x&y)+((x^y)>>1)
// x+y = 奇数,例137,该算法 = 68; x+y = 偶数,例136,该算法 = 68;

private int average(int x,int y)
{
    return (x&y)+((x^y)>>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比较

posted @ 2021-10-05 16:12  镜子-眼泪  阅读(79)  评论(0)    收藏  举报