我們曾在《計算機組成原理》這門課中學習過進制轉換的相關知識,在這之前,我們應該首先了解一下原碼、反碼和補碼。根據我們以前在《計算機組成原理》學到的知識,我們知道對於正數和負數,他們的原碼、反碼、補碼是不一樣的。
一、原碼、反碼、補碼
對於正數而言,原碼、反碼、補碼都是一樣的,其中最高位表示符號位,因為是正數,所以符號位是0,其他位置是該數的數值位
對於負數而言,其原碼的最高位是符號位1,其他位置是數值位;它的反碼是除了符號位以外的其他位置全部按位取反;補碼是在其反碼的基礎上加1;
其中因為對於一個數來說,它的補碼的符號位是可以和數值位一起參與加減乘除運算的,所以在計算機中,存儲一個數的時候,都是以補碼的形式存儲的。
上面反碼、原碼、補碼都是一個數的二進制形式,說完這些,再來說進制轉換。
二、進制轉換
對於二進制、十進制、八進制、十六進制來說,它們之間的相互轉換,其實都是以二進制數作為中間過渡的,比如:
十進制轉換為八進制,先將十進制數轉為二進制形式,然后將二進制從右向左每三位一組合並為一個八進制數,例如10轉為為八進制表示:
十進制:10 二進制:1010 八進制:12
八進制轉換十六進制,同樣也是先轉換為二進制,再轉換為十六進制,其中八進制轉換為二進制的時候,注意由於二進制轉換為八進制的時候,是從右到左每三位一組轉為八進制數,那么八進制轉換為二進制的時候也要使得八進制數從右到左的每一位轉換成三位二進制數。然后二進制轉換為十六進制的時候,就是從右往左每四位一組合並成一個十六進制數。
三、在Java中表示二進制、八進制、十六進制
在Java中表示一個二進制、八進制、十六進制數是有規定的,它們的具體的形式如下:
二進制: 由0和1兩個數字組成;
八進制: 由0-7數字組成,為了區分與其他進制的數字區別,必須以0開頭,比如,十進制的8,用八進制表示是010;
十進制: 都是以0-9這九個數字組成,不能以0開頭;
十六進制:由0-9和A-F組成。為了和其他進制的數字進行區分,開頭都是以0x或0X開始。
四、移位操作
移位操作符操作的運算對象是二進制的“位”,並且只能用來操作整數類型,,移位操作符一共有四種:
1、<< 左移位操作符
value << num value是運算對象,num是要向左進行移位的位數,左移的時候在低位補0。其實左移n 位,就相當於乘以2 的n 次方。
2、>> 有符號右移位操作符
value >> num value是運算對象,num是要向右進行移位的位數,右移動的時候,如果原來符號為正,那么在高位插入0;如果原來符號為負,那么在高位插入1。
3、>>> 無符號右移位操作符
value >>> num value是運算對象,num是要向右進行移位的位數,右移動的時候,無論正負,都在高位插入0;其實右移n 位,就相當於除以2 的n 次方。
練習:力扣405題
題目:給定一個整數,編寫一個算法將這個數轉換為十六進制數。對於負整數,我們通常使用補碼運算方法。
注意:
十六進制中所有字母(a-f)都必須是小寫。
十六進制字符串中不能包含多余的前導零。如果要轉化的數為0,那么以單個字符'0'來表示;對於其他情況,十六進制字符串中的第一個字符將不會是0字符。
給定的數確保在32位有符號整數范圍內。
不能使用任何由庫提供的將數字直接轉換或格式化為十六進制的方法。
分析思路:
十進制數轉換為十六進制數,借助二進制數,從右向左,二進制數每四位合並為十六進制數的一位,所以依次從輸入數的二進制形式右邊每次取出四位數計算出數值作為十六進制數的一位,然后,將二進制數向右進行移動四位,高位要補0,所以采用無符號右移位操作符,直到最終二進制形式的數變為0。
具體實現如下:
public String toHex(int num) { if (num == 0){ return "0"; } char[] c = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; StringBuilder sb = new StringBuilder(); while (num != 0){ sb.append(c[num & 0b1111]); num >>>= 4; } return sb.reverse().toString(); }
注意,對於byte或者short類型的值,最好不要將無符號右移位操作符和等號組合使用。