在 Java 中將正整數轉換為負整數,反之亦然
1. 概述
在 Java 程式設計中,了解如何操作整數是編寫健全且有效率的程式碼的基礎。常見的操作是對整數求負。
在本教程中,我們將探索對整數求反的不同方法。
2.問題介紹
對整數求負涉及將其符號從正變為負,反之亦然。例如,給定一個int 42,對其求反後,我們預期會得到 -42 作為結果。
我們不應該忘記數字 0 既不是正數也不是負數。因此,對 0 求反的結果也應該是 0。
在 Java 中,此操作很簡單,我們將看到三種不同的方法來實作它。此外,我們將討論一個極端情況:整數溢位。
為簡單起見,我們將使用單元測試斷言來驗證每種方法的結果。
3. 使用一元減運算符
對整數求反的最直接方法是使用一元減運算子 ( – )。它只是改變給定整數的符號:
int x = 42;
assertEquals(-42, -x);
int z = 0;
assertEquals(0, -z);
int n = -42;
assertEquals(42, -n);
如測試所示,我們透過將“ – ”應用於輸入整數來獲得預期結果。
4. 使用位元補碼運算符
另一種非常規但有效的對整數求反的方法是使用位元補運算子 ( ~ )。此運算子反轉給定整數的位,有效地建立二進位補碼:
int number = 12;
int negative13 = ~number; // ~00001100 = 11110011 = -13
因此,給定一個整數x , ~x + 1 是x的負數。
接下來,讓我們寫一個測試來驗證:
int x = 42;
assertEquals(-42, ~x + 1);
int z = 0;
assertEquals(0, ~z + 1);
int n = -42;
assertEquals(42, ~n + 1);
正如我們所見, ~x + 1解決了問題。
5. Integer.MIN_VALUE的溢出問題
我們知道Java的整數類型是有符號的32位元類型,範圍從-2147483648到2147483647.如果我們對Integer.MAX_VALUE,結果2147483647仍然在這個範圍內。但是,如果我們否定Integer.MIN_VALUE,我們應該得到2147483648, 它大於Integer.MAX_VALUE 。因此,在這種邊緣情況下,會發生溢出錯誤。
儘管「 -x 」和「 ~x + 1 」方法很簡單,但只有在確保不會發生溢出的情況下,我們才能在應用程式中使用它們。可能適合使用它們的一些示例場景包括:
- 計算足球隊在錦標賽中的淨勝球數
- 計算員工一個月的工作時間
但是,如果我們的程式中可能發生溢出,則不鼓勵使用這些方法。
接下來,讓我們來探討為什麼這兩種方法在使用Integer.MIN_VALUE作為輸入時會導致溢出錯誤。
5.1. -x使用Integer.MIN_VALUE
首先,我們使用「 – 」運算子對Integer.MIN_VALUE求反:
int min = Integer.MIN_VALUE;
LOG.info("The value of '-min' is: " + -min);
assertTrue((-min) < 0);
測試通過了,這表示在否定Integer.MIN_VALUE後我們仍然得到負結果。我們可以從輸出中進一步驗證這一點:
The value of '-min' is: -2147483648
因此,當發生溢出時, '-x'方法會傳回錯誤的結果。
5.2. ~x + 1使用Integer.MIN_VALUE
讓我們使用“ ~x + 1′方法運行相同的測試:
int min = Integer.MIN_VALUE;
int result = ~min + 1;
LOG.info("The value of '~min + 1' is: " + result);
assertFalse(result > 0);
我們可以看到,當發生溢出時,這種方法也不會給出預期的結果。讓我們透過檢查控制台中的日誌輸出來進一步驗證這一點:
The value of '~min + 1' is: -2147483648
6. 使用Math.negateExact()方法
對於需要處理Integer.MIN_VALUE的場景, Math.negateExact()方法提供了一種安全且精確的方法來對整數取反。
首先, Math.negateExact()在正常情況下如預期般運作:
int x = 42;
assertEquals(-42, Math.negateExact(x));
int z = 0;
assertEquals(0, Math.negateExact(z));
int n = -42;
assertEquals(42, Math.negateExact(n));
接下來,讓我們看看如果輸入是Integer.MIN_VALUE會出現什麼結果:
int min = Integer.MIN_VALUE;
assertThrowsExactly(ArithmeticException.class, () -> Math.negateExact(min));
如測試所示,如果求反期間發生溢出, Math.negateExact()方法將引發ArithmeticException ,從而允許開發人員在發生錯誤時進行處理。
七、結論
在本文中,我們探討了在 Java 中對整數求反的三種方法。
「 -x 」和「 ~x + 1 」是簡單的解決方案。但是,如果我們的程式可能嘗試對Integer.MIN_VALUE,那麼使用Math.negateExact()是正確的選擇。
與往常一樣,範例的完整原始程式碼可在 GitHub 上取得。