Fix details

Better comments, errors, check bit_length=0 conditions
This commit is contained in:
Bill Breitmayer 2024-06-01 12:47:58 -04:00
parent 1b582d23e8
commit db1466309a

View File

@ -54,11 +54,11 @@ rather the position to the right of the bit index.
- The original bint is ANDed with bitmask 0b11 producing 0b01 which is - The original bint is ANDed with bitmask 0b11 producing 0b01 which is
ORed with 0b1000 yielding the target 0b1001. ORed with 0b1000 yielding the target 0b1001.
It's not so bad once you get the hang of it, although it can still be a Bit manipulation operations can be tricky to debug. In the insert example
bear to debug. In the insert example above, the result of inserting 0b11 above, the result of inserting 0b11 in the center ( index=3 ) or to the
in the center ( index=3 ) or to the right ( index=2 ) produces the same right ( index=2 ) produces the same correct result despite the unintended
correct result despite the misspecification. These algorithms are very misspecification. Why is it worling sometimes and not others ? Frequently,
fast but can be touchy at times. it's the result of inserting at the wrong index, for the hundredth time !
Various bit insert/remove solutions exist using bin() string functions Various bit insert/remove solutions exist using bin() string functions
and slicing, but this bitwise implementation is significantly faster and slicing, but this bitwise implementation is significantly faster
@ -83,11 +83,11 @@ def bit_get(bint: int, index: int) -> int:
>>> bit_get(-1, 2) >>> bit_get(-1, 2)
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: All input values must be positive integers. ValueError: multi_get -> All input values must be positive integers.
>>> bit_get(0, -1) >>> bit_get(0, -1)
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: All input values must be positive integers. ValueError: multi_get -> All input values must be positive integers.
""" """
return multibit_get(bint, index, 1) return multibit_get(bint, index, 1)
@ -105,11 +105,11 @@ def bit_set(bint: int, index: int, value: int = 1) -> int:
>>> bit_set(31, 6, 3) >>> bit_set(31, 6, 3)
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Input value must be 1 or 0. ValueError: bit_set -> Input value must be 1 or 0.
""" """
if value not in [0, 1]: if value not in [0, 1]:
raise ValueError("Input value must be 1 or 0.") raise ValueError("bit_set -> Input value must be 1 or 0.")
return multibit_set(bint, index, 1, value) return multibit_set(bint, index, 1, value)
@ -128,7 +128,7 @@ def bit_insert(bint: int, index: int, value: int = 1) -> int:
""" """
if value not in [0, 1]: if value not in [0, 1]:
raise ValueError("Input value must be 1 or 0.") raise ValueError("bit_insert -> Input value must be 1 or 0.")
return multibit_insert(bint, index, 1, value) return multibit_insert(bint, index, 1, value)
@ -164,7 +164,7 @@ def multibit_get(bint: int, index: int, bit_len: int) -> int:
""" """
if bint < 0 or index < 0 or bit_len < 0: if bint < 0 or index < 0 or bit_len < 0:
raise ValueError("All input values must be positive integers.") raise ValueError("multi_get -> All input values must be positive integers.")
return (bint >> index) & ((1 << bit_len) - 1) return (bint >> index) & ((1 << bit_len) - 1)
@ -183,14 +183,14 @@ def multibit_set(bint: int, index: int, bit_len: int, value: int) -> int:
>>> multibit_set(22, 2, 1, 3) is None >>> multibit_set(22, 2, 1, 3) is None
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Bit length of value can not be greater than specified bit length. ValueError: multi_set -> Bit length of value can not be greater than specified bit length.
""" """
if bint < 0 or index < 0 or bit_len < 0 or value < 0: if bint < 0 or index < 0 or bit_len < 0 or value < 0:
raise ValueError("All input values must be positive integers.") raise ValueError("multi_set -> All input values must be positive integers.")
if bit_length(value) > bit_len: if bit_length(value) > bit_len:
raise ValueError( raise ValueError(
"Bit length of value can not be greater than specified bit length." "multi_set -> Bit length of value can not be greater than specified bit length."
) )
return ((((bint >> (index + bit_len)) << bit_len) | value) << index) | ( return ((((bint >> (index + bit_len)) << bit_len) | value) << index) | (
@ -209,17 +209,19 @@ def multibit_insert(bint: int, index: int, bit_len: int, value: int) -> int:
45 45
>>> multibit_insert(22, 2, 1, 0) >>> multibit_insert(22, 2, 1, 0)
42 42
>>> multibit_insert(22, 2, 0, 0)
22
>>> multibit_insert(22, 2, 1, 3) >>> multibit_insert(22, 2, 1, 3)
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Bit length of value can not be greater than specified bit length. ValueError: multi_insert -> Bit length of value can not be greater than specified bit length.
""" """
if bint < 0 or index < 0 or bit_len < 0 or value < 0: if bint < 0 or index < 0 or bit_len < 0 or value < 0:
raise ValueError("All input values must be positive integers.") raise ValueError("multi_insert -> All input values must be positive integers.")
if bit_length(value) > bit_len: if bit_length(value) > bit_len:
raise ValueError( raise ValueError(
"Bit length of value can not be greater than specified bit length." "multi_insert -> Bit length of value can not be greater than specified bit length."
) )
return ((((bint >> index) << bit_len) | value) << index) | bint & ((1 << index) - 1) return ((((bint >> index) << bit_len) | value) << index) | bint & ((1 << index) - 1)
@ -241,12 +243,13 @@ def multibit_remove(bint: int, index: int, bit_len: int) -> int:
""" """
if bint < 0 or index < 0 or bit_len < 0: if bint < 0 or index < 0 or bit_len < 0:
raise ValueError("All input values must be positive integers.") raise ValueError("multi_remove -> All input values must be positive integers.")
return ((bint >> index + bit_len) << index) | bint & ((1 << index) - 1) return ((bint >> index + bit_len) << index) | bint & ((1 << index) - 1)
if __name__ == "__main__": if __name__ == "__main__":
import doctest import doctest
doctest.testmod() doctest.testmod()