二进制可以说是专门为了计算机而设计的一种数字系统,在该系统中,只有两个数字,0和1,进位规则是“逢二进一”。
二进制对计算机来说还是很有意义的,计算机是通过一系列硬件通过电子电路连接来进行相关计算的。
在计算机电路中,二进制数通常使用逻辑信号表示,即电路中只有两种状态:高电平和低电平。其中,高电平表示二进制数中的1,而低电平表示二进制数中的0。
二进制每一位的权重,从右向左依次是:2的0次方,2的1次方,2的2次方…以此类推。
比如:二进制的1101,转换成十进制为13
十进制整数转换为二进制整数采用"除2取余,逆序排列"法。
具体做法是:用2整除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为小于1时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。
整数的二进制表示方法有三种,原码、反码和补码。
三种表示方法都有符号位和数值位这两部分,2进制序列中,最高位的1位是符号位,其余的为数值
位。其中,符号位若为0,则表示该数为正数;符号位为1,表示该数是负数;
正整数的原码、反码和补码都相同。
负整数的例外,负整数的三种码的表示方法各不相同:
原码:符号位为1,数值位和正数的数值位一样。(5和-5的数值位相同,-5的符号位为1,5的符号位为0)
反码:将原码的符号位不变,数值位依次按位取反得到反码。
补码:反码+1 得到补码。
举例:(C语言中,VS2020环境下,一个int类型,数值-5,二进制相关表示如下)
对于整形来说,数据是以补码的形式存储在内存中的
这里拓展一下知识,为什么在计算机中,数值一律用补码来表示和存储
原因:使用补码,可以将符号位和数值位进行统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码和原码相互转换,其运算过程是相同的,不需要设计额外的硬件电路就能实现。
PS:对于移位操作符,不要移动负数位(比如3 <<-1或者3 >> -1),这个是标准未定义的。
PS:一般逻辑右移比较常见,VS2020环境下右移操作也是逻辑右移。
int num = 10;
# 10乘以2的3次方
result = x << 3
# 10除以2的n次方
result = x >> 3
对于两个相应的二进制位,只有当两个位都是1时,结果才是1,否则为0。
//例如:5 & 8 = 0
00000000 00000000 00000000 00000101 //5的补码(正整数的原码、反码、补码都一样)
00000000 00000000 00000000 00001000 //8的补码
————————————————————————————————————————————————————————————————————————————————
00000000 00000000 00000000 00000000 //结果为0
对于两个相应的二进制位,只要其中一个是1,结果就是1,只有当两个位都是0时,结果才是0。
//例如:5 | 8 = 13
00000000 00000000 00000000 00000101 //5的补码(正整数的原码、反码、补码都一样)
00000000 00000000 00000000 00001000 //8的补码
————————————————————————————————————————————————————————————————————————————————
00000000 00000000 00000000 00001101 //结果为13
对于两个相应的二进制位,当两个位不同时,结果为1,当两个位相同时,结果为0。
//例如:5 ^ 8 = 13
00000000 00000000 00000000 00000101 //5的补码(正整数的原码、反码、补码都一样)
00000000 00000000 00000000 00001000 //8的补码
————————————————————————————————————————————————————————————————————————————————
00000000 00000000 00000000 00001101 //结果为13
它翻转操作数的每一位(包括符号位)
//例如:~ 5 = -6
00000000 00000000 00000000 00000101 //5的补码(正整数的原码、反码、补码都一样)
————————————————————————————————————————————————————————————————————————————————
11111111 11111111 11111111 11111010 //一个负数的补码
10000000 00000000 00000000 00000101 //反码
10000000 00000000 00000000 00000110 //原码,结果为-6
#include
int main()
{
int a = 10;
int b = 20;
printf("交换前:a = %d b = %d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后:a = %d b = %d\n", a, b);
return 0;
}
输出结果:
交换前:a = 10 b = 20
交换后:a = 20 b = 10
#include
int main()
{
int num = -1;
int i = 0;
int count = 0;//计数
while (num)
{
count++;
num = num & (num - 1);
}
printf("二进制中1的个数 = %d\n", count);
return 0;
}
输出结果:
二进制中1的个数 = 32
#include
int find_single_dog(int arr[], int sz)
{
int ret = 0;
int i = 0;
for (i = 0; i < sz; i++)
{
ret ^= arr[i];
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,1,2,3,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
int dog = find_single_dog(arr, sz);
printf("%d\n", dog);
return 0;
}
输出结果
5
这行代码运行一次,n的二进制补码中最右边的1就消失了。
也就是说,这行代码运行了几次,就说明n的二进制补码中有几个1。代码如下
#include
int main()
{
int n = 0;
scanf("%d", &n);
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
printf("%d", count);
}
这个表达式还可以用来判断n是不是2的次方。代码如下:
#include
int main()
{
int n = 0;
scanf("%d", &n);
if ((n & (n - 1) )== 0)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}