Skip to content

Commit e5bceac

Browse files
Add two's complement implementation (TheAlgorithms#968)
1 parent 00cbbb9 commit e5bceac

File tree

3 files changed

+147
-7
lines changed

3 files changed

+147
-7
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* [Reverse Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/reverse_bits.rs)
2525
* [Sum of Two Integers](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/sum_of_two_integers.rs)
2626
* [Swap Odd and Even Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/swap_odd_even_bits.rs)
27+
* [Two's Complement](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/twos_complement.rs)
2728
* Ciphers
2829
* [AES](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/aes.rs)
2930
* [Another ROT13](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/another_rot13.rs)

src/bit_manipulation/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ mod n_bits_gray_code;
55
mod reverse_bits;
66
mod sum_of_two_integers;
77
mod swap_odd_even_bits;
8+
mod twos_complement;
89

9-
pub use binary_coded_decimal::binary_coded_decimal;
10-
pub use counting_bits::count_set_bits;
11-
pub use highest_set_bit::find_highest_set_bit;
12-
pub use n_bits_gray_code::generate_gray_code;
13-
pub use reverse_bits::reverse_bits;
14-
pub use sum_of_two_integers::add_two_integers;
15-
pub use swap_odd_even_bits::swap_odd_even_bits;
10+
pub use self::binary_coded_decimal::binary_coded_decimal;
11+
pub use self::counting_bits::count_set_bits;
12+
pub use self::highest_set_bit::find_highest_set_bit;
13+
pub use self::n_bits_gray_code::generate_gray_code;
14+
pub use self::reverse_bits::reverse_bits;
15+
pub use self::sum_of_two_integers::add_two_integers;
16+
pub use self::swap_odd_even_bits::swap_odd_even_bits;
17+
pub use self::twos_complement::twos_complement;
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//! Two's Complement Representation
2+
//!
3+
//! Two's complement is a mathematical operation on binary numbers and a binary signed
4+
//! number representation. It is widely used in computing as the most common method of
5+
//! representing signed integers on computers.
6+
//!
7+
//! For more information: <https://en.wikipedia.org/wiki/Two%27s_complement>
8+
9+
/// Takes a negative integer and returns its two's complement binary representation.
10+
///
11+
/// The two's complement of a negative number is calculated by finding the binary
12+
/// representation that, when added to the positive value with the same magnitude,
13+
/// equals 2^n (where n is the number of bits).
14+
///
15+
/// # Arguments
16+
///
17+
/// * `number` - A non-positive integer (0 or negative)
18+
///
19+
/// # Returns
20+
///
21+
/// A `Result` containing:
22+
/// - `Ok(String)` - The two's complement representation with "0b" prefix
23+
/// - `Err(String)` - An error message if the input is positive
24+
///
25+
/// # Examples
26+
///
27+
/// ```
28+
/// use the_algorithms_rust::bit_manipulation::twos_complement;
29+
///
30+
/// assert_eq!(twos_complement(0).unwrap(), "0b0");
31+
/// assert_eq!(twos_complement(-1).unwrap(), "0b11");
32+
/// assert_eq!(twos_complement(-5).unwrap(), "0b1011");
33+
/// assert_eq!(twos_complement(-17).unwrap(), "0b101111");
34+
/// assert_eq!(twos_complement(-207).unwrap(), "0b100110001");
35+
///
36+
/// // Positive numbers return an error
37+
/// assert!(twos_complement(1).is_err());
38+
/// ```
39+
///
40+
/// # Errors
41+
///
42+
/// Returns an error if the input number is positive.
43+
pub fn twos_complement(number: i32) -> Result<String, String> {
44+
if number > 0 {
45+
return Err("input must be a negative integer".to_string());
46+
}
47+
48+
if number == 0 {
49+
return Ok("0b0".to_string());
50+
}
51+
52+
// Calculate the number of bits needed for the binary representation
53+
// (excluding the sign bit in the original representation)
54+
let binary_number_length = format!("{:b}", number.abs()).len();
55+
56+
// Calculate two's complement value
57+
// This is equivalent to: abs(number) - 2^binary_number_length
58+
let twos_complement_value = (number.abs() as i64) - (1_i64 << binary_number_length);
59+
60+
// Format as binary string (removing the negative sign)
61+
let mut twos_complement_str = format!("{:b}", twos_complement_value.abs());
62+
63+
// Add leading zeros if necessary
64+
let padding_zeros = binary_number_length.saturating_sub(twos_complement_str.len());
65+
if padding_zeros > 0 {
66+
twos_complement_str = format!("{}{twos_complement_str}", "0".repeat(padding_zeros));
67+
}
68+
69+
// Add leading '1' to indicate negative number in two's complement
70+
Ok(format!("0b1{twos_complement_str}"))
71+
}
72+
73+
#[cfg(test)]
74+
mod tests {
75+
use super::*;
76+
77+
#[test]
78+
fn test_zero() {
79+
assert_eq!(twos_complement(0).unwrap(), "0b0");
80+
}
81+
82+
#[test]
83+
fn test_negative_one() {
84+
assert_eq!(twos_complement(-1).unwrap(), "0b11");
85+
}
86+
87+
#[test]
88+
fn test_negative_five() {
89+
assert_eq!(twos_complement(-5).unwrap(), "0b1011");
90+
}
91+
92+
#[test]
93+
fn test_negative_seventeen() {
94+
assert_eq!(twos_complement(-17).unwrap(), "0b101111");
95+
}
96+
97+
#[test]
98+
fn test_negative_two_hundred_seven() {
99+
assert_eq!(twos_complement(-207).unwrap(), "0b100110001");
100+
}
101+
102+
#[test]
103+
fn test_negative_small_values() {
104+
assert_eq!(twos_complement(-2).unwrap(), "0b110");
105+
assert_eq!(twos_complement(-3).unwrap(), "0b101");
106+
assert_eq!(twos_complement(-4).unwrap(), "0b1100");
107+
}
108+
109+
#[test]
110+
fn test_negative_larger_values() {
111+
assert_eq!(twos_complement(-128).unwrap(), "0b110000000");
112+
assert_eq!(twos_complement(-255).unwrap(), "0b100000001");
113+
assert_eq!(twos_complement(-1000).unwrap(), "0b10000011000");
114+
}
115+
116+
#[test]
117+
fn test_positive_number_returns_error() {
118+
let result = twos_complement(1);
119+
assert!(result.is_err());
120+
assert_eq!(result.unwrap_err(), "input must be a negative integer");
121+
}
122+
123+
#[test]
124+
fn test_large_positive_number_returns_error() {
125+
let result = twos_complement(100);
126+
assert!(result.is_err());
127+
assert_eq!(result.unwrap_err(), "input must be a negative integer");
128+
}
129+
130+
#[test]
131+
fn test_edge_case_negative_powers_of_two() {
132+
assert_eq!(twos_complement(-8).unwrap(), "0b11000");
133+
assert_eq!(twos_complement(-16).unwrap(), "0b110000");
134+
assert_eq!(twos_complement(-32).unwrap(), "0b1100000");
135+
assert_eq!(twos_complement(-64).unwrap(), "0b11000000");
136+
}
137+
}

0 commit comments

Comments
 (0)