Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 9 additions & 7 deletions src/bit_manipulation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
137 changes: 137 additions & 0 deletions src/bit_manipulation/twos_complement.rs
Original file line number Diff line number Diff line change
@@ -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: <https://en.wikipedia.org/wiki/Two%27s_complement>

/// 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<String, String> {
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");
}
}