計算一個數的補數
一、簡介
補碼是一種透過反轉數字的所有位元來以二進位形式表示負數的方法。它通常在網路協定中用於錯誤檢測和校驗和計算。在本教程中,我們將學習如何在 Java 中計算數字的補碼。
2. 使用位元非運算
我們可以透過對數字執行位元 NOT 運算來計算該數字的補碼。按位 NOT 運算翻轉數字的二進位表示形式中的所有位,有效地將 0 變更為 1,將 1 變更為 0。
以下是使用位元 NOT 運算來計算數字的補碼的範例程式碼片段:
int calculateOnesComplementUsingBitwiseNot(int num) {
return ~num;
}
我們來驗證一下使用位元 NOT 運算的結果:
int onesComplement = calculateOnesComplementUsingBitwiseNot(10);
assertEquals(-11, onesComplement);
assertEquals("11111111111111111111111111110101", Integer.toBinaryString(onesComplement));
數字10用二進位表示為“00000000 00000000 00000000 00001010”。以位元非運算子 ( ~ ) 反轉二進位表示中的每一位。翻轉後,二進位變為「 11111111 11111111 11111111 11110101 」。
Java 使用有符號整數的補碼來解釋這種二進位表示法。在二進位補碼中,最左邊的位元表示符號(0 表示正,1 表示負)。由於最左邊的位現在為 1,因此該數字被解釋為負數。因此實際值為-11。
值得注意的是,負數的補碼是正數,反之亦然。這是因為位元 NOT 運算會翻轉數字的二進位表示形式中的所有位,包括符號位。
對於負數-10,其補碼為9 :
int onesComplement = calculateOnesComplementUsingBitwiseNot(-10);
assertEquals(9, onesComplement);
assertEquals("1001", Integer.toBinaryString(onesComplement));
-10的二進位補碼形式的二進位表示為「11111111 11111111 11111111 11110110」。當我們套用位元非運算子時,它會翻轉該二進位數的所有位元。翻轉「11111111 11111111 11111111 11110110」的位會得到「00000000 00000000 00000000 00001001」。將此二進制數轉換為十進制數得到9 。
因此,當使用位元 NOT 運算計算數字的補碼時,考慮數字的符號和所得補碼的符號非常重要。
3.使用BigInteger類
對於非常大的數字,使用int資料類型可能不夠。在這種情況下,我們可以利用BigInteger類別。 BigInteger的not()方法執行位元 NOT 運算,提供反碼。
這是使用BigInteger.not()的程式碼片段:
BigInteger calculateOnesComplementUsingBigIntegerNot(BigInteger num) {
return num.not();
}
讓我們測試一下這個實作:
BigInteger onesComplement = calculateOnesComplementUsingBigInteger(BigInteger.valueOf(10));
assertEquals(BigInteger.valueOf(-11), onesComplement);
assertEquals("11111111111111111111111111110101", Integer.toBinaryString(onesComplement.intValue()));
4. 對全 1 使用異或
或者,我們可以使用全1遮罩的位元異或 (^) 運算。當我們想要明確控制位長度時,此方法特別有用:
int calculateOnesComplementUsingXOROperator(int num, int bitLength) {
int mask = (1 << bitLength) - 1;
return num ^ mask;
}
在此範例中,我們首先確定位元長度並使用(1 << bitLength) – 1將該位元長度屏蔽為全 1。這可以透過將1左移 ( <<)所需的位數來實現。然後我們對正數減1 ,以確保最左邊的位(符號位)為 0。
接下來,我們在輸入數字和遮罩 1 之間執行位元異或運算。這會翻轉輸入數字中的所有位,從而得到補碼。
例如,對於8位元表示的數字10 ,遮罩為11111111 (二進位為 255)。將0000 1010與11111111進行異或,得到11110101 ,得到245 :
int onesComplement = calculateOnesComplementUsingXOROperator(10, 8);
assertEquals(245, onesComplement);
assertEquals("11110101", Integer.toBinaryString(onesComplement));
當使用 XOR 作為補碼時,它會翻轉所有位,包括正數的符號位。在二進制補碼中,翻轉的符號位元將解釋從正變為負。然而,值部分 ( 11110101 ) 確實是10的補碼。
對於負數,我們可以先將它們轉換為對應的正值,以確保在應用位元異或之前保持位元長度:
int calculateOnesComplementUsingXOROperator(int num, int bitLength) {
int mask = (1 << bitLength) - 1;
// To handle negative value
int extendedNum = num < 0 ? (1 << bitLength) + num : num;
return extendedNum ^ mask;
}
讓我們檢查一下數字-10的補碼的輸出:
int onesComplement = calculateOnesComplementUsingXOROperator(-10, 8);
assertEquals(9, onesComplement);
assertEquals("1001", Integer.toBinaryString(onesComplement));
5. 結論
在本文中,我們了解了補碼以及如何使用三種方法在 Java 中計算補碼。
位元 NOT 運算子更有效率、更簡單,使我們能夠透過一次操作來計算補碼。此外,我們可以將 XOR 運算子與遮罩一起使用,從而可以精確控制位元長度。
與往常一樣,範例的原始程式碼可在 GitHub 上取得。