//整型变量的存储方式以及位运算均以补码方式进行:(正数原码反码补码均相同)
例如:-13
原码:10001101(原码的第一位表示符号位:1表示负数,0表示正数)
反码:11110010(符号位不变其他位取反)
补码:11110011(反码加一)
按位与:全1为1,有0则0
//把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0 。
//那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。(可以用来计算2进制数中1的个数)
int Count(int n)
{
int num = 0;
while (n)
{
n &= (n - 1);
num++;
}
return num;
}
//与运算一用途:取一个数中指定位。找一个数,对应X要取的位,该数的对应位为1,其余位为零,此数与X进行“与运算”可以得到X中的指定位。例:设X=10101110,取X的后4位,用 X & 0000 1111 = 0000 1110 即可得到;还可用来取X的2、4、6位。
按位或:有1则1,全0为0
负数进行按位操作后得到的依然为补码:若要求其具体值还要转换成原码
int main()
{
int a = 8;
int b = -3;
// 8的原码:00000000000000000000000000001000
// -3的原码:10000000000000000000000000000011
// 反码:11111111111111111111111111111100
// 补码:11111111111111111111111111111101
// 8的补码为:00000000000000000000000000001000
//8 | -3得到:11111111111111111111111111111101(得到补码)
//转换为原码:10000000000000000000000000000011(即为二进制的-3)
int c = a | b;
printf("%d\n", c);//输出-3
return 0;
}
按位异或^:相同为0,相异为1
按位异或的3个特点:
(1) 任何数字异或它自己都等于0;
(2) 0异或任何数,等于任何数;
(3) 1异或任何数,等于取反任何数。
//进行异或运算时,当前位的两个二进制表示不同则为1相同则为0.该方法被广泛推广用来统计一个数的1的位数!
int main()
{
int n = 0;
int i = 0;
int count = 0;
scanf("%d", &n);
for (i = 0; i < 32; i++)
{
if ((n ^ 1) == n - 1)//如果最后一位为1则异或1后小1;
count++;
n >>= 1;//右移一位
}
printf("%d\n", count);
return 0;
}
//异或运算也可进行两个数的交换(不需要创建新的变量):
int main()
{
int a = 3;
int b = 5;
printf("a=%d b=%d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
//类似于加减法中的:
//a = a + b; b = a - b; a = a -b;
printf("a=%d b=%d\n", a, b);
return 0;
}
利用异或的三个特点也可以解决某些问题:
如:1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;
正常解法这里就不说了,而且如果数字较大了话正常解法可能造成栈溢出,利用异或的特点1也可以迅速把它找出来。
int main()
{
int arr[1001] = { 5 };
int i = 0;
int x = 0;//存储重复的数字
for (i = 1; i < 1001; ++i)
arr[i] = i;//得到1-1000且只含有一个重复数字的数组
int j = 0;
for (j = 0; j < 1001; j++)
x = x^ arr[j];//首先对数组内每个元素异或一遍
for (j = 1; j < 1001; j++)
x = x ^ j;//对1-1000的数字异或一遍
//这里相当于1-1000中除了重复那个其他数字均异或两遍,
// 根据特点1、2可以得出x的值即为重复元素的值
printf("%d\n", x);
}