原码、反码、补码,位运算符
一、概念
原码、反码、补码:最高位均为符号位,1表示负数,0表示正数**。
正数的原反补码均相同,负数才不相同。
原码:最高位为符号位,其余位使用该数值的绝对值表示。
反码:在原码的基础上,符号位不变,原****码的其他位均取反**。
补码:反码+1,即在原码的基础上,符号位不变,原码的其他位取反后+1。补码的补码为原码。
二、补码的引入解决的问题
1、计算机中因符号位参与运算而得不到正确结果的现象
例如:-1-127=-128
原码:10000001[原] - 01111111[原] = 01111110[原]=126
反码:111111110[反] - 01111111[反] = 01111110[反]=126
补码:111111111[补] - 01111111[补] = 10000000[补]=-128
注意:根据上面的运算得到-128的原码是00000000[原]是不对的。
2、使用补码,**表示的范围扩大了,能多表示一个最小的数。**即使用补码byte能表示的范围是-128~127,而原码、反码均为-127-127,因为在这两者中都各存在一个正0和负0,而补码中的负0被-128取代。
三、位运算符
-
逻辑运算符
&按位与,|按位或,~按位非,^按位异或,字面意思,按位操作区别于&&短路与,||短路或,!非。
注意:|和&同时也可以表示非短路的与和或。 -
移位运算符
移位运算符只适合对整数类型的数据进行操作(byte,short,char,int,long)
对于低于int类型的基础类型数据自动转化为int后再进行移位操作
移位运算符的右操作数要对32取余(long为64),例如1<<34=1<<2
左移运算符<<:左移后末尾补上0,可能改变数字的正负。例如-2^31(补码是10…29个0.0)<<1=0
右移运算符>>:右移后左边全部补上符号位,不会改变数字的正负
无符号右移>>>:用0填充左边的空位
不溢出的情况下,可以理解为左移n位相当于乘以2^n
相反右移除以2^n
四、应用举例
1、判断int型变量a是奇数还是偶数
a&1 = 0 偶数
a&1 = 1 奇数
2、取int型变量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1
3、将int型变量a的第k位清0,即a=a&~(1<<k)
4、将int型变量a的第k位置1, 即a=a|(1<<k)
5、int型变量循环左移k次,即a=a<<k|a>>16-k (设sizeof(int)=16)
6、int型变量a循环右移k次,即a=a>>k|a<<16-k (设sizeof(int)=16)
7、整数的平均值
对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的,我们用如下算法:
int average(int x, int y) //返回X,Y 的平均值
{
return (x&y)+((x^y)>>1);
}
8、判断一个整数是不是2的幂,对于一个数 x >= 0,判断他是不是2的幂
boolean power2(int x)
{
return ((x&(x-1))==0)&&(x!=0);
}
9、不用temp交换两个整数
void swap(int x , int y)
{
x ^= y;
y ^= x;
x ^= y;
}
10、计算绝对值
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ; //or: (x+y)^y
}
11、取模运算转化成位运算 (在不产生溢出的情况下)
a % (2^n) 等价于 a & (2^n - 1)
12、乘法运算转化成位运算 (在不产生溢出的情况下)
a * (2^n) 等价于 a<< n
13、除法运算转化成位运算 (在不产生溢出的情况下)
a / (2^n) 等价于 a>> n
例: 12/8 == 12>>3
14、a % 2 等价于 a & 1
15、if (x == a) x= b;
else x= a;
等价于 x= a ^ b ^ x;
16、x 的相反数表示为 (~x+1)
上一篇: 最短路径算法---有向图
下一篇: 天梯赛倒数第n个字符串