大家好,欢迎来到IT知识分享网。
本文来自——赶路人儿 按位与、或、异或运算以及其应用_按位或-CSDN博客
于 2020-03-23 01:24:25 发布
1、定义:
1)按位与运算(&):双目运算符,其功能是参与运算的两数对应的二进位相与,只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。
例如:
9&5=1 00001001 (9的补码) & 00000101 (5的补码) = 00000001 (1的二进制补码)。
清零特定位 (mask中特定位置0,其它位为1,s=s&mask)
取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask)
掩码 mask 应该在第3位设置为 1,其他位设置为 0,以便只保留第3位,其他位都会被清零。 假设我们数的位数是8位,第3位是1,那么掩码 mask 应该是 00000100。 执行操作 s = s & mask 后,结果将只包含 s 的第3位,其他位都将被清零。如果 s 的第3位是1,结果将为 00000100,如果是0,则结果为 00000000。 正确的操作应该是: 清零特定位: 假设 s = (二进制) 要清零第3位,掩码 mask = (第3位是0,其余都是1) s & mask 后,s 变为 取某数中指定位: 假设 s = (二进制) 要取第3位,掩码 mask = 00000100(第3位是1,其余都是0) s & mask 后,如果第3位是1,结果为 00000100,如果是0,则结果为 00000000。 这样,通过掩码操作,我们可以控制特定位的清零或提取。
例如:
9|5=13,可写算式如下: 00001001 (9的补码) | 00000101 (5的补码) = 00001101 (十进制为13)
常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
3)按位异或运算(^):双目运算符,其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。参与运算数仍以补码出现。
例如:
9^5=12,可写成算式如下: 00001001 (9的补码) ^ 00000101 (9的补码) = 00001100 (十进制为12)
与0相∧,保留原值;
两个相同数异或,结果为0;
异或操作满足结合律和交换律;
将源操作数某些位翻转(1变0,0变1), (mask中特定位置1,其它位为0 s=s^mask)
交换两个值,不用临时变量;(如下)
a = a^b; (把a = a^b; 中的第一个a看成第三个参数C,就能理解)
b = a^b;
a = a^b;
例如:
2、使用二进制位运算设计权限:
1)原理:
我们都知道在linux中,x – 可执行权限,w – 可写权限 , r – 可读权限。其权限值分别是1,2,4。有没有想过为什么是1,2,4 而不是 1,2,3 呢?
观察发现,这些权限对应的int数值都是2的幂次方,对应的二进制如如下:
1:0000 0000 0000 0000 0000 0000 0000 0001 2:0000 0000 0000 0000 0000 0000 0000 0010 4:0000 0000 0000 0000 0000 0000 0000 0100 8:0000 0000 0000 0000 0000 0000 0000 1000
使用二进制的方式来表示权限的优点:
运算速度块(位运算在计算机内部非常高效)
通过按位与、或、异或操作高效的进行权限添加、删除和判断。
private static void quanxianTest() { //1.定义权限:权限值使用int类型表示,且满足2的N次方 int c = 1;//create,二进制表示:...0 0001 int r = 2;//retrieve,二进制表示 ...0 0010 int u = 4;//update,二进制表示 ...0 0100 int d = 8;//delete,二进制表示 ...0 1000 //其他权限:16、32、64...; //2.初始化权限 int usera = c | r | u;//初始化用户A的权限,等价于c+r+u=7 int userb = c | d;//初始化用户B的权限,等价于c+d=9 int userc = 13;//初始化用户C的权限,即:c+u+d=13 System.out.println("usera 权限值:"+usera); System.out.println("userb 权限值:"+userb); System.out.println("userc 权限值:"+userc); //3.判断权限 if ((usera & u) == u) {//与操作结果只有两种:0或u System.out.println("usera有u权限"); } if ((userb & u) == 0) { System.out.println("userb没有u权限"); } if ((userc & c) != 0) { System.out.println("userc有c权限"); } //添加权限 userb = userb | u;//或者userb = userb + u; if ((userb & u) == u) { System.out.println("userb有u权限,userb的权限值="+userb); } //删除权限 usera = usera & (~r);//或者usera = usera - r; if ((usera & r) == 0) { System.out.println("user a没有r权限,usera的权限值="+usera); } }
使用二进制的与或非来设计权限的步骤:
- 定义权限,权限的int值分别是2的幂次方,即1、2、4、8…
- 添加权限时使用或(|)运算,最终权限值在数值上=对应的权限值加在一起;
- 删除权限时使用与(&)和异或(~)运算,最终权限值在数值上=原权限值-删除的权限值
- 判断权限是使用与(&)运算,结果等于非零(或对应权限的值)时表示有该权限,结果等于0表示没有该权限;
注:只有当权值是2的幂次方时,或(|)运算相当于加法、与(&)运算相当于减法。
https://www.cnblogs.com/jifeng/archive/2013/03/03/2941159.html
3、使用二进制位运算存储数据信息:(类似bitmap)
在设计程序时,我们经常会运到一种情况:某个类有多个属性值时,且这些属性的取值为1和0。这时,我们的常规思路是每个属性使用一种类型表示(boolean或int),优点是清晰,缺点是浪费空间(假设我们有2kw个这样的对象)。
为了节省空间,我们使用一个int类型的变量,来表示类的所有属性。int类型变量值转成二进制位,每一位表示一个属性值(0或1)——bitMap算法思想。
1)原理:
根据位运算的定义,我们可以得出以下结论:
将int型变量a的第k位清0:即a=a&~(1<<k)
将int型变量a的第k位置1:即a=a|(1<<k)
取int型变量a的第k位:即a>>k&1
例如:
将31的第8位设置成1,可以表示成:31的二进制|(1<<8) 1)31的二进制: 00000000 00000000 00000000 00011111 2)1的二进制: 00000000 00000000 00000000 00000001 左移动8位: 00000000 00000000 00000001 00000000 3)31|(1<<8)表示成: 00000000 00000000 00000000 00011111 | 00000000 00000000 00000001 00000000 = 00000000 00000000 00000001 00011111
2)示例:
private static void test0() { int a = 31; System.out.println(toBinaryString(a));//按2进制输出 //00000000 00000000 00000000 00011111 //将int型变量a的第k位清0,即a=a&~(1<<k) int b = a & ~(1<<3); System.out.println(toBinaryString(b)); //00000000 00000000 00000000 00010111 //将int型变量a的第k位置1, 即a=a|(1<<k) int c = a | (1<<8); System.out.println(toBinaryString(c)); //00000000 00000000 00000001 00011111 //取int型变量a的第k位,(k=0,1,2……sizeof(int)),即a>>k&1 int d = a >> 2 & 1; System.out.println(d);//1 int d2 = a & (1<<2); System.out.println(d2);//4 } public static String toBinaryString(int a) { StringBuilder sb = new StringBuilder(); for(int i=0;i<32;i++){ int t = (a & 0x>>>i)>>>(31-i); //System.out.println(t); sb.append(t); if ((i+1) % 8 ==0) { sb.append(" "); } } return sb.toString();
补充:取int型变量a的第k位:即a>>k&1
这个表达式常用于判断一个数的二进制表示中特定位置(右移k 位后的最低位)的值是0 还是1。
a的二进制表示中,第k位是几
表达式 “a >> k & 1″ 中,” >>” 操作符的优先级比 “&” 高。因此,该表达式会先执行右移操作,然后再执行按位与操作。
表达式 “a >> k & 1” 是一个位操作表达式,其中包含了右移和按位与操作。
具体含义如下:
- a >> k 表示将变量 a 的二进制表示向右移动 k 位。
- & 1 表示对结果执行按位与操作,即将结果与二进制数 1 进行按位与操作。
综合起来,表达式 “a >> k & 1” 的含义是:将变量 a 的二进制表示向右移动 k 位,然后对结果执行按位与操作,并且只保留最后一位。
这样的操作通常用于提取变量 a 中的特定位,例如检查变量 a 的二进制表示中的第 k 位是否为 1。
表达式 `a >> k & 1` 在编程中通常用于检查一个数 `a` 右移 `k` 位后的最低位(即二进制表示的最右边一位)是否为1。这里,`>>` 是位右移运算符,`&` 是位与运算符。 具体步骤如下: 1. `a >> k`:将数 `a` 的二进制表示向右移动 `k` 位。右移时,左边会填充0(在大多数编程语言中,包括C和C++)。 2. `a >> k & 1`:将右移后的结果与1进行位与运算。由于1的二进制表示为 `0001`(假设 `a` 是一个32位整数),这个操作实际上就是检查右移后结果的最低位是否为1。 如果 `a` 右移 `k` 位后的最低位是1,那么 `a >> k & 1` 的结果是1;如果是0,结果是0。 例如,如果 `a = 13`(二进制为 `1101`)且 `k = 1`,那么: 1. `a >> k = 13 >> 1 = 6`(二进制为 `0110`) 2. `a >> k & 1 = 0110 & 0001 = 0`(最低位是0) 所以,`13 >> 1 & 1` 的结果是0。 如果 `a = 13` 且 `k = 0`,那么: 1. `a >> k = 13 >> 0 = 13`(二进制为 `1101`) 2. `a >> k & 1 = 1101 & 0001 = 1`(最低位是1) 所以,`13 >> 0 & 1` 的结果是1。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/112296.html