Skip to content

Commit 7cf4aab

Browse files
committed
bit_manipulation: add parity, next_power_of_two, rotate_bits (Author: Basuki Nath) and extend doctests
1 parent a71618f commit 7cf4aab

5 files changed

Lines changed: 173 additions & 0 deletions

File tree

bit_manipulation/count_number_of_one_bits.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ def get_set_bits_count_using_brian_kernighans_algorithm(number: int) -> int:
2020
Traceback (most recent call last):
2121
...
2222
ValueError: the value of input must not be negative
23+
>>> get_set_bits_count_using_brian_kernighans_algorithm(1023)
24+
10
2325
"""
2426
if number < 0:
2527
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:
4951
Traceback (most recent call last):
5052
...
5153
ValueError: the value of input must not be negative
54+
>>> get_set_bits_count_using_modulo_operator(1024)
55+
1
5256
"""
5357
if number < 0:
5458
raise ValueError("the value of input must not be negative")

bit_manipulation/is_power_of_two.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ def is_power_of_two(number: int) -> bool:
3333
True
3434
>>> is_power_of_two(17)
3535
False
36+
>>> is_power_of_two(1024)
37+
True
38+
>>> is_power_of_two(1023)
39+
False
3640
>>> is_power_of_two(-1)
3741
Traceback (most recent call last):
3842
...
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""
2+
Author : Basuki Nath
3+
Date : 2025-10-04
4+
5+
Utility to compute the next power of two greater than or equal to n.
6+
"""
7+
8+
def next_power_of_two(n: int) -> int:
9+
"""
10+
Return the smallest power of two >= n for positive integers.
11+
12+
>>> next_power_of_two(1)
13+
1
14+
>>> next_power_of_two(2)
15+
2
16+
>>> next_power_of_two(3)
17+
4
18+
>>> next_power_of_two(5)
19+
8
20+
>>> next_power_of_two(1025)
21+
2048
22+
>>> next_power_of_two(0)
23+
Traceback (most recent call last):
24+
...
25+
ValueError: n must be positive
26+
>>> next_power_of_two(-3)
27+
Traceback (most recent call last):
28+
...
29+
ValueError: n must be positive
30+
"""
31+
if n <= 0:
32+
raise ValueError("n must be positive")
33+
# If already a power of two, return it
34+
if n & (n - 1) == 0:
35+
return n
36+
# Otherwise, fill bits to the right
37+
v = n - 1
38+
v |= v >> 1
39+
v |= v >> 2
40+
v |= v >> 4
41+
v |= v >> 8
42+
v |= v >> 16
43+
# for very large ints, continue shifting using Python's arbitrary precision
44+
shift = 32
45+
while (1 << shift) <= v:
46+
v |= v >> shift
47+
shift <<= 1
48+
return v + 1
49+
50+
51+
if __name__ == "__main__":
52+
import doctest
53+
54+
doctest.testmod()

bit_manipulation/parity.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""
2+
Author : Basuki Nath
3+
Date : 2025-10-04
4+
5+
Simple parity utility for integers.
6+
7+
The parity is 1 when the number of set bits is odd, otherwise 0.
8+
"""
9+
10+
def parity(number: int) -> int:
11+
"""
12+
Return 1 if `number` has an odd number of set bits, otherwise 0.
13+
14+
>>> parity(0)
15+
0
16+
>>> parity(1)
17+
1
18+
>>> parity(2) # 10b -> one set bit
19+
1
20+
>>> parity(3) # 11b -> two set bits
21+
0
22+
>>> parity(1023) # 10 ones -> even
23+
0
24+
>>> parity(-1)
25+
Traceback (most recent call last):
26+
...
27+
ValueError: number must not be negative
28+
"""
29+
if number < 0:
30+
raise ValueError("number must not be negative")
31+
# Kernighan's algorithm toggling parity
32+
p = 0
33+
while number:
34+
p ^= 1
35+
number &= number - 1
36+
return p
37+
38+
39+
if __name__ == "__main__":
40+
import doctest
41+
42+
doctest.testmod()

bit_manipulation/rotate_bits.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""
2+
Author : Basuki Nath
3+
Date : 2025-10-04
4+
5+
Bit rotation helpers for 32-bit unsigned integers.
6+
"""
7+
8+
def rotate_left32(x: int, k: int) -> int:
9+
"""
10+
Rotate the lower 32 bits of x left by k and return result in 0..2**32-1.
11+
12+
>>> rotate_left32(1, 1)
13+
2
14+
>>> rotate_left32(1, 31)
15+
2147483648
16+
>>> rotate_left32(0x80000000, 1)
17+
1
18+
>>> rotate_left32(0x12345678, 4)
19+
591751041
20+
>>> rotate_left32(-1, 3)
21+
Traceback (most recent call last):
22+
...
23+
ValueError: x must be a non-negative integer
24+
>>> rotate_left32(1, -1)
25+
Traceback (most recent call last):
26+
...
27+
ValueError: k must be non-negative
28+
"""
29+
if not isinstance(x, int) or x < 0:
30+
raise ValueError("x must be a non-negative integer")
31+
if not isinstance(k, int) or k < 0:
32+
raise ValueError("k must be non-negative")
33+
mask = (1 << 32) - 1
34+
k &= 31
35+
return ((x << k) & mask) | ((x & mask) >> (32 - k))
36+
37+
38+
def rotate_right32(x: int, k: int) -> int:
39+
"""
40+
Rotate the lower 32 bits of x right by k and return result in 0..2**32-1.
41+
42+
>>> rotate_right32(2, 1)
43+
1
44+
>>> rotate_right32(1, 1)
45+
2147483648
46+
>>> rotate_right32(0x12345678, 4)
47+
2166572391
48+
>>> rotate_right32(-1, 1)
49+
Traceback (most recent call last):
50+
...
51+
ValueError: x must be a non-negative integer
52+
>>> rotate_right32(1, -3)
53+
Traceback (most recent call last):
54+
...
55+
ValueError: k must be non-negative
56+
"""
57+
if not isinstance(x, int) or x < 0:
58+
raise ValueError("x must be a non-negative integer")
59+
if not isinstance(k, int) or k < 0:
60+
raise ValueError("k must be non-negative")
61+
mask = (1 << 32) - 1
62+
k &= 31
63+
return ((x & mask) >> k) | ((x << (32 - k)) & mask)
64+
65+
66+
if __name__ == "__main__":
67+
import doctest
68+
69+
doctest.testmod()

0 commit comments

Comments
 (0)