diff --git a/bit_manipulation/count_number_of_one_bits.py b/bit_manipulation/count_number_of_one_bits.py index f0c9f927620a..b34ff7e1c5d2 100644 --- a/bit_manipulation/count_number_of_one_bits.py +++ b/bit_manipulation/count_number_of_one_bits.py @@ -20,6 +20,8 @@ def get_set_bits_count_using_brian_kernighans_algorithm(number: int) -> int: Traceback (most recent call last): ... ValueError: the value of input must not be negative + >>> get_set_bits_count_using_brian_kernighans_algorithm(1023) + 10 """ if number < 0: raise ValueError("the value of input must not be negative") @@ -49,6 +51,8 @@ def get_set_bits_count_using_modulo_operator(number: int) -> int: Traceback (most recent call last): ... ValueError: the value of input must not be negative + >>> get_set_bits_count_using_modulo_operator(1024) + 1 """ if number < 0: raise ValueError("the value of input must not be negative") diff --git a/bit_manipulation/is_power_of_two.py b/bit_manipulation/is_power_of_two.py index 023e979fe51c..3dd8df3540bc 100644 --- a/bit_manipulation/is_power_of_two.py +++ b/bit_manipulation/is_power_of_two.py @@ -33,6 +33,10 @@ def is_power_of_two(number: int) -> bool: True >>> is_power_of_two(17) False + >>> is_power_of_two(1024) + True + >>> is_power_of_two(1023) + False >>> is_power_of_two(-1) Traceback (most recent call last): ... diff --git a/bit_manipulation/next_power_of_two.py b/bit_manipulation/next_power_of_two.py new file mode 100644 index 000000000000..4b523c17b130 --- /dev/null +++ b/bit_manipulation/next_power_of_two.py @@ -0,0 +1,55 @@ +""" +Author : Basuki Nath +Date : 2025-10-04 + +Utility to compute the next power of two greater than or equal to n. +""" + + +def next_power_of_two(n: int) -> int: + """ + Return the smallest power of two >= n for positive integers. + + >>> next_power_of_two(1) + 1 + >>> next_power_of_two(2) + 2 + >>> next_power_of_two(3) + 4 + >>> next_power_of_two(5) + 8 + >>> next_power_of_two(1025) + 2048 + >>> next_power_of_two(0) + Traceback (most recent call last): + ... + ValueError: n must be positive + >>> next_power_of_two(-3) + Traceback (most recent call last): + ... + ValueError: n must be positive + """ + if n <= 0: + raise ValueError("n must be positive") + # If already a power of two, return it + if n & (n - 1) == 0: + return n + # Otherwise, fill bits to the right + v = n - 1 + v |= v >> 1 + v |= v >> 2 + v |= v >> 4 + v |= v >> 8 + v |= v >> 16 + # for very large ints, continue shifting using Python's arbitrary precision + shift = 32 + while (1 << shift) <= v: + v |= v >> shift + shift <<= 1 + return v + 1 + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/bit_manipulation/parity.py b/bit_manipulation/parity.py new file mode 100644 index 000000000000..019c88deea30 --- /dev/null +++ b/bit_manipulation/parity.py @@ -0,0 +1,43 @@ +""" +Author : Basuki Nath +Date : 2025-10-04 + +Simple parity utility for integers. + +The parity is 1 when the number of set bits is odd, otherwise 0. +""" + + +def parity(number: int) -> int: + """ + Return 1 if `number` has an odd number of set bits, otherwise 0. + + >>> parity(0) + 0 + >>> parity(1) + 1 + >>> parity(2) # 10b -> one set bit + 1 + >>> parity(3) # 11b -> two set bits + 0 + >>> parity(1023) # 10 ones -> even + 0 + >>> parity(-1) + Traceback (most recent call last): + ... + ValueError: number must not be negative + """ + if number < 0: + raise ValueError("number must not be negative") + # Kernighan's algorithm toggling parity + p = 0 + while number: + p ^= 1 + number &= number - 1 + return p + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/bit_manipulation/rotate_bits.py b/bit_manipulation/rotate_bits.py new file mode 100644 index 000000000000..521ab8de203f --- /dev/null +++ b/bit_manipulation/rotate_bits.py @@ -0,0 +1,70 @@ +""" +Author : Basuki Nath +Date : 2025-10-04 + +Bit rotation helpers for 32-bit unsigned integers. +""" + + +def rotate_left32(x: int, k: int) -> int: + """ + Rotate the lower 32 bits of x left by k and return result in 0..2**32-1. + + >>> rotate_left32(1, 1) + 2 + >>> rotate_left32(1, 31) + 2147483648 + >>> rotate_left32(0x80000000, 1) + 1 + >>> rotate_left32(0x12345678, 4) + 591751041 + >>> rotate_left32(-1, 3) + Traceback (most recent call last): + ... + ValueError: x must be a non-negative integer + >>> rotate_left32(1, -1) + Traceback (most recent call last): + ... + ValueError: k must be non-negative + """ + if not isinstance(x, int) or x < 0: + raise ValueError("x must be a non-negative integer") + if not isinstance(k, int) or k < 0: + raise ValueError("k must be non-negative") + mask = (1 << 32) - 1 + k &= 31 + return ((x << k) & mask) | ((x & mask) >> (32 - k)) + + +def rotate_right32(x: int, k: int) -> int: + """ + Rotate the lower 32 bits of x right by k and return result in 0..2**32-1. + + >>> rotate_right32(2, 1) + 1 + >>> rotate_right32(1, 1) + 2147483648 + >>> rotate_right32(0x12345678, 4) + 2166572391 + >>> rotate_right32(-1, 1) + Traceback (most recent call last): + ... + ValueError: x must be a non-negative integer + >>> rotate_right32(1, -3) + Traceback (most recent call last): + ... + ValueError: k must be non-negative + """ + if not isinstance(x, int) or x < 0: + raise ValueError("x must be a non-negative integer") + if not isinstance(k, int) or k < 0: + raise ValueError("k must be non-negative") + mask = (1 << 32) - 1 + k &= 31 + return ((x & mask) >> k) | ((x << (32 - k)) & mask) + + +if __name__ == "__main__": + import doctest + + doctest.testmod()