diff --git a/conversions/binary_to_gray_code.py b/conversions/binary_to_gray_code.py new file mode 100644 index 000000000000..494cad66f503 --- /dev/null +++ b/conversions/binary_to_gray_code.py @@ -0,0 +1,224 @@ +""" +Convert between Binary and Gray Code representations. + +Gray Code (also known as reflected binary code) is a binary numeral system where +two successive values differ in only one bit. This property makes it useful in +error correction, digital communications, and position encoders. + +Wikipedia: https://en.wikipedia.org/wiki/Gray_code +""" + + +def binary_to_gray(binary_number: int) -> int: + """ + Convert a binary number to its Gray Code equivalent. + + The algorithm works by XORing the binary number with itself right-shifted by 1. + Formula: gray = binary XOR (binary >> 1) + + Args: + binary_number: A positive integer representing a binary number + + Returns: + The Gray Code equivalent as an integer + + Examples: + >>> binary_to_gray(0) + 0 + >>> binary_to_gray(1) + 1 + >>> binary_to_gray(2) + 3 + >>> binary_to_gray(3) + 2 + >>> binary_to_gray(4) + 6 + >>> binary_to_gray(7) + 4 + >>> binary_to_gray(10) + 15 + >>> binary_to_gray(15) + 8 + >>> binary_to_gray(255) + 128 + >>> binary_to_gray(-1) + Traceback (most recent call last): + ... + ValueError: Input must be a non-negative integer + >>> binary_to_gray(3.5) + Traceback (most recent call last): + ... + TypeError: Input must be an integer + """ + if not isinstance(binary_number, int): + raise TypeError("Input must be an integer") + if binary_number < 0: + raise ValueError("Input must be a non-negative integer") + + return binary_number ^ (binary_number >> 1) + + +def gray_to_binary(gray_number: int) -> int: + """ + Convert a Gray Code number to its binary equivalent. + + The algorithm works by repeatedly XORing the gray code with itself right-shifted, + until the right-shifted value becomes 0. + + Args: + gray_number: A positive integer representing a Gray Code number + + Returns: + The binary equivalent as an integer + + Examples: + >>> gray_to_binary(0) + 0 + >>> gray_to_binary(1) + 1 + >>> gray_to_binary(3) + 2 + >>> gray_to_binary(2) + 3 + >>> gray_to_binary(6) + 4 + >>> gray_to_binary(4) + 7 + >>> gray_to_binary(15) + 10 + >>> gray_to_binary(8) + 15 + >>> gray_to_binary(128) + 255 + >>> gray_to_binary(-1) + Traceback (most recent call last): + ... + ValueError: Input must be a non-negative integer + >>> gray_to_binary(5.5) + Traceback (most recent call last): + ... + TypeError: Input must be an integer + """ + if not isinstance(gray_number, int): + raise TypeError("Input must be an integer") + if gray_number < 0: + raise ValueError("Input must be a non-negative integer") + + binary_number = gray_number + gray_number >>= 1 + + while gray_number: + binary_number ^= gray_number + gray_number >>= 1 + + return binary_number + + +def decimal_to_gray(decimal_number: int) -> str: + """ + Convert a decimal number to its Gray Code representation as a binary string. + + Args: + decimal_number: A positive integer in decimal + + Returns: + Gray Code representation as a binary string + + Examples: + >>> decimal_to_gray(0) + '0' + >>> decimal_to_gray(1) + '1' + >>> decimal_to_gray(2) + '11' + >>> decimal_to_gray(3) + '10' + >>> decimal_to_gray(4) + '110' + >>> decimal_to_gray(10) + '1111' + >>> decimal_to_gray(15) + '1000' + >>> decimal_to_gray(-1) + Traceback (most recent call last): + ... + ValueError: Input must be a non-negative integer + """ + if not isinstance(decimal_number, int): + raise TypeError("Input must be an integer") + if decimal_number < 0: + raise ValueError("Input must be a non-negative integer") + + gray_code = binary_to_gray(decimal_number) + return bin(gray_code)[2:] # Remove '0b' prefix + + +def gray_to_decimal(gray_string: str) -> int: + """ + Convert a Gray Code binary string to its decimal equivalent. + + Args: + gray_string: A string of 0s and 1s representing Gray Code + + Returns: + The decimal equivalent as an integer + + Examples: + >>> gray_to_decimal('0') + 0 + >>> gray_to_decimal('1') + 1 + >>> gray_to_decimal('11') + 2 + >>> gray_to_decimal('10') + 3 + >>> gray_to_decimal('110') + 4 + >>> gray_to_decimal('1111') + 10 + >>> gray_to_decimal('1000') + 15 + >>> gray_to_decimal('invalid') + Traceback (most recent call last): + ... + ValueError: Invalid binary string + >>> gray_to_decimal('') + Traceback (most recent call last): + ... + ValueError: Input string cannot be empty + """ + if not gray_string: + raise ValueError("Input string cannot be empty") + + # Validate binary string + if not all(bit in "01" for bit in gray_string): + raise ValueError("Invalid binary string") + + gray_number = int(gray_string, 2) + return gray_to_binary(gray_number) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + # Interactive demonstration + print("=== Binary to Gray Code Converter ===\n") + + # Demonstrate conversions for 0-15 + print("Decimal | Binary | Gray Code") + print("--------|----------|----------") + for i in range(16): + binary = bin(i)[2:].zfill(4) + gray = decimal_to_gray(i).zfill(4) + print(f"{i:7} | {binary:8} | {gray:9}") + + print("\n=== Verification: Gray to Binary ===\n") + print("Gray Code | Binary | Decimal") + print("----------|----------|--------") + for i in range(16): + gray = decimal_to_gray(i).zfill(4) + decimal = gray_to_decimal(gray) + binary = bin(decimal)[2:].zfill(4) + print(f"{gray:9} | {binary:8} | {decimal:7}")