Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve bit manipulation algorithm implementations #788

Merged
merged 3 commits into from
Sep 16, 2024
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
58 changes: 33 additions & 25 deletions src/bit_manipulation/counting_bits.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
/*
The counting bits algorithm, also known as the "population count" or "Hamming weight,"
calculates the number of set bits (1s) in the binary representation of an unsigned integer.
It uses a technique known as Brian Kernighan's algorithm, which efficiently clears the least
significant set bit in each iteration.
*/

pub fn count_set_bits(mut n: u32) -> u32 {
//! This module implements a function to count the number of set bits (1s)
//! in the binary representation of an unsigned integer.
//! It uses Brian Kernighan's algorithm, which efficiently clears the least significant
//! set bit in each iteration until all bits are cleared.
//! The algorithm runs in O(k), where k is the number of set bits.

/// Counts the number of set bits in an unsigned integer.
///
/// # Arguments
///
/// * `n` - An unsigned 32-bit integer whose set bits will be counted.
///
/// # Returns
///
/// * `usize` - The number of set bits (1s) in the binary representation of the input number.
pub fn count_set_bits(mut n: usize) -> usize {
vil02 marked this conversation as resolved.
Show resolved Hide resolved
// Initialize a variable to keep track of the count of set bits
let mut count = 0;
while n > 0 {
Expand All @@ -24,23 +32,23 @@ pub fn count_set_bits(mut n: u32) -> u32 {
mod tests {
use super::*;

#[test]
fn test_count_set_bits_zero() {
assert_eq!(count_set_bits(0), 0);
}

#[test]
fn test_count_set_bits_one() {
assert_eq!(count_set_bits(1), 1);
macro_rules! test_count_set_bits {
($($name:ident: $test_case:expr,)*) => {
$(
#[test]
fn $name() {
let (input, expected) = $test_case;
assert_eq!(count_set_bits(input), expected);
}
)*
};
}

#[test]
fn test_count_set_bits_power_of_two() {
assert_eq!(count_set_bits(16), 1); // 16 is 2^4, only one set bit
}

#[test]
fn test_count_set_bits_all_set_bits() {
assert_eq!(count_set_bits(u32::MAX), 32); // Maximum value for u32, all set bits
test_count_set_bits! {
test_count_set_bits_zero: (0, 0),
test_count_set_bits_one: (1, 1),
test_count_set_bits_power_of_two: (16, 1),
test_count_set_bits_all_set_bits: (usize::MAX, std::mem::size_of::<usize>() * 8),
test_count_set_bits_alternating_bits: (0b10101010, 4),
test_count_set_bits_mixed_bits: (0b11011011, 6),
}
}
56 changes: 30 additions & 26 deletions src/bit_manipulation/highest_set_bit.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
// Find Highest Set Bit in Rust
// This code provides a function to calculate the position (or index) of the most significant bit set to 1 in a given integer.

// Define a function to find the highest set bit.
pub fn find_highest_set_bit(num: i32) -> Option<i32> {
if num < 0 {
// Input cannot be negative.
panic!("Input cannot be negative");
}

//! This module provides a function to find the position of the most significant bit (MSB)
//! set to 1 in a given positive integer.

/// Finds the position of the highest (most significant) set bit in a positive integer.
///
/// # Arguments
///
/// * `num` - An integer value for which the highest set bit will be determined.
///
/// # Returns
///
/// * Returns `Some(position)` if a set bit exists or `None` if no bit is set.
pub fn find_highest_set_bit(num: usize) -> Option<usize> {
if num == 0 {
return None; // No bit is set, return None.
return None;
}

let mut position = 0;
Expand All @@ -27,22 +30,23 @@ pub fn find_highest_set_bit(num: i32) -> Option<i32> {
mod tests {
use super::*;

#[test]
fn test_positive_number() {
let num = 18;
assert_eq!(find_highest_set_bit(num), Some(4));
}

#[test]
fn test_zero() {
let num = 0;
assert_eq!(find_highest_set_bit(num), None);
macro_rules! test_find_highest_set_bit {
($($name:ident: $test_case:expr,)*) => {
$(
#[test]
fn $name() {
let (input, expected) = $test_case;
assert_eq!(find_highest_set_bit(input), expected);
}
)*
};
}

#[test]
#[should_panic(expected = "Input cannot be negative")]
fn test_negative_number() {
let num = -12;
find_highest_set_bit(num);
test_find_highest_set_bit! {
test_positive_number: (18, Some(4)),
test_0: (0, None),
test_1: (1, Some(0)),
test_2: (2, Some(1)),
test_3: (3, Some(1)),
}
}
67 changes: 37 additions & 30 deletions src/bit_manipulation/sum_of_two_integers.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
/**
* This algorithm demonstrates how to add two integers without using the + operator
* but instead relying on bitwise operations, like bitwise XOR and AND, to simulate
* the addition. It leverages bit manipulation to compute the sum efficiently.
*/
//! This module provides a function to add two integers without using the `+` operator.
//! It relies on bitwise operations (XOR and AND) to compute the sum, simulating the addition process.

pub fn add_two_integers(a: i32, b: i32) -> i32 {
let mut a = a;
let mut b = b;
/// Adds two integers using bitwise operations.
///
/// # Arguments
///
/// * `a` - The first integer to be added.
/// * `b` - The second integer to be added.
///
/// # Returns
///
/// * `isize` - The result of adding the two integers.
pub fn add_two_integers(mut a: isize, mut b: isize) -> isize {
let mut carry;
let mut sum;

// Iterate until there is no carry left
while b != 0 {
sum = a ^ b; // XOR operation to find the sum without carry
carry = (a & b) << 1; // AND operation to find the carry, shifted left by 1
let sum = a ^ b;
carry = (a & b) << 1;
a = sum;
b = carry;
}
Expand All @@ -23,26 +26,30 @@ pub fn add_two_integers(a: i32, b: i32) -> i32 {

#[cfg(test)]
mod tests {
use super::add_two_integers;
use super::*;

#[test]
fn test_add_two_integers_positive() {
assert_eq!(add_two_integers(3, 5), 8);
assert_eq!(add_two_integers(100, 200), 300);
assert_eq!(add_two_integers(65535, 1), 65536);
macro_rules! test_add_two_integers {
($($name:ident: $test_case:expr,)*) => {
$(
#[test]
fn $name() {
let (a, b) = $test_case;
assert_eq!(add_two_integers(a, b), a + b);
assert_eq!(add_two_integers(b, a), a + b);
}
)*
};
}

#[test]
fn test_add_two_integers_negative() {
assert_eq!(add_two_integers(-10, 6), -4);
assert_eq!(add_two_integers(-50, -30), -80);
assert_eq!(add_two_integers(-1, -1), -2);
}

#[test]
fn test_add_two_integers_zero() {
assert_eq!(add_two_integers(0, 0), 0);
assert_eq!(add_two_integers(0, 42), 42);
assert_eq!(add_two_integers(0, -42), -42);
test_add_two_integers! {
test_add_two_integers_positive: (3, 5),
test_add_two_integers_large_positive: (100, 200),
test_add_two_integers_edge_positive: (65535, 1),
test_add_two_integers_negative: (-10, 6),
test_add_two_integers_both_negative: (-50, -30),
test_add_two_integers_edge_negative: (-1, -1),
test_add_two_integers_zero: (0, 0),
test_add_two_integers_zero_with_positive: (0, 42),
test_add_two_integers_zero_with_negative: (0, -42),
}
}