移位

来源:互联网 发布:nginx 403 权限 编辑:程序博客网 时间:2024/05/16 23:55

运算符巧用

看源码是每个程序员必过的坎儿,刚开始看源码真的太痛苦了….没办法,只有不断的看源码才能了解一些原理,才能快速的进步。在源码的过程中你坑定遇到过这样位运算那样位运算,当位运算你肯定清除,但是运算符一组合,就懵了。。。。什么鬼,反正我就是这样,就是知识我们不熟悉其中运算的效果而已。

计算机中是以补码的形式保存所有整数的
负数:源码除最高符号位,其余为按位取反得到反码,反码+1得到补码
正数:源码和补码相同

补码—>源码:补码-1=得到反码,发码出最高符号位,其余为取反得到原码

  • (>>):有移,(X>>Y)X为int类型,X转化为32位的二进制,如果为正数,左边空位用0补位,如果为负数,用1补位;相当于X除以2的y方

  • (>>>)(无符号有移):都用0 补位

  • <<:移动后,右边有0补位;相当于X乘以2的Y方

关于移位运算符>>、<<、>>>并不是适合所有数值类型,只适合byte、short、char、int、long等整数类型进行运算;

总结:
1. 一个32位的int整数,右移(b>>a),当a>32时,系统用b%32得到结果才是移位的位数。例如:a>>33和a>>1结果是一样的(因为int类型只有32位),a>>32还是a本身。
2. 一个64位的long整数,右移(b>>a),当a>64时,系统用b%64得到结果才是移位的位数。例如:a>>64和a>>1结果是一样的,a>>64还是a本身。
2. 对于低于int类型的操作数(如byte、short、char)总是会自动转化为int在移位

^(异或)

相同为0,不同为1

1 1—>0

0 0—>0

1 0—>1

0 1—>1

特定位取反

最后一位取反:X^1(高位不变(位与0异或不变))

        0111    ^   0001---------------        0110

对异或取反,叫做(同或)或者(异或非)

巧用技巧

奇偶数判断

        0101    &   0001--------------        0000

利用最有一位是否是1,判断是否是奇数;为1,就是奇数;为0就是偶数;
X&1=1,表示X为奇数
X&1=0,表示X为偶数

不用temp交换两个数

X=5,y=4

X^=y;y^=X;X^=y

即可交换X、y的值;

特定位取反

使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask),源源操作数异或操作即可
右数第k位取反:x ^ (1 < < (k-1))

取模运算转化为位运算

X%(2^n)<====>X&((2^n)-1)

清除特定位

源操作数X与掩码mask(特定位为0 其他位都为1)&

举例说明:这里我们要将5(0101)的第三位清除,mask=1011

    0101&    1011--------------    0001

总结一下公式:X&((1<

取特定位

同样是源操作数和mask(只不过这里特定位为1,其他位为0)与;就不在举例说明,可以参看后面的取出指定位部分

将int型变量a的右起的第k位置1

a=a|(1 <<(k-1))

把右数第k位变成0

x & ~ (1 < < (k-1))

求两个整数的平均值

(X+Y)+((X+Y)>>1)

判断一个整数是不是2的幂(是不是2的n次方(n=0,1…..))

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

——(Android运用)—-

使用位运算来表示共同具有哪些属性,对应为为1就表示具有该属性,为0就表示不具有该属性;
举个例子:

0x01(0001)表示可读
0x02(0010)可写
0x03(0011)表示可读可写

a&~b:   清除标志位b;a|b:       添加标志位b;a&b:     取出标志位b;a^b:    取出a与b的不同部分;

Android中对flag主要由三种操作

  1. 通过“|”运算向flag变量中增加某个Flag;
    原因: 如果flag变量没有XXX_FLAG,则 | 完后flag对应的位为1,如果有XXX_FLAG,则 | 完后值不会变对应位还是1.

flag|=XX_Flag;

  1. 通过“&”判断flag变量中是否包含XX_Flag

    flag & XXX_FLAG != 0 或者 flag & XXX_FLAG = XXX_FLAG

原因: 如果flag变量里包含XXX_FLAG,则&完后flag变量对应的位为1,因为XXX_FLAG的定义保证了只有一位非0,其他位都为0,所以如果是包含的话&运算后值不为0,值为此XXX_FLAG的值,不包含的话值为0.
flag&XX_Flag:得到的就是XX_Flag标志位的值即取出XX_Flag标志位;举例说明:

        0011(可读可写)              0001    &   0010(可写)                &   0010---------------             ---------------        0010(可写)                    0010

可以看见取出对应的标志位状态,之前是改为是什么状态(是否是可写状态),与对应位掩码&后,就可以得到该标志位的状态。

Android中应用:

    // 返回是否可点击   return (((viewFlags & CLICKABLE) == CLICKABLE ||      (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); 

3. 取消属性( 取消flag变量中XX_flag)

flag&=~XX_flag;

原因:先对XXX_FLAG进行取反 则XXX_FLAG原来非0的那一位变为0,则使用&运算符后flag变量非0的那一位变为0,则意味着flag变量不包含XXX_FLAG
4. 标志位取反(比如之前是可读不可写状态0001,和掩码0011一异或,对应位(读、写标志位)的标志位都置反了,变成了0010(可写不可读了))

            0001        ^   0011    -----------------            0010

Android中运用:

……   private static final int PRESSED                = 0x00004000;   int mPrivateFlags ;  ……       public void setPressed(boolean pressed) {          if (pressed) {              mPrivateFlags |= PRESSED;     // 添加PRESSED状态          } else {              mPrivateFlags &= ~PRESSED;    // 取消PRESSED状态          }          refreshDrawableState();          dispatchSetPressed(pressed);      }  
  1. 获取X指定低N位的集合

举例说明:获取233的第6位

        11,101001    &        00,111111--------------------------        00,101001可以推导出公式就是:X&(N<<k)-1

获取X高N位:
x & (((1 << n) - 1) << (sizeof(x)-n))

sizeof(X):表示X的位数,比如这里是8位