<jupyter_start><jupyter_text>This notebook was prepared by [<NAME>](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges).  Solution Notebook  Problem: Implement common bit manipulation operations: get_bit, set_bit, clear_bit, clear_bits_msb_to_index, clear_bits_msb_to_lsb, update_bit.* [Constraints](Constraints)* [Test Cases](Test-Cases)* [Algorithm](Algorithm)* [Code](Code)* [Unit Test](Unit-Test)  Constraints* Can we assume the inputs are valid?    * No* Can we assume this fits memory?    * Yes  Test Cases* None as a number input -> Exception* Negative index -> Exception get_bit    number   = 0b10001110, index = 3    expected = True set_bit    number   = 0b10001110, index = 4    expected = 0b10011110 clear_bit    number   = 0b10001110, index = 3    expected = 0b10000110 clear_bits_msb_to_index    number   = 0b10001110, index = 3    expected = 0b00000110 clear_bits_index_to_lsb    number   = 0b10001110, index = 3    expected = 0b10000000 update_bit    number   = 0b10001110, index = 3, value = 1    expected = 0b10001110    number   = 0b10001110, index = 3, value = 0    expected = 0b10000110    number   = 0b10001110, index = 0, value = 1    expected = 0b10001111  Algorithm get_bitindices  7 6 5 4  3 2 1 0  index = 3--------------------------------------------------input    1 0 0 0  1 1 1 0  0b10001110mask     0 0 0 0  1 0 0 0  1 << index--------------------------------------------------result   0 0 0 0  1 0 0 0  number & mask != 0Complexity:* Time: O(n)* Space: O(n) set_bitindices  7 6 5 4  3 2 1 0  index = 4--------------------------------------------------input    1 0 0 0  1 1 1 0  0b10001110mask     0 0 0 1  0 0 0 0  1 << index--------------------------------------------------result   1 0 0 1  1 1 1 0  number | maskComplexity:* Time: O(n)* Space: O(n) clear_bitindices  7 6 5 4  3 2 1 0  index = 3--------------------------------------------------input    1 0 0 0  1 1 1 0  0b10001110mask     0 0 0 0  1 0 0 0  1 << indexmask     1 1 1 1  0 1 1 1  ~(1 << index)--------------------------------------------------result   1 0 0 0  0 1 1 0  number & maskComplexity:* Time: O(n)* Space: O(n) clear_bits_msb_to_indexindices  7 6 5 4  3 2 1 0  index = 3--------------------------------------------------input    1 0 0 0  1 1 1 0  0b10001110mask     0 0 0 0  1 0 0 0  1 << indexmask     0 0 0 0  0 1 1 1  (1 << index) - 1--------------------------------------------------result   0 0 0 0  0 1 1 1  number & maskComplexity:* Time: O(n)* Space: O(n) clear_bits_index_to_lsbindices  7 6 5 4  3 2 1 0  index = 3--------------------------------------------------input    1 0 0 0  1 1 1 0  0b10001110mask     0 0 0 1  0 0 0 0  1 << index + 1mask     0 0 0 0  1 1 1 1  (1 << index + 1) - 1mask     1 1 1 1  0 0 0 0  ~((1 << index + 1) - 1)--------------------------------------------------result   1 0 0 0  0 0 0 0  number & maskComplexity:* Time: O(n)* Space: O(n) update_bit* Use `get_bit` to see if the value is already set or cleared* If not, use `set_bit` if setting the value or `clear_bit` if clearing the valueComplexity:* Time: O(n)* Space: O(n)  Code<jupyter_code>def validate_index(func):
    def validate_index_wrapper(self, *args, **kwargs):
        for arg in args:
            if arg < 0:
                raise IndexError('Invalid index')
        return func(self, *args, **kwargs)
    return validate_index_wrapper
class Bit(object):

    def __init__(self, number):
        if number is None:
            raise TypeError('number cannot be None')
        self.number = number

    @validate_index
    def get_bit(self, index):
        mask = 1 << index
        return self.number & mask != 0

    @validate_index
    def set_bit(self, index):
        mask = 1 << index
        self.number |= mask
        return self.number

    @validate_index
    def clear_bit(self, index):
        mask = ~(1 << index)
        self.number &= mask
        return self.number

    @validate_index
    def clear_bits_msb_to_index(self, index):
        mask = (1 << index) - 1
        self.number &= mask
        return self.number

    @validate_index
    def clear_bits_index_to_lsb(self, index):
        mask = ~((1 << index + 1) - 1)
        self.number &= mask
        return self.number

    @validate_index
    def update_bit(self, index, value):
        if value is None or value not in (0, 1):
            raise Exception('Invalid value')
        if self.get_bit(index) == value:
            return self.number
        if value:
            self.set_bit(index)
        else:
            self.clear_bit(index)
        return self.number<jupyter_output><empty_output><jupyter_text>Unit Test<jupyter_code>%%writefile test_bit.py
import unittest


class TestBit(unittest.TestCase):

    def test_bit(self):
        number = int('10001110', base=2)
        bit = Bit(number)
        self.assertEqual(bit.get_bit(index=3), True)
        expected = int('10011110', base=2)
        self.assertEqual(bit.set_bit(index=4), expected)
        bit = Bit(number)
        expected = int('10000110', base=2)
        self.assertEqual(bit.clear_bit(index=3), expected)
        bit = Bit(number)
        expected = int('00000110', base=2)
        self.assertEqual(bit.clear_bits_msb_to_index(index=3), expected)
        bit = Bit(number)
        expected = int('10000000', base=2)
        self.assertEqual(bit.clear_bits_index_to_lsb(index=3), expected)
        bit = Bit(number)
        self.assertEqual(bit.update_bit(index=3, value=1), number)
        bit = Bit(number)
        expected = int('10000110', base=2)
        self.assertEqual(bit.update_bit(index=3, value=0), expected)
        bit = Bit(number)
        expected = int('10001111', base=2)
        self.assertEqual(bit.update_bit(index=0, value=1), expected)
        print('Success: test_bit')


def main():
    test = TestBit()
    test.test_bit()


if __name__ == '__main__':
    main()
%run -i test_bit.py<jupyter_output>Success: test_bit
{'fraction_non_alphanumeric': 0.17587185049224094, 'fraction_numerical': 0.08176205573168698, 'mean_word_length': 1.977645305514158, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 11, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '49355', 'license': 'Apache-2.0', 'n_tokens_mistral': 2195, 'n_tokens_neox': 1838, 'n_words': 624, 'path': 'bit_manipulation/bit/bit_solution.ipynb', 'repo_name': 'keivanzavari/interactive-coding-challenges', 'size': '5999'}