Skip to content

Commit a2225d0

Browse files
Add find previous power of two implementation
1 parent e5bceac commit a2225d0

File tree

3 files changed

+184
-9
lines changed

3 files changed

+184
-9
lines changed

DIRECTORY.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* [Counting Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/counting_bits.rs)
2222
* [Highest Set Bit](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/highest_set_bit.rs)
2323
* [N Bits Gray Code](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/n_bits_gray_code.rs)
24+
* [Previous Power of Two](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/find_previous_power_of_two.rs)
2425
* [Reverse Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/reverse_bits.rs)
2526
* [Sum of Two Integers](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/sum_of_two_integers.rs)
2627
* [Swap Odd and Even Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/swap_odd_even_bits.rs)
@@ -195,7 +196,7 @@
195196
* [Gradient Descent](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/optimization/gradient_descent.rs)
196197
* [Momentum](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/optimization/momentum.rs)
197198
* Math
198-
* [Abs](https://github.com/TheAlgorithms/Rust/blob/master/src/math/abs.rs)
199+
* [Absolute](https://github.com/TheAlgorithms/Rust/blob/master/src/math/abs.rs)
199200
* [Aliquot Sum](https://github.com/TheAlgorithms/Rust/blob/master/src/math/aliquot_sum.rs)
200201
* [Amicable Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/amicable_numbers.rs)
201202
* [Area Of Polygon](https://github.com/TheAlgorithms/Rust/blob/master/src/math/area_of_polygon.rs)
@@ -259,18 +260,18 @@
259260
* [Prime Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/prime_numbers.rs)
260261
* [Quadratic Residue](https://github.com/TheAlgorithms/Rust/blob/master/src/math/quadratic_residue.rs)
261262
* [Random](https://github.com/TheAlgorithms/Rust/blob/master/src/math/random.rs)
262-
* [Relu](https://github.com/TheAlgorithms/Rust/blob/master/src/math/relu.rs)
263-
* [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sieve_of_eratosthenes.rs)
263+
* [ReLU](https://github.com/TheAlgorithms/Rust/blob/master/src/math/relu.rs)
264+
* [Sieve of Eratosthenes](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sieve_of_eratosthenes.rs)
264265
* [Sigmoid](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sigmoid.rs)
265266
* [Signum](https://github.com/TheAlgorithms/Rust/blob/master/src/math/signum.rs)
266267
* [Simpsons Integration](https://github.com/TheAlgorithms/Rust/blob/master/src/math/simpsons_integration.rs)
267268
* [Softmax](https://github.com/TheAlgorithms/Rust/blob/master/src/math/softmax.rs)
268269
* [Sprague Grundy Theorem](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sprague_grundy_theorem.rs)
269270
* [Square Pyramidal Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/square_pyramidal_numbers.rs)
270271
* [Square Root](https://github.com/TheAlgorithms/Rust/blob/master/src/math/square_root.rs)
271-
* [Sum Of Digits](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sum_of_digits.rs)
272-
* [Sum Of Geometric Progression](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sum_of_geometric_progression.rs)
273-
* [Sum Of Harmonic Series](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sum_of_harmonic_series.rs)
272+
* [Sum of Digits](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sum_of_digits.rs)
273+
* [Sum of Geometric Progression](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sum_of_geometric_progression.rs)
274+
* [Sum of Harmonic Series](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sum_of_harmonic_series.rs)
274275
* [Sylvester Sequence](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sylvester_sequence.rs)
275276
* [Tanh](https://github.com/TheAlgorithms/Rust/blob/master/src/math/tanh.rs)
276277
* [Trapezoidal Integration](https://github.com/TheAlgorithms/Rust/blob/master/src/math/trapezoidal_integration.rs)
@@ -285,16 +286,16 @@
285286
* Number Theory
286287
* [Compute Totient](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/compute_totient.rs)
287288
* [Euler Totient](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/euler_totient.rs)
288-
* [Kth Factor](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/kth_factor.rs)
289+
* [K-th Factor](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/kth_factor.rs)
289290
* Searching
290291
* [Binary Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/binary_search.rs)
291292
* [Binary Search Recursive](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/binary_search_recursive.rs)
292293
* [Exponential Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/exponential_search.rs)
293294
* [Fibonacci Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/fibonacci_search.rs)
294295
* [Interpolation Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/interpolation_search.rs)
295296
* [Jump Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/jump_search.rs)
296-
* [Kth Smallest](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/kth_smallest.rs)
297-
* [Kth Smallest Heap](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/kth_smallest_heap.rs)
297+
* [K-th Smallest](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/kth_smallest.rs)
298+
* [K-th Smallest Heap](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/kth_smallest_heap.rs)
298299
* [Linear Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/linear_search.rs)
299300
* [Moore Voting](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/moore_voting.rs)
300301
* [Quick Select](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/quick_select.rs)
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//! Previous Power of Two
2+
//!
3+
//! This module provides a function to find the largest power of two that is less than
4+
//! or equal to a given non-negative integer.
5+
//!
6+
//! # Algorithm
7+
//!
8+
//! The algorithm works by repeatedly left-shifting (doubling) a power value starting
9+
//! from 1 until it exceeds the input number, then returning the previous power (by
10+
//! right-shifting once).
11+
//!
12+
//! For more information: <https://stackoverflow.com/questions/1322510>
13+
14+
/// Finds the largest power of two that is less than or equal to a given integer.
15+
///
16+
/// The function uses bit shifting to efficiently find the power of two. It starts
17+
/// with 1 and keeps doubling (left shift) until it exceeds the input, then returns
18+
/// the previous value (right shift).
19+
///
20+
/// # Arguments
21+
///
22+
/// * `number` - A non-negative integer
23+
///
24+
/// # Returns
25+
///
26+
/// A `Result` containing:
27+
/// - `Ok(u32)` - The largest power of two ≤ the input number
28+
/// - `Err(String)` - An error message if the input is negative
29+
///
30+
/// # Examples
31+
///
32+
/// ```
33+
/// use the_algorithms_rust::bit_manipulation::find_previous_power_of_two;
34+
///
35+
/// assert_eq!(find_previous_power_of_two(0).unwrap(), 0);
36+
/// assert_eq!(find_previous_power_of_two(1).unwrap(), 1);
37+
/// assert_eq!(find_previous_power_of_two(2).unwrap(), 2);
38+
/// assert_eq!(find_previous_power_of_two(3).unwrap(), 2);
39+
/// assert_eq!(find_previous_power_of_two(4).unwrap(), 4);
40+
/// assert_eq!(find_previous_power_of_two(5).unwrap(), 4);
41+
/// assert_eq!(find_previous_power_of_two(8).unwrap(), 8);
42+
/// assert_eq!(find_previous_power_of_two(15).unwrap(), 8);
43+
/// assert_eq!(find_previous_power_of_two(16).unwrap(), 16);
44+
/// assert_eq!(find_previous_power_of_two(17).unwrap(), 16);
45+
///
46+
/// // Negative numbers return an error
47+
/// assert!(find_previous_power_of_two(-5).is_err());
48+
/// ```
49+
///
50+
/// # Errors
51+
///
52+
/// Returns an error if the input number is negative.
53+
pub fn find_previous_power_of_two(number: i32) -> Result<u32, String> {
54+
if number < 0 {
55+
return Err("Input must be a non-negative integer".to_string());
56+
}
57+
58+
let number = number as u32;
59+
60+
if number == 0 {
61+
return Ok(0);
62+
}
63+
64+
let mut power = 1u32;
65+
while power <= number {
66+
power <<= 1; // Equivalent to multiplying by 2
67+
}
68+
69+
Ok(if number > 1 { power >> 1 } else { 1 })
70+
}
71+
72+
#[cfg(test)]
73+
mod tests {
74+
use super::*;
75+
76+
#[test]
77+
fn test_zero() {
78+
assert_eq!(find_previous_power_of_two(0).unwrap(), 0);
79+
}
80+
81+
#[test]
82+
fn test_one() {
83+
assert_eq!(find_previous_power_of_two(1).unwrap(), 1);
84+
}
85+
86+
#[test]
87+
fn test_powers_of_two() {
88+
assert_eq!(find_previous_power_of_two(2).unwrap(), 2);
89+
assert_eq!(find_previous_power_of_two(4).unwrap(), 4);
90+
assert_eq!(find_previous_power_of_two(8).unwrap(), 8);
91+
assert_eq!(find_previous_power_of_two(16).unwrap(), 16);
92+
assert_eq!(find_previous_power_of_two(32).unwrap(), 32);
93+
assert_eq!(find_previous_power_of_two(64).unwrap(), 64);
94+
assert_eq!(find_previous_power_of_two(128).unwrap(), 128);
95+
assert_eq!(find_previous_power_of_two(256).unwrap(), 256);
96+
assert_eq!(find_previous_power_of_two(512).unwrap(), 512);
97+
assert_eq!(find_previous_power_of_two(1024).unwrap(), 1024);
98+
}
99+
100+
#[test]
101+
fn test_numbers_between_powers() {
102+
// Between 2 and 4
103+
assert_eq!(find_previous_power_of_two(3).unwrap(), 2);
104+
105+
// Between 4 and 8
106+
assert_eq!(find_previous_power_of_two(5).unwrap(), 4);
107+
assert_eq!(find_previous_power_of_two(6).unwrap(), 4);
108+
assert_eq!(find_previous_power_of_two(7).unwrap(), 4);
109+
110+
// Between 8 and 16
111+
assert_eq!(find_previous_power_of_two(9).unwrap(), 8);
112+
assert_eq!(find_previous_power_of_two(10).unwrap(), 8);
113+
assert_eq!(find_previous_power_of_two(11).unwrap(), 8);
114+
assert_eq!(find_previous_power_of_two(12).unwrap(), 8);
115+
assert_eq!(find_previous_power_of_two(13).unwrap(), 8);
116+
assert_eq!(find_previous_power_of_two(14).unwrap(), 8);
117+
assert_eq!(find_previous_power_of_two(15).unwrap(), 8);
118+
119+
// Between 16 and 32
120+
assert_eq!(find_previous_power_of_two(17).unwrap(), 16);
121+
assert_eq!(find_previous_power_of_two(20).unwrap(), 16);
122+
assert_eq!(find_previous_power_of_two(31).unwrap(), 16);
123+
}
124+
125+
#[test]
126+
fn test_range_0_to_17() {
127+
// Test the exact output from the Python docstring
128+
let expected = vec![0, 1, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16];
129+
let results: Vec<u32> = (0..18)
130+
.map(|i| find_previous_power_of_two(i).unwrap())
131+
.collect();
132+
assert_eq!(results, expected);
133+
}
134+
135+
#[test]
136+
fn test_large_numbers() {
137+
assert_eq!(find_previous_power_of_two(100).unwrap(), 64);
138+
assert_eq!(find_previous_power_of_two(500).unwrap(), 256);
139+
assert_eq!(find_previous_power_of_two(1000).unwrap(), 512);
140+
assert_eq!(find_previous_power_of_two(2000).unwrap(), 1024);
141+
assert_eq!(find_previous_power_of_two(10000).unwrap(), 8192);
142+
}
143+
144+
#[test]
145+
fn test_max_safe_values() {
146+
assert_eq!(find_previous_power_of_two(1023).unwrap(), 512);
147+
assert_eq!(find_previous_power_of_two(2047).unwrap(), 1024);
148+
assert_eq!(find_previous_power_of_two(4095).unwrap(), 2048);
149+
}
150+
151+
#[test]
152+
fn test_negative_number_returns_error() {
153+
let result = find_previous_power_of_two(-1);
154+
assert!(result.is_err());
155+
assert_eq!(result.unwrap_err(), "Input must be a non-negative integer");
156+
}
157+
158+
#[test]
159+
fn test_negative_numbers_return_errors() {
160+
assert!(find_previous_power_of_two(-5).is_err());
161+
assert!(find_previous_power_of_two(-10).is_err());
162+
assert!(find_previous_power_of_two(-100).is_err());
163+
}
164+
165+
#[test]
166+
fn test_edge_cases() {
167+
// One less than powers of two
168+
assert_eq!(find_previous_power_of_two(127).unwrap(), 64);
169+
assert_eq!(find_previous_power_of_two(255).unwrap(), 128);
170+
assert_eq!(find_previous_power_of_two(511).unwrap(), 256);
171+
}
172+
}

src/bit_manipulation/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod binary_coded_decimal;
22
mod counting_bits;
3+
mod find_previous_power_of_two;
34
mod highest_set_bit;
45
mod n_bits_gray_code;
56
mod reverse_bits;
@@ -9,6 +10,7 @@ mod twos_complement;
910

1011
pub use self::binary_coded_decimal::binary_coded_decimal;
1112
pub use self::counting_bits::count_set_bits;
13+
pub use self::find_previous_power_of_two::find_previous_power_of_two;
1214
pub use self::highest_set_bit::find_highest_set_bit;
1315
pub use self::n_bits_gray_code::generate_gray_code;
1416
pub use self::reverse_bits::reverse_bits;

0 commit comments

Comments
 (0)