目錄
今天看到一個算法題,其中有一個解法是通過位運算來提高效率的。然後寫這篇博客來回憶與總結以下位運算的知識
一、原碼
原碼(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)