RedEnginePress logo
RedEnginePress
AlgorithmsLanguagesPlaygroundAbout

Binary to Gray Code

p
"""
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}")