//这篇笔记是个人学习笔记,如有错误感谢纠正。
在计算机中数字是以二进制0和1来表示的,而关于二进制也有自己独特的位运算符号如&、|、^等等,这篇笔记就来讲讲二进制及其位运算。
二进制:
计算机以它能看懂的语言来执行操作,0和1就如同开关一样代表这最精炼的符号,在二进制中数字逢二进一,就像十进制的逢十进一一般。//为了在下文区分,就在二进制表示的数字外加个括号。
2 -> (10),10 -> (1010),诸如此类,可以看出来在二进制的每一位代表2的(n-1)次方。
二进制中的加减法和十进制类似,加法逢二进一,减法低位不够向高位借一。
我们的位运算就是据此展开。
位与&:
位与运算符(&), 示例:x & y,特点是遇0则0,全1则1,也可以理解为无论是0或1,&0则0,无论是0或1,&1还是它本身。
代码示例:
#include<stdio.h>
int main(){
int a = 0b0110;
int b = 0b1010;
printf("%d\n", (a&b));
return 0;
}
其中的0b前缀表示这是一个二进制数,最后的输出结果是2。
例:
如果我们需要判断一个数的奇偶性,可以将其&1,因为一个数转换为二进制后最低位只会是0或1,如果最低位是0即偶数,&1后仍是0,最低位是1即奇数,&1后仍为1。
#include<stdio.h>
int main(){
int a;
if(a & 1)
printf("%d是奇数\n", a);
else
printf("%d是偶数\n", a);
return 0;
}
如果我们需要取一个数二进制的后几位,就&0b10```(取决于要取几位)。
如果要消去末尾连续1,可用a&(a+1)。
如果判断是否为2的幂,可用a&(a-1)。
位或|:
位或运算符(|),示例:x | y,特点是遇1则1,全0则0。
代码示例:
#include<stdio.h>
int main(){
int a = 0b0110;
int b = 0b1010;
printf("%d\n", (a | b));
return 0;
}
结果为16。
例:
如果判断一个数二进制的第几位是否为0,如果为0置为1,可用该数位与0b100```(取决于判断第几位)。
异或^:
异或运算符(^),示例:x ^ y,两位不同^则1,相同则0,即1^0 = 0^1 = 1,0^0 = 1^1 = 0。
可得结论:两个相同的十进制数异或一定为0。一个数与0异或仍为它本身。
代码示例:
#include<stdio.h>
int main(){
int a = 0b0110;
int b = 0b1010;
printf("%d\n", (a^b));
return 0;
}
结果为14。
例:
交换变量a和b,可以不用临时命名一个temp了,可以用如下代码:
#include<stdio.h>
int main(){
int a, b;
while(scanf("%d %d", &a, &b) != EOF){
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("%d %d\n", a, b);
}
return 0;
}
按位取反~:
取反运算符(~), 示例:~a,将0变1,将1变0。
在这块内容还涉及补码的概念:
计算机中二进制编码是采用补码的形式表示的,补码的定义如下:
正数的补码为它本身,符号位为0,负数的补码为正数数值二进制位取反后加1,符号位为1。(符号位为左数起第一位)
例子(-2的补码):
1.先对2进行取反:
- ~00000000 00000000 00000000 00000010
- 111111111 111111111 111111111 111111101
2.再加1:
- 111111111 111111111 111111111 111111101
- +00000000 00000000 00000000 00000001
- 111111111 111111111 111111111 111111110
补码的重要在于补,二进制中两个互为相反数的数字相加等于2的n次方,对于32位整形为32,64位整形为64。
左移<<:
左移运算符(<<),示例:a << b,代表着a的二进制左移b位,也同于将该数乘2的b次方,如0b10001<<2 = 0b1000100,负数同理。
右移>>:
右移运算符(>>),示例:a >> b,代表着a的二进制右移b位,也同于将该数除与2的b次方,如0b10001>>2 = 0b100,负数同理且符号不变。