目录
今天看到一个算法题,其中有一个解法是通过位运算来提高效率的。然后写这篇博客来回忆与总结以下位运算的知识
一、原码
原码(true form)是一种计算机中对数字二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。 ----百度百科
例如:11的原码为00001011 ,-11的原码为10001011,其中一位符号位,七位数据位。
代码实现(整数部分):
public static void bytedata(int byte_length,int data)//其中byte_length代表着几位
{ Stack<Integer >stack=new Stack<>();//存储数据
boolean Negative=false;
if(data<0)//如果是负数那么就标记,并且将其转化为负数
{ data=Math.abs(data);
Negative=true;
}
while(data!=0)//不断除2
{
stack.push(data%2);
data=data/2;
}
int middle_size=stack.size();
for(int i=middle_size+1;i<=byte_length-1;i++)//保留一位变成符号位
{ stack.push(0);
}
if(Negative)
stack.push(1);
else
stack.push(0);
System.out.print("二进制数据为:");
while(!stack.isEmpty())
System.out.print(stack.pop());
}
public static void main(String args[])
{
bytedata(8,4);//8位数据表示,4代表值
}
实现结果:
代码实现(小数部分):
//小数部分处理
public static void float_data(float data)
{ ArrayList<Integer> arrayList=new ArrayList<>();
boolean Negative=false;
int j=0;
if(data<0)
{
data=Math.abs(data);
Negative=true;
}
while(Math.abs(data-0.0)>0.000001)
{ data=(data*2);
if(data>1)
{
arrayList.add(1);
data=data-1;
}
else if(data<1)
arrayList.add(0);
else
{ arrayList.add(1);
break;
}
}
if(Negative)
System.out.print("-0.");
for (int i = 0; i < arrayList.size(); i++) {
System.out.print(arrayList.get(i));
}
}
运行结果:
二、反码
就是原码按位取反,注意符号位不动(对于负数而言,正数的原码=反码=补码)
三、补码
就是反码+1,计算机中负数用补码存储(正数的原码=反码=补码)。
四、浮点数
在计算机中浮点数一般以IEEE754的形式保存。
即单精度浮点数字长32位,尾数长度23,指数长度8,指数偏移量127;
双精度浮点数字长64位,尾数长度52,指数长度11,指数偏移量1023;
例如: 178.0625的IEEE754形式表示过程如下
整数部分178 二进制形式为10110010
小数部分 二进制为0001
整体形式为 10110010.0001 将其标准化为1.01100100001*2^7
那么移码变为7+127=134(二进制形式为10110010)
最终格式变为了0 10110010 01100100001000000000000
(想到了当初考研的情形(>!<))
五、位运算(& | ~ ^ << >>)
名称 | 规则 |
& 与运算 | 二者全为1则为1,其余为0 (与 相当于两者同时成立) |
| 或运算 | 二者之间有1则为1,其余为0 (或 相当于两者有一个成立即可) |
~ 按位取反 | 除符号位外逐位取反 。 |
^ 异或运算 | 两者相同为0,不同为1 (异或 异代表不同的意思) |
<< 左移运算 | 左移,移掉的省略,右边补零。 相当于*2 |
>> 右移运算 | 右移,移掉的省略,正数左边补0,负数左边补1。相当于/2 |
>>> 无符号右移 | 将二进制数按指定右移几位,移掉的省略,左边缺失的位,用0补齐 |
一、& 与运算
x&0=0
x&(-1)=x (因为 -1对应为11111111)
x&x=x
二、| 或运算
x|(-1) =-1 (因为-1对应的为11111111,那么逐位或下来肯定为1111111,代表着-1)
x|x =x
三、~ 逐位取反(符号位除外)
~(-1)=0 (因为-1对应的为11111111,那么逐位取反下来为100000,代表着0)
四、^ 异或运算
x^x=0
x^0=x
x^(~x)=-1 (因为~x 中 原来的1变为0,那么与x中的值不同,产生1)
(记住任何数异或自己都为0;任何数异0都为本身;进行异或的数可以无序交换)
五、<< 左移运算
相当于*2 例如 5<<3 5x2³=40
六、 >> 右移运算
相当于 /2 例如 -70>>2 -70÷2²=-18
七、>>> 无符号右移
l例如 -1>>>1 =2的31次方-1
六、位运算应用
一、判断奇偶(奇数二进制最后一位为1,偶数为0)
if((x&1)==0)
{
System.out.println("为偶数");
}
else
System.out.println("为奇数");
二、交换两个数
void swap(a,b){
a^=b;
b^=a;
a^=b;
}
计算过程(看的别人的):
a=a^b
b=b^a=b^(a^b)=(b^b)^a=a --> b=a
a=a^b=(a^b)^b^(a^b)=(a^a)^(b^b)^b=b --> a=b
三、判断正负(向右移31位获取到符号位)
int b = a>>31 ,b=0则为正,b=1则为负
四、 取相反数:
a的相反数 ~a+1
五、取反
~n=-(n+1)
六、获取整数n的二进制串中最后一个1
-n&n=~(n-1)&n
七、去除整数n的二进制串中最后一个1
n&(n-1)