diff --git a/DIRECTORY.md b/DIRECTORY.md index a11d2108775..d8d527a02e3 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -24,6 +24,7 @@ * [Reverse Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/reverse_bits.rs) * [Sum of Two Integers](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/sum_of_two_integers.rs) * [Swap Odd and Even Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/swap_odd_even_bits.rs) + * [Two's Complement](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/twos_complement.rs) * Ciphers * [AES](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/aes.rs) * [Another ROT13](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/another_rot13.rs) diff --git a/src/bit_manipulation/mod.rs b/src/bit_manipulation/mod.rs index f00bee29bdd..d2405375483 100644 --- a/src/bit_manipulation/mod.rs +++ b/src/bit_manipulation/mod.rs @@ -5,11 +5,13 @@ mod n_bits_gray_code; mod reverse_bits; mod sum_of_two_integers; mod swap_odd_even_bits; +mod twos_complement; -pub use binary_coded_decimal::binary_coded_decimal; -pub use counting_bits::count_set_bits; -pub use highest_set_bit::find_highest_set_bit; -pub use n_bits_gray_code::generate_gray_code; -pub use reverse_bits::reverse_bits; -pub use sum_of_two_integers::add_two_integers; -pub use swap_odd_even_bits::swap_odd_even_bits; +pub use self::binary_coded_decimal::binary_coded_decimal; +pub use self::counting_bits::count_set_bits; +pub use self::highest_set_bit::find_highest_set_bit; +pub use self::n_bits_gray_code::generate_gray_code; +pub use self::reverse_bits::reverse_bits; +pub use self::sum_of_two_integers::add_two_integers; +pub use self::swap_odd_even_bits::swap_odd_even_bits; +pub use self::twos_complement::twos_complement; diff --git a/src/bit_manipulation/twos_complement.rs b/src/bit_manipulation/twos_complement.rs new file mode 100644 index 00000000000..14a85996728 --- /dev/null +++ b/src/bit_manipulation/twos_complement.rs @@ -0,0 +1,137 @@ +//! Two's Complement Representation +//! +//! Two's complement is a mathematical operation on binary numbers and a binary signed +//! number representation. It is widely used in computing as the most common method of +//! representing signed integers on computers. +//! +//! For more information: + +/// Takes a negative integer and returns its two's complement binary representation. +/// +/// The two's complement of a negative number is calculated by finding the binary +/// representation that, when added to the positive value with the same magnitude, +/// equals 2^n (where n is the number of bits). +/// +/// # Arguments +/// +/// * `number` - A non-positive integer (0 or negative) +/// +/// # Returns +/// +/// A `Result` containing: +/// - `Ok(String)` - The two's complement representation with "0b" prefix +/// - `Err(String)` - An error message if the input is positive +/// +/// # Examples +/// +/// ``` +/// use the_algorithms_rust::bit_manipulation::twos_complement; +/// +/// assert_eq!(twos_complement(0).unwrap(), "0b0"); +/// assert_eq!(twos_complement(-1).unwrap(), "0b11"); +/// assert_eq!(twos_complement(-5).unwrap(), "0b1011"); +/// assert_eq!(twos_complement(-17).unwrap(), "0b101111"); +/// assert_eq!(twos_complement(-207).unwrap(), "0b100110001"); +/// +/// // Positive numbers return an error +/// assert!(twos_complement(1).is_err()); +/// ``` +/// +/// # Errors +/// +/// Returns an error if the input number is positive. +pub fn twos_complement(number: i32) -> Result { + if number > 0 { + return Err("input must be a negative integer".to_string()); + } + + if number == 0 { + return Ok("0b0".to_string()); + } + + // Calculate the number of bits needed for the binary representation + // (excluding the sign bit in the original representation) + let binary_number_length = format!("{:b}", number.abs()).len(); + + // Calculate two's complement value + // This is equivalent to: abs(number) - 2^binary_number_length + let twos_complement_value = (number.abs() as i64) - (1_i64 << binary_number_length); + + // Format as binary string (removing the negative sign) + let mut twos_complement_str = format!("{:b}", twos_complement_value.abs()); + + // Add leading zeros if necessary + let padding_zeros = binary_number_length.saturating_sub(twos_complement_str.len()); + if padding_zeros > 0 { + twos_complement_str = format!("{}{twos_complement_str}", "0".repeat(padding_zeros)); + } + + // Add leading '1' to indicate negative number in two's complement + Ok(format!("0b1{twos_complement_str}")) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_zero() { + assert_eq!(twos_complement(0).unwrap(), "0b0"); + } + + #[test] + fn test_negative_one() { + assert_eq!(twos_complement(-1).unwrap(), "0b11"); + } + + #[test] + fn test_negative_five() { + assert_eq!(twos_complement(-5).unwrap(), "0b1011"); + } + + #[test] + fn test_negative_seventeen() { + assert_eq!(twos_complement(-17).unwrap(), "0b101111"); + } + + #[test] + fn test_negative_two_hundred_seven() { + assert_eq!(twos_complement(-207).unwrap(), "0b100110001"); + } + + #[test] + fn test_negative_small_values() { + assert_eq!(twos_complement(-2).unwrap(), "0b110"); + assert_eq!(twos_complement(-3).unwrap(), "0b101"); + assert_eq!(twos_complement(-4).unwrap(), "0b1100"); + } + + #[test] + fn test_negative_larger_values() { + assert_eq!(twos_complement(-128).unwrap(), "0b110000000"); + assert_eq!(twos_complement(-255).unwrap(), "0b100000001"); + assert_eq!(twos_complement(-1000).unwrap(), "0b10000011000"); + } + + #[test] + fn test_positive_number_returns_error() { + let result = twos_complement(1); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "input must be a negative integer"); + } + + #[test] + fn test_large_positive_number_returns_error() { + let result = twos_complement(100); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "input must be a negative integer"); + } + + #[test] + fn test_edge_case_negative_powers_of_two() { + assert_eq!(twos_complement(-8).unwrap(), "0b11000"); + assert_eq!(twos_complement(-16).unwrap(), "0b110000"); + assert_eq!(twos_complement(-32).unwrap(), "0b1100000"); + assert_eq!(twos_complement(-64).unwrap(), "0b11000000"); + } +}