From 4ff76c7c68d29dc015f98b40f8c32efda6729028 Mon Sep 17 00:00:00 2001 From: Ali Alimohammadi Date: Wed, 17 Dec 2025 13:30:26 -0800 Subject: [PATCH 1/3] feat: add binary count trailing zeros algorithm --- DIRECTORY.md | 1 + .../binary_count_trailing_zeros.rs | 162 ++++++++++++++++++ src/bit_manipulation/mod.rs | 2 + 3 files changed, 165 insertions(+) create mode 100644 src/bit_manipulation/binary_count_trailing_zeros.rs diff --git a/DIRECTORY.md b/DIRECTORY.md index 934db9477b6..1c08021c544 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -26,6 +26,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) + * [Trailing Zeros](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/binary_count_trailing_zeros.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) diff --git a/src/bit_manipulation/binary_count_trailing_zeros.rs b/src/bit_manipulation/binary_count_trailing_zeros.rs new file mode 100644 index 00000000000..268dc3dfe01 --- /dev/null +++ b/src/bit_manipulation/binary_count_trailing_zeros.rs @@ -0,0 +1,162 @@ +/// Counts the number of trailing zeros in the binary representation of a number +/// +/// Takes an unsigned integer and returns the count of trailing zeros (consecutive +/// zeros from the least significant bit) in its binary representation. +/// +/// # Arguments +/// +/// * `num` - The input number (unsigned integer) +/// +/// # Returns +/// +/// The number of trailing zeros in the binary representation +/// +/// # Examples +/// +/// ``` +/// use the_algorithms_rust::bit_manipulation::binary_count_trailing_zeros; +/// +/// assert_eq!(binary_count_trailing_zeros(25), 0); // 11001 -> 0 trailing zeros +/// assert_eq!(binary_count_trailing_zeros(36), 2); // 100100 -> 2 trailing zeros +/// assert_eq!(binary_count_trailing_zeros(16), 4); // 10000 -> 4 trailing zeros +/// assert_eq!(binary_count_trailing_zeros(58), 1); // 111010 -> 1 trailing zero +/// assert_eq!(binary_count_trailing_zeros(4294967296), 32); +/// assert_eq!(binary_count_trailing_zeros(0), 0); +/// ``` +/// +/// # Algorithm Explanation +/// +/// This function uses Rust's built-in `trailing_zeros()` method, which efficiently +/// counts trailing zeros using CPU instructions. The method works by: +/// 1. Examining the binary representation from right to left +/// 2. Counting consecutive zeros until hitting the first 1 bit +/// 3. Returning the count +/// +/// Alternative implementation using bit manipulation: +/// The count can also be computed using: `log2(num & -num)` +/// - `num & -num` isolates the rightmost set bit +/// - Taking log2 gives the position of that bit (= trailing zeros count) +pub fn binary_count_trailing_zeros(num: u64) -> u32 { + // Handle zero case explicitly to match Python behavior + if num == 0 { + return 0; + } + + // Rust's built-in method for counting trailing zeros + // Note: trailing_zeros() on 0 returns the bit width (64 for u64) + // but we handle zero separately above + num.trailing_zeros() +} + +/// Alternative implementation using bit manipulation and logarithm +/// +/// This matches the Python implementation more closely by using the +/// bit manipulation trick: log2(num & -num) +/// +/// # Examples +/// +/// ``` +/// # use the_algorithms_rust::bit_manipulation::binary_count_trailing_zeros; +/// // Note: This is an internal alternative implementation +/// // For actual use, call binary_count_trailing_zeros() instead +/// assert_eq!(binary_count_trailing_zeros(25), 0); +/// assert_eq!(binary_count_trailing_zeros(36), 2); +/// assert_eq!(binary_count_trailing_zeros(16), 4); +/// ``` +#[allow(dead_code)] +pub fn binary_count_trailing_zeros_bitwise(num: u64) -> u32 { + if num == 0 { + return 0; + } + + // The bit manipulation trick: num & -num isolates the rightmost set bit + // Taking log2 gives us the position (number of trailing zeros) + let rightmost_set_bit = num & (num.wrapping_neg()); + + // Calculate log2 using leading zeros + // log2(x) = 63 - leading_zeros(x) for u64 + 63 - rightmost_set_bit.leading_zeros() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_basic_cases() { + assert_eq!(binary_count_trailing_zeros(25), 0); // 11001 + assert_eq!(binary_count_trailing_zeros(36), 2); // 100100 + assert_eq!(binary_count_trailing_zeros(16), 4); // 10000 + assert_eq!(binary_count_trailing_zeros(58), 1); // 111010 + } + + #[test] + fn test_large_number() { + assert_eq!(binary_count_trailing_zeros(4294967296), 32); + } + + #[test] + fn test_zero() { + assert_eq!(binary_count_trailing_zeros(0), 0); + } + + #[test] + fn test_powers_of_two() { + // Powers of 2 have trailing zeros equal to their exponent + assert_eq!(binary_count_trailing_zeros(1), 0); // 2^0 + assert_eq!(binary_count_trailing_zeros(2), 1); // 2^1 + assert_eq!(binary_count_trailing_zeros(4), 2); // 2^2 + assert_eq!(binary_count_trailing_zeros(8), 3); // 2^3 + assert_eq!(binary_count_trailing_zeros(1024), 10); // 2^10 + } + + #[test] + fn test_odd_numbers() { + // Odd numbers always have 0 trailing zeros + assert_eq!(binary_count_trailing_zeros(1), 0); + assert_eq!(binary_count_trailing_zeros(3), 0); + assert_eq!(binary_count_trailing_zeros(5), 0); + assert_eq!(binary_count_trailing_zeros(7), 0); + assert_eq!(binary_count_trailing_zeros(99), 0); + } + + #[test] + fn test_even_numbers() { + assert_eq!(binary_count_trailing_zeros(2), 1); // 10 + assert_eq!(binary_count_trailing_zeros(4), 2); // 100 + assert_eq!(binary_count_trailing_zeros(6), 1); // 110 + assert_eq!(binary_count_trailing_zeros(8), 3); // 1000 + assert_eq!(binary_count_trailing_zeros(12), 2); // 1100 + } + + #[test] + fn test_bitwise_implementation() { + // Test that both implementations give the same results + let test_cases = vec![0, 1, 2, 4, 8, 16, 25, 36, 58, 1024, 4294967296]; + + for num in test_cases { + assert_eq!( + binary_count_trailing_zeros(num), + binary_count_trailing_zeros_bitwise(num), + "Mismatch for input: {}", + num + ); + } + } + + #[test] + fn test_max_value() { + // Test with maximum u64 value + let max_u64 = u64::MAX; + assert_eq!(binary_count_trailing_zeros(max_u64), 0); // All 1s, no trailing zeros + } + + #[test] + fn test_patterns() { + // Test specific binary patterns + assert_eq!(binary_count_trailing_zeros(0b1000), 3); + assert_eq!(binary_count_trailing_zeros(0b10000), 4); + assert_eq!(binary_count_trailing_zeros(0b100000), 5); + assert_eq!(binary_count_trailing_zeros(0b1111000), 3); + } +} diff --git a/src/bit_manipulation/mod.rs b/src/bit_manipulation/mod.rs index 95bbb755123..606dc81e89e 100644 --- a/src/bit_manipulation/mod.rs +++ b/src/bit_manipulation/mod.rs @@ -1,4 +1,5 @@ mod binary_coded_decimal; +mod binary_count_trailing_zeros; mod counting_bits; mod find_previous_power_of_two; mod highest_set_bit; @@ -10,6 +11,7 @@ mod swap_odd_even_bits; mod twos_complement; pub use self::binary_coded_decimal::binary_coded_decimal; +pub use self::binary_count_trailing_zeros::binary_count_trailing_zeros; pub use self::counting_bits::count_set_bits; pub use self::find_previous_power_of_two::find_previous_power_of_two; pub use self::highest_set_bit::find_highest_set_bit; From c0259d976b0ee5f49e3da0770bb24271b506e0d0 Mon Sep 17 00:00:00 2001 From: Ali Alimohammadi <41567902+AliAlimohammadi@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:38:45 -0800 Subject: [PATCH 2/3] Update binary_count_trailing_zeros.rs --- .../binary_count_trailing_zeros.rs | 117 ++++-------------- 1 file changed, 21 insertions(+), 96 deletions(-) diff --git a/src/bit_manipulation/binary_count_trailing_zeros.rs b/src/bit_manipulation/binary_count_trailing_zeros.rs index 268dc3dfe01..9e6bb5bc297 100644 --- a/src/bit_manipulation/binary_count_trailing_zeros.rs +++ b/src/bit_manipulation/binary_count_trailing_zeros.rs @@ -1,11 +1,8 @@ /// Counts the number of trailing zeros in the binary representation of a number /// -/// Takes an unsigned integer and returns the count of trailing zeros (consecutive -/// zeros from the least significant bit) in its binary representation. -/// /// # Arguments /// -/// * `num` - The input number (unsigned integer) +/// * `num` - The input number /// /// # Returns /// @@ -16,65 +13,35 @@ /// ``` /// use the_algorithms_rust::bit_manipulation::binary_count_trailing_zeros; /// -/// assert_eq!(binary_count_trailing_zeros(25), 0); // 11001 -> 0 trailing zeros -/// assert_eq!(binary_count_trailing_zeros(36), 2); // 100100 -> 2 trailing zeros -/// assert_eq!(binary_count_trailing_zeros(16), 4); // 10000 -> 4 trailing zeros -/// assert_eq!(binary_count_trailing_zeros(58), 1); // 111010 -> 1 trailing zero -/// assert_eq!(binary_count_trailing_zeros(4294967296), 32); -/// assert_eq!(binary_count_trailing_zeros(0), 0); +/// assert_eq!(binary_count_trailing_zeros(25), 0); +/// assert_eq!(binary_count_trailing_zeros(36), 2); +/// assert_eq!(binary_count_trailing_zeros(16), 4); +/// assert_eq!(binary_count_trailing_zeros(58), 1); /// ``` -/// -/// # Algorithm Explanation -/// -/// This function uses Rust's built-in `trailing_zeros()` method, which efficiently -/// counts trailing zeros using CPU instructions. The method works by: -/// 1. Examining the binary representation from right to left -/// 2. Counting consecutive zeros until hitting the first 1 bit -/// 3. Returning the count -/// -/// Alternative implementation using bit manipulation: -/// The count can also be computed using: `log2(num & -num)` -/// - `num & -num` isolates the rightmost set bit -/// - Taking log2 gives the position of that bit (= trailing zeros count) pub fn binary_count_trailing_zeros(num: u64) -> u32 { - // Handle zero case explicitly to match Python behavior if num == 0 { return 0; } - - // Rust's built-in method for counting trailing zeros - // Note: trailing_zeros() on 0 returns the bit width (64 for u64) - // but we handle zero separately above num.trailing_zeros() } -/// Alternative implementation using bit manipulation and logarithm +/// Alternative implementation using bit manipulation /// -/// This matches the Python implementation more closely by using the -/// bit manipulation trick: log2(num & -num) +/// Uses the bit manipulation trick: log2(num & -num) /// /// # Examples /// /// ``` -/// # use the_algorithms_rust::bit_manipulation::binary_count_trailing_zeros; -/// // Note: This is an internal alternative implementation -/// // For actual use, call binary_count_trailing_zeros() instead -/// assert_eq!(binary_count_trailing_zeros(25), 0); -/// assert_eq!(binary_count_trailing_zeros(36), 2); -/// assert_eq!(binary_count_trailing_zeros(16), 4); +/// # use the_algorithms_rust::bit_manipulation::binary_count_trailing_zeros_bitwise; +/// assert_eq!(binary_count_trailing_zeros_bitwise(25), 0); +/// assert_eq!(binary_count_trailing_zeros_bitwise(36), 2); /// ``` -#[allow(dead_code)] pub fn binary_count_trailing_zeros_bitwise(num: u64) -> u32 { if num == 0 { return 0; } - - // The bit manipulation trick: num & -num isolates the rightmost set bit - // Taking log2 gives us the position (number of trailing zeros) + let rightmost_set_bit = num & (num.wrapping_neg()); - - // Calculate log2 using leading zeros - // log2(x) = 63 - leading_zeros(x) for u64 63 - rightmost_set_bit.leading_zeros() } @@ -84,14 +51,10 @@ mod tests { #[test] fn test_basic_cases() { - assert_eq!(binary_count_trailing_zeros(25), 0); // 11001 - assert_eq!(binary_count_trailing_zeros(36), 2); // 100100 - assert_eq!(binary_count_trailing_zeros(16), 4); // 10000 - assert_eq!(binary_count_trailing_zeros(58), 1); // 111010 - } - - #[test] - fn test_large_number() { + assert_eq!(binary_count_trailing_zeros(25), 0); + assert_eq!(binary_count_trailing_zeros(36), 2); + assert_eq!(binary_count_trailing_zeros(16), 4); + assert_eq!(binary_count_trailing_zeros(58), 1); assert_eq!(binary_count_trailing_zeros(4294967296), 32); } @@ -102,61 +65,23 @@ mod tests { #[test] fn test_powers_of_two() { - // Powers of 2 have trailing zeros equal to their exponent - assert_eq!(binary_count_trailing_zeros(1), 0); // 2^0 - assert_eq!(binary_count_trailing_zeros(2), 1); // 2^1 - assert_eq!(binary_count_trailing_zeros(4), 2); // 2^2 - assert_eq!(binary_count_trailing_zeros(8), 3); // 2^3 - assert_eq!(binary_count_trailing_zeros(1024), 10); // 2^10 - } - - #[test] - fn test_odd_numbers() { - // Odd numbers always have 0 trailing zeros assert_eq!(binary_count_trailing_zeros(1), 0); - assert_eq!(binary_count_trailing_zeros(3), 0); - assert_eq!(binary_count_trailing_zeros(5), 0); - assert_eq!(binary_count_trailing_zeros(7), 0); - assert_eq!(binary_count_trailing_zeros(99), 0); - } - - #[test] - fn test_even_numbers() { - assert_eq!(binary_count_trailing_zeros(2), 1); // 10 - assert_eq!(binary_count_trailing_zeros(4), 2); // 100 - assert_eq!(binary_count_trailing_zeros(6), 1); // 110 - assert_eq!(binary_count_trailing_zeros(8), 3); // 1000 - assert_eq!(binary_count_trailing_zeros(12), 2); // 1100 + assert_eq!(binary_count_trailing_zeros(2), 1); + assert_eq!(binary_count_trailing_zeros(4), 2); + assert_eq!(binary_count_trailing_zeros(8), 3); + assert_eq!(binary_count_trailing_zeros(1024), 10); } #[test] fn test_bitwise_implementation() { - // Test that both implementations give the same results let test_cases = vec![0, 1, 2, 4, 8, 16, 25, 36, 58, 1024, 4294967296]; - + for num in test_cases { assert_eq!( binary_count_trailing_zeros(num), binary_count_trailing_zeros_bitwise(num), - "Mismatch for input: {}", - num + "Mismatch for input: {num}" ); } } - - #[test] - fn test_max_value() { - // Test with maximum u64 value - let max_u64 = u64::MAX; - assert_eq!(binary_count_trailing_zeros(max_u64), 0); // All 1s, no trailing zeros - } - - #[test] - fn test_patterns() { - // Test specific binary patterns - assert_eq!(binary_count_trailing_zeros(0b1000), 3); - assert_eq!(binary_count_trailing_zeros(0b10000), 4); - assert_eq!(binary_count_trailing_zeros(0b100000), 5); - assert_eq!(binary_count_trailing_zeros(0b1111000), 3); - } } From 28d769d3f18f009e00b9853d0a3abd0d69ab9000 Mon Sep 17 00:00:00 2001 From: Ali Alimohammadi <41567902+AliAlimohammadi@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:46:48 -0800 Subject: [PATCH 3/3] Update binary_count_trailing_zeros.rs --- .../binary_count_trailing_zeros.rs | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/bit_manipulation/binary_count_trailing_zeros.rs b/src/bit_manipulation/binary_count_trailing_zeros.rs index 9e6bb5bc297..9950375ddf9 100644 --- a/src/bit_manipulation/binary_count_trailing_zeros.rs +++ b/src/bit_manipulation/binary_count_trailing_zeros.rs @@ -32,15 +32,23 @@ pub fn binary_count_trailing_zeros(num: u64) -> u32 { /// # Examples /// /// ``` -/// # use the_algorithms_rust::bit_manipulation::binary_count_trailing_zeros_bitwise; +/// // This function uses bit manipulation: log2(num & -num) +/// // where num & -num isolates the rightmost set bit +/// # fn binary_count_trailing_zeros_bitwise(num: u64) -> u32 { +/// # if num == 0 { return 0; } +/// # let rightmost_set_bit = num & (num.wrapping_neg()); +/// # 63 - rightmost_set_bit.leading_zeros() +/// # } /// assert_eq!(binary_count_trailing_zeros_bitwise(25), 0); /// assert_eq!(binary_count_trailing_zeros_bitwise(36), 2); +/// assert_eq!(binary_count_trailing_zeros_bitwise(16), 4); /// ``` +#[allow(dead_code)] pub fn binary_count_trailing_zeros_bitwise(num: u64) -> u32 { if num == 0 { return 0; } - + let rightmost_set_bit = num & (num.wrapping_neg()); 63 - rightmost_set_bit.leading_zeros() } @@ -73,9 +81,33 @@ mod tests { } #[test] - fn test_bitwise_implementation() { - let test_cases = vec![0, 1, 2, 4, 8, 16, 25, 36, 58, 1024, 4294967296]; - + fn test_bitwise_vs_builtin() { + // Test that bitwise implementation matches built-in trailing_zeros() + let test_cases = vec![ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 16, + 25, + 36, + 58, + 64, + 100, + 128, + 256, + 512, + 1024, + 4294967296, + u64::MAX - 1, + u64::MAX, + ]; + for num in test_cases { assert_eq!( binary_count_trailing_zeros(num),