From 9da255c2f09f1abaac6aa6d320500d05a4bea520 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Wed, 16 Oct 2024 09:00:39 +0530 Subject: [PATCH] refactor: Enhance docs, add more tests in `TwosComplement` --- .../bitmanipulation/TwosComplement.java | 55 +++++++++++++------ .../bitmanipulation/TwosComplementTest.java | 38 ++++++++----- 2 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java b/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java index 0bc200722943..9b8cecd791a6 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. + * + *

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. + * + *

For more information on Two's Complement: + * @see Wikipedia - Two's Complement + * + *

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(); } } diff --git a/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java b/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java index 512e94b6374e..578acc7af18c 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 void testTwosComplementAllZeroes() { @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 void testTwosComplementAllOnes() { @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("")); } }