Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1b3d80d

Browse files
feat: add rightmost_set_bit function (TheAlgorithms#975)
1 parent a486aea commit 1b3d80d

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed

‎DIRECTORY.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
* [N Bits Gray Code](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/n_bits_gray_code.rs)
2626
* [Previous Power of Two](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/find_previous_power_of_two.rs)
2727
* [Reverse Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/reverse_bits.rs)
28+
* [Rightmost Set Bit](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/rightmost_set_bit.rs)
2829
* [Sum of Two Integers](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/sum_of_two_integers.rs)
2930
* [Swap Odd and Even Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/swap_odd_even_bits.rs)
3031
* [Trailing Zeros](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/binary_count_trailing_zeros.rs)

‎src/bit_manipulation/mod.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod highest_set_bit;
88
mod is_power_of_two;
99
mod n_bits_gray_code;
1010
mod reverse_bits;
11+
mod rightmost_set_bit;
1112
mod sum_of_two_integers;
1213
mod swap_odd_even_bits;
1314
mod twos_complement;
@@ -22,6 +23,7 @@ pub use self::highest_set_bit::find_highest_set_bit;
2223
pub use self::is_power_of_two::is_power_of_two;
2324
pub use self::n_bits_gray_code::generate_gray_code;
2425
pub use self::reverse_bits::reverse_bits;
26+
pub use self::rightmost_set_bit::{index_of_rightmost_set_bit, index_of_rightmost_set_bit_log};
2527
pub use self::sum_of_two_integers::add_two_integers;
2628
pub use self::swap_odd_even_bits::swap_odd_even_bits;
2729
pub use self::twos_complement::twos_complement;
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/// Finds the index (position) of the rightmost set bit in a number.
2+
///
3+
/// The index is 1-based, where position 1 is the least significant bit (rightmost).
4+
/// This function uses the bitwise trick `n & -n` to isolate the rightmost set bit,
5+
/// then calculates its position using logarithm base 2.
6+
///
7+
/// # Algorithm
8+
///
9+
/// 1. Use `n & -n` to isolate the rightmost set bit
10+
/// 2. Calculate log2 of the result to get the 0-based position
11+
/// 3. Add 1 to convert to 1-based indexing
12+
///
13+
/// # Arguments
14+
///
15+
/// * `num` - A positive integer
16+
///
17+
/// # Returns
18+
///
19+
/// * `Ok(u32)` - The 1-based position of the rightmost set bit
20+
/// * `Err(String)` - An error message if the input is invalid
21+
///
22+
/// # Examples
23+
///
24+
/// ```
25+
/// # use the_algorithms_rust::bit_manipulation::index_of_rightmost_set_bit;
26+
/// // 18 in binary: 10010, rightmost set bit is at position 2
27+
/// assert_eq!(index_of_rightmost_set_bit(18).unwrap(), 2);
28+
///
29+
/// // 12 in binary: 1100, rightmost set bit is at position 3
30+
/// assert_eq!(index_of_rightmost_set_bit(12).unwrap(), 3);
31+
///
32+
/// // 5 in binary: 101, rightmost set bit is at position 1
33+
/// assert_eq!(index_of_rightmost_set_bit(5).unwrap(), 1);
34+
///
35+
/// // 16 in binary: 10000, rightmost set bit is at position 5
36+
/// assert_eq!(index_of_rightmost_set_bit(16).unwrap(), 5);
37+
///
38+
/// // 0 has no set bits
39+
/// assert!(index_of_rightmost_set_bit(0).is_err());
40+
/// ```
41+
pub fn index_of_rightmost_set_bit(num: i32) -> Result<u32, String> {
42+
if num <= 0 {
43+
return Err("input must be a positive integer".to_string());
44+
}
45+
46+
// Isolate the rightmost set bit using n & -n
47+
let rightmost_bit = num & -num;
48+
49+
// Calculate position: log2(rightmost_bit) + 1
50+
// We use trailing_zeros which gives us the 0-based position
51+
// and add 1 to make it 1-based
52+
let position = rightmost_bit.trailing_zeros() + 1;
53+
54+
Ok(position)
55+
}
56+
57+
/// Alternative implementation using a different algorithm approach.
58+
///
59+
/// This version demonstrates the mathematical relationship between
60+
/// the rightmost set bit position and log2.
61+
///
62+
/// # Examples
63+
///
64+
/// ```
65+
/// # use the_algorithms_rust::bit_manipulation::index_of_rightmost_set_bit_log;
66+
/// assert_eq!(index_of_rightmost_set_bit_log(18).unwrap(), 2);
67+
/// assert_eq!(index_of_rightmost_set_bit_log(12).unwrap(), 3);
68+
/// ```
69+
pub fn index_of_rightmost_set_bit_log(num: i32) -> Result<u32, String> {
70+
if num <= 0 {
71+
return Err("input must be a positive integer".to_string());
72+
}
73+
74+
// Isolate the rightmost set bit
75+
let rightmost_bit = num & -num;
76+
77+
// Use f64 log2 and convert to position
78+
let position = (rightmost_bit as f64).log2() as u32 + 1;
79+
80+
Ok(position)
81+
}
82+
83+
#[cfg(test)]
84+
mod tests {
85+
use super::*;
86+
87+
#[test]
88+
fn test_basic_cases() {
89+
// 18 = 10010 in binary, rightmost set bit at position 2
90+
assert_eq!(index_of_rightmost_set_bit(18).unwrap(), 2);
91+
92+
// 12 = 1100 in binary, rightmost set bit at position 3
93+
assert_eq!(index_of_rightmost_set_bit(12).unwrap(), 3);
94+
95+
// 5 = 101 in binary, rightmost set bit at position 1
96+
assert_eq!(index_of_rightmost_set_bit(5).unwrap(), 1);
97+
}
98+
99+
#[test]
100+
fn test_powers_of_two() {
101+
// 1 = 1 in binary, position 1
102+
assert_eq!(index_of_rightmost_set_bit(1).unwrap(), 1);
103+
104+
// 2 = 10 in binary, position 2
105+
assert_eq!(index_of_rightmost_set_bit(2).unwrap(), 2);
106+
107+
// 4 = 100 in binary, position 3
108+
assert_eq!(index_of_rightmost_set_bit(4).unwrap(), 3);
109+
110+
// 8 = 1000 in binary, position 4
111+
assert_eq!(index_of_rightmost_set_bit(8).unwrap(), 4);
112+
113+
// 16 = 10000 in binary, position 5
114+
assert_eq!(index_of_rightmost_set_bit(16).unwrap(), 5);
115+
116+
// 32 = 100000 in binary, position 6
117+
assert_eq!(index_of_rightmost_set_bit(32).unwrap(), 6);
118+
}
119+
120+
#[test]
121+
fn test_odd_numbers() {
122+
// All odd numbers have rightmost set bit at position 1
123+
assert_eq!(index_of_rightmost_set_bit(1).unwrap(), 1);
124+
assert_eq!(index_of_rightmost_set_bit(3).unwrap(), 1);
125+
assert_eq!(index_of_rightmost_set_bit(7).unwrap(), 1);
126+
assert_eq!(index_of_rightmost_set_bit(15).unwrap(), 1);
127+
assert_eq!(index_of_rightmost_set_bit(31).unwrap(), 1);
128+
}
129+
130+
#[test]
131+
fn test_even_numbers() {
132+
// 6 = 110 in binary, rightmost set bit at position 2
133+
assert_eq!(index_of_rightmost_set_bit(6).unwrap(), 2);
134+
135+
// 10 = 1010 in binary, rightmost set bit at position 2
136+
assert_eq!(index_of_rightmost_set_bit(10).unwrap(), 2);
137+
138+
// 20 = 10100 in binary, rightmost set bit at position 3
139+
assert_eq!(index_of_rightmost_set_bit(20).unwrap(), 3);
140+
}
141+
142+
#[test]
143+
fn test_zero() {
144+
assert!(index_of_rightmost_set_bit(0).is_err());
145+
assert_eq!(
146+
index_of_rightmost_set_bit(0).unwrap_err(),
147+
"input must be a positive integer"
148+
);
149+
}
150+
151+
#[test]
152+
fn test_negative_numbers() {
153+
assert!(index_of_rightmost_set_bit(-1).is_err());
154+
assert!(index_of_rightmost_set_bit(-10).is_err());
155+
assert_eq!(
156+
index_of_rightmost_set_bit(-5).unwrap_err(),
157+
"input must be a positive integer"
158+
);
159+
}
160+
161+
#[test]
162+
fn test_large_numbers() {
163+
// 1024 = 10000000000 in binary, position 11
164+
assert_eq!(index_of_rightmost_set_bit(1024).unwrap(), 11);
165+
166+
// 1023 = 1111111111 in binary, position 1
167+
assert_eq!(index_of_rightmost_set_bit(1023).unwrap(), 1);
168+
169+
// 2048 = 100000000000 in binary, position 12
170+
assert_eq!(index_of_rightmost_set_bit(2048).unwrap(), 12);
171+
}
172+
173+
#[test]
174+
fn test_consecutive_numbers() {
175+
// Testing a range to ensure correctness
176+
assert_eq!(index_of_rightmost_set_bit(14).unwrap(), 2); // 1110
177+
assert_eq!(index_of_rightmost_set_bit(15).unwrap(), 1); // 1111
178+
assert_eq!(index_of_rightmost_set_bit(16).unwrap(), 5); // 10000
179+
assert_eq!(index_of_rightmost_set_bit(17).unwrap(), 1); // 10001
180+
}
181+
182+
#[test]
183+
fn test_log_version() {
184+
// Test the alternative log-based implementation
185+
assert_eq!(index_of_rightmost_set_bit_log(18).unwrap(), 2);
186+
assert_eq!(index_of_rightmost_set_bit_log(12).unwrap(), 3);
187+
assert_eq!(index_of_rightmost_set_bit_log(5).unwrap(), 1);
188+
assert_eq!(index_of_rightmost_set_bit_log(16).unwrap(), 5);
189+
}
190+
191+
#[test]
192+
fn test_both_implementations_match() {
193+
// Verify both implementations give the same results
194+
for i in 1..=100 {
195+
assert_eq!(
196+
index_of_rightmost_set_bit(i).unwrap(),
197+
index_of_rightmost_set_bit_log(i).unwrap()
198+
);
199+
}
200+
}
201+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /