Repository: TheAlgorithms/Java
Pull request #5862 (2024-10-16 03:30:55)

refactor: Enhance docs, add more tests in `TwosComplement`
<!--
Thank you for your contribution!
In order to reduce the number of notifications sent to the maintainers, please:
- create your PR as draft, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests,
- make sure that all of the CI checks pass,
- mark your PR as ready for review, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#marking-a-pull-request-as-ready-for-review
-->

<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.
- [x] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`

codecov-commenter: ## [Codecov](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5862?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 66.72%. Comparing base [(`2a518e3`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/2a518e3c9a44c4333c5ec9283895132264773afb?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) to head [(`9da255c`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/9da255c2f09f1abaac6aa6d320500d05a4bea520?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##             master    #5862      +/-   ##
============================================
+ Coverage     66.70%   66.72%   +0.01%     
- Complexity     4482     4483       +1     
============================================
  Files           608      608              
  Lines         16913    16912       -1     
  Branches       3264     3263       -1     
============================================
+ Hits          11282    11284       +2     
+ Misses         5182     5181       -1     
+ Partials        449      447       -2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5862?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).


Patch:
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java b/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
index 0bc20072..9b8cecd7 100644
--- a/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
+++ b/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
@@ -1,41 +1,62 @@
 package com.thealgorithms.bitmanipulation;
 
 /**
- * @wikipedia - https://en.wikipedia.org/wiki/Two%27s_complement
- *            This Algorithm was first suggested by Jon Von Neumann
- * @author - https://github.com/Monk-AbhinayVerma
- * @return the two's complement of any binary number
+ * This class provides a method to compute the Two's Complement of a given binary number.
+ *
+ * <p>In two's complement representation, a binary number's negative value is obtained
+ * by taking the one's complement (inverting all bits) and then adding 1 to the result.
+ * This method handles both small and large binary strings and ensures the output is
+ * correct for all binary inputs, including edge cases like all zeroes and all ones.
+ *
+ * <p>For more information on Two's Complement:
+ * @see <a href="https://en.wikipedia.org/wiki/Two%27s_complement">Wikipedia - Two's Complement</a>
+ *
+ * <p>Algorithm originally suggested by Jon von Neumann.
+ *
+ * @author Abhinay Verma (https://github.com/Monk-AbhinayVerma)
  */
 public final class TwosComplement {
     private TwosComplement() {
     }
 
-    // Function to get the 2's complement of a binary number
+    /**
+     * Computes the Two's Complement of the given binary string.
+     * Steps:
+     * 1. Compute the One's Complement (invert all bits).
+     * 2. Add 1 to the One's Complement to get the Two's Complement.
+     * 3. Iterate from the rightmost bit to the left, adding 1 and carrying over as needed.
+     * 4. If a carry is still present after the leftmost bit, prepend '1' to handle overflow.
+     *
+     * @param binary The binary number as a string (only '0' and '1' characters allowed).
+     * @return The two's complement of the input binary string as a new binary string.
+     * @throws IllegalArgumentException If the input contains non-binary characters.
+     */
     public static String twosComplement(String binary) {
+        if (!binary.matches("[01]+")) {
+            throw new IllegalArgumentException("Input must contain only '0' and '1'.");
+        }
+
         StringBuilder onesComplement = new StringBuilder();
-        // Step 1: Find the 1's complement (invert the bits)
-        for (int i = 0; i < binary.length(); i++) {
-            if (binary.charAt(i) == '0') {
-                onesComplement.append('1');
-            } else {
-                onesComplement.append('0');
-            }
+        for (char bit : binary.toCharArray()) {
+            onesComplement.append(bit == '0' ? '1' : '0');
         }
-        // Step 2: Add 1 to the 1's complement
+
         StringBuilder twosComplement = new StringBuilder(onesComplement);
         boolean carry = true;
-        for (int i = onesComplement.length() - 1; i >= 0; i--) {
-            if (onesComplement.charAt(i) == '1' && carry) {
+
+        for (int i = onesComplement.length() - 1; i >= 0 && carry; i--) {
+            if (onesComplement.charAt(i) == '1') {
                 twosComplement.setCharAt(i, '0');
-            } else if (onesComplement.charAt(i) == '0' && carry) {
+            } else {
                 twosComplement.setCharAt(i, '1');
                 carry = false;
             }
         }
-        // If there is still a carry, append '1' at the beginning
+
         if (carry) {
             twosComplement.insert(0, '1');
         }
+
         return twosComplement.toString();
     }
 }


Test patch:
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java b/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java
index 512e94b6..578acc7a 100644
--- a/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java
+++ b/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java
@@ -1,6 +1,7 @@
 package com.thealgorithms.bitmanipulation;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import org.junit.jupiter.api.Test;
 
@@ -12,7 +13,6 @@ public class TwosComplementTest {
 
     @Test
     public void testTwosComplementAllZeroes() {
-        // Test with a binary number consisting entirely of zeroes
         assertEquals("10000", TwosComplement.twosComplement("0000"));
         assertEquals("1000", TwosComplement.twosComplement("000"));
         assertEquals("100", TwosComplement.twosComplement("00"));
@@ -21,7 +21,6 @@ public class TwosComplementTest {
 
     @Test
     public void testTwosComplementAllOnes() {
-        // Test with a binary number consisting entirely of ones
         assertEquals("00001", TwosComplement.twosComplement("11111"));
         assertEquals("0001", TwosComplement.twosComplement("1111"));
         assertEquals("001", TwosComplement.twosComplement("111"));
@@ -30,25 +29,36 @@ public class TwosComplementTest {
 
     @Test
     public void testTwosComplementMixedBits() {
-        // Test with binary numbers with mixed bits
-        assertEquals("1111", TwosComplement.twosComplement("0001")); // 1's complement: 1110, then add 1: 1111
-        assertEquals("1001", TwosComplement.twosComplement("0111")); // 1's complement: 1000
-        assertEquals("11001", TwosComplement.twosComplement("00111")); // 1's complement: 11000, add 1: 11001
-        assertEquals("011", TwosComplement.twosComplement("101")); // 1's complement: 010, add 1: 011
+        assertEquals("1111", TwosComplement.twosComplement("0001")); // 1 -> 1111
+        assertEquals("1001", TwosComplement.twosComplement("0111")); // 0111 -> 1001
+        assertEquals("11001", TwosComplement.twosComplement("00111")); // 00111 -> 11001
+        assertEquals("011", TwosComplement.twosComplement("101")); // 101 -> 011
     }
 
     @Test
     public void testTwosComplementSingleBit() {
-        // Test with single bit
-        assertEquals("10", TwosComplement.twosComplement("0"));
-        assertEquals("1", TwosComplement.twosComplement("1"));
+        assertEquals("10", TwosComplement.twosComplement("0")); // 0 -> 10
+        assertEquals("1", TwosComplement.twosComplement("1")); // 1 -> 1
     }
 
     @Test
     public void testTwosComplementWithLeadingZeroes() {
-        // Test with leading zeroes in the input
-        assertEquals("1111", TwosComplement.twosComplement("0001"));
-        assertEquals("101", TwosComplement.twosComplement("011"));
-        assertEquals("110", TwosComplement.twosComplement("010"));
+        assertEquals("1111", TwosComplement.twosComplement("0001")); // 0001 -> 1111
+        assertEquals("101", TwosComplement.twosComplement("011")); // 011 -> 101
+        assertEquals("110", TwosComplement.twosComplement("010")); // 010 -> 110
+    }
+
+    @Test
+    public void testInvalidBinaryInput() {
+        // Test for invalid input that contains non-binary characters.
+        assertThrows(IllegalArgumentException.class, () -> TwosComplement.twosComplement("102"));
+        assertThrows(IllegalArgumentException.class, () -> TwosComplement.twosComplement("abc"));
+        assertThrows(IllegalArgumentException.class, () -> TwosComplement.twosComplement("10a01"));
+    }
+
+    @Test
+    public void testEmptyInput() {
+        // Edge case: Empty input should result in an IllegalArgumentException.
+        assertThrows(IllegalArgumentException.class, () -> TwosComplement.twosComplement(""));
     }
 }