0 前提
在Java中,所有數據的表示方式都是以補碼形式來表示
在Java中,所有數據的表示方式都是以補碼形式來表示
在Java中,所有數據的表示方式都是以補碼形式來表示
public static void main(String[] args) {
int num = 5;
System.out.println(num + "的補碼 " + Integer.toBinaryString(num));
num = -1;
System.out.println(num + "的補碼 " + Integer.toBinaryString(num));
num = -3;
System.out.println(num + "的補碼 " + Integer.toBinaryString(num));
}
# 5的補碼 101 #int是32位長度 但是前面都是0 省略了
# -1的補碼 11111111111111111111111111111111
# -3的補碼 11111111111111111111111111111101
0.1 機器數
一個數在計算機中的二進制表示形式, 叫做這個數的機器數。機器數是帶符號的,在計算機用一個數的最高位存放符號, 正數0,負數為1
比如,十進制中的數 +3 ,計算機字長為8位,轉換成二進制就是0000 0011。如果是 -3 ,就是 1111 1101 。那么,這里的 00000011 和 1111 1101 就是機器數。 機器數包含了符號和數值部分。
0.2 真值
因為第一位是符號位,所以機器數的形式值就不能很好的表示真正的數值。
例如上面的有符號數1111 1101(8位),其最高位1代表負,其真正數值是 -3 而不是形式值253(1111 1101按無符號整數轉換成十進制等於253)。所以,為區別起見,將帶符號位的機器數對應的真正數值稱為機器數的真值。
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –0111 1111 = –127;這里所說的比如-3二進制代碼為10000011,就是我們計算機里面對-3表示的原碼
1 規定
1.1 原碼
原碼:原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其余位表示值.
比如如果是8位二進制
[+1]原 = 0000 0001
[-1]原 = 1000 0001
[-3]原 = 1000 0011
比如如果是32位二進制
[+1]原 = 0000 0000 0000 0000 0000 0000 0000 0001
[-3]原 = 1000 0000 0000 0000 0000 0000 0000 0011
1.2 反碼
反碼:正數的反碼與其原碼相同;負數的反碼是對其原碼逐位取反,但符號位除外
8位二進制
[+1] = [ 0000 0001 ]原碼 = [ 0000 0001 ]反碼;
[-1] = [ 1000 0001 ]原碼 = [ 1111 1110 ]反碼;
1.3 補碼
補碼:正數的補碼為其本身,負數的補碼為其反碼再加1
8位二進制
[+1]=[0000 0001]原碼=[0000 0001]反碼=[0000 0001]補碼
[-1] =[1000 0001]原碼=[1111 1110]反碼=[1111 1111]補碼
補碼的補碼為原碼
2 總結
-
在Java中,所有數據的表示方式都是以補碼形式來表示
-
正數:原碼、反碼、補碼相同
-
負數:符號位(最高位)為1,其余各位是對原碼取反是反碼,然后反碼加1是補碼
3 二進制運算
- 與 (&)按位與運算
- 或 (|)按位或運算
- 異或 (^)異或運算
- 非(~)運算符
3.1 測試1
public static void main(String[] args) {
int num = ~5;
System.out.println(num + "的補碼 " + Integer.toBinaryString(num));
}
#-6的補碼 11111111111111111111111111111010
解釋
5非運算為什么是-6?
-
5對應補碼 0000 0101;
-
5取非(所有二進制位上取非):1111 1010
-
求補碼1111 1010的原碼,由補碼的補碼就是原碼知:
[1111 1010] -> 反碼 [1000 0101] ->補碼 [1000 0110]
則 補碼1111 1010的原碼為1000 0110。
原碼為1000 0110對應的真值為最高位1為負數,各級求和-1*(4*1 + 2*1)= -6
注意,取非和取反碼不一樣
-
取非是所有位上都取反;
-
取反碼,最高位即符號位不取反,其他位取反
3.2 測試2
位移運算:
- >> n 右移n位,一個正數的補碼整體右移n位,不足補0,負數最高位補1
- << m 左移m位,一個數的補碼整體左移m位,不足補0
public static void main(String[] args) {
int num = 5 << 2;
System.out.println(num + "的補碼 " + Integer.toBinaryString(num));
num = 5 >> 5;
System.out.println(num + "的補碼 " + Integer.toBinaryString(num));
}
# 20的補碼 10100
# 0的補碼 0
解釋
左移:
- 5的補碼 0000 0101;
- 先左移兩位后:0001 0100;(二進制補碼整體左移兩位,末位空出的補上0)
- 0001 0100計算后1*(16 + 4)= 20;
右移:
- 5的補碼 0000 0101;
- 先右移五位后:0000 0000;
- 對應0
注意:
- 負數的位移運算要小心,負數右移最高位補的是1,而不是0了
3.3 應用
3.3.1 快速計算奇數還是偶數
public static void main(String[] args) {
int num = -150;
if((num & 1) == 0){
System.out.println("偶數");
}else {
System.out.println("奇數");
}
}
3.3.2 快速計算2^n(2的n次方)
public static void main(String[] args) {
System.out.println(1 << 16);
}
注意:整數默認是int,而int是32位有符號整數,取值范圍-2^31 到(2^31 -1)
所以一個數的左移不要超過范圍了。