Skip to content

Bitarray Library#29

Open
FaridManafov wants to merge 5 commits into
masterfrom
kvsBitarray
Open

Bitarray Library#29
FaridManafov wants to merge 5 commits into
masterfrom
kvsBitarray

Conversation

@FaridManafov

Copy link
Copy Markdown
Collaborator

This is a library that creates a bitarray with a specified size (all set to the value of 0). This has 3 methods where it can setall() for every array index to the parameter (as a bit), set() which sets only one index of the array, and get() to retrieve a value from the array.

This can be typed as well from the research I gathered to make it more explicit, let me know if that should be done.

@FaridManafov FaridManafov self-assigned this Aug 7, 2020
@FaridManafov FaridManafov linked an issue Aug 7, 2020 that may be closed by this pull request
Comment thread bitarray.py
except IndexError:
raise Exception("Set: Value entered is out of range of the array.")
except TypeError:
raise Exception("Set: Enter a value that is an integer")

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to add generic exceptions here

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to just re-raise the same type of exceptions here if you want to add this information. You should also specify which value was incorrect as it's not clear what exactly went wrong from the message alone.

@amackillop amackillop left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work.

Comment thread bitarray.py
for i in range(len(self.arr)):
self.arr[i] = bit
else:
raise Exception("SetAll: Invalid bit entered, only 1 or 0 are valid inputs.")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend raising specific exceptions when it makes sense. This seems to be a ValueError, you can reference the builtin exceptions here: https://docs.python.org/3/library/exceptions.html#ValueError

Comment thread bitarray.py

if bit == 0 or bit == 1:
for i in range(len(self.arr)):
self.arr[i] = bit

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since everything is the same bit, it's probably faster to just do self.arr = [bit] * len(self.arr) again.

Comment thread bitarray.py

def __init__(self, size):
self.arr = [0] * size

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add a__str__ and __repr__ as a good practice. https://docs.python.org/3.8/reference/datamodel.html#object.__str__

Comment thread bitarray.py
except IndexError:
raise Exception("Set: Value entered is out of range of the array.")
except TypeError:
raise Exception("Set: Enter a value that is an integer")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to just re-raise the same type of exceptions here if you want to add this information. You should also specify which value was incorrect as it's not clear what exactly went wrong from the message alone.

Comment thread bitarray.py
except IndexError:
raise Exception("Get: Value entered is out of range of the array.")
except TypeError:
raise Exception("Get: Value entered is not an integer.")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, re-raise the same error. Also I don't think it's necessary to mention which method in the exception message. We will already know that from the stacktrace.

Comment thread bitarray.py


def setall(self, bit):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Knit pick. Remove these empty lines.

@robbassi

robbassi commented Aug 8, 2020

Copy link
Copy Markdown
Owner

Good work, from an API standpoint this looks good, and could be a drop-in replacement for the current bitarray dependency. I put together some notes below on how we could improve this implementation further, and would be good stuff for you to get experience with.

Space Complexity

In this implementation, we represent a bit using a Python int value. Although this is not incorrect, the smallest amount of memory required to represent this would be 1 byte.

For example, let's say we want 1000 bits:

$ b = bitarray(1000)
$ len(bytes(b.arr))
1000

bitarray requires 1 byte per bit. In theory, we should only need 125 bytes to represent 1000 bits in memory. To better understand the issue, let's consider how this looks in memory. We'll use a bit array of 8 bits here to make it easier to follow.

$ b = bitarray(8)
$ len(bytes(b.arr))
8

In memory, b is something like:

b.arr[0] = 00000000
b.arr[1] = 00000000
b.arr[2] = 00000000
b.arr[3] = 00000000
b.arr[4] = 00000000
b.arr[5] = 00000000
b.arr[6] = 00000000
b.arr[7] = 00000000

Now, if we run b.set(3, 1), this would change to:

b.arr[0] = 00000000
b.arr[1] = 00000000
b.arr[2] = 00000000
b.arr[3] = 00000001
b.arr[4] = 00000000
b.arr[5] = 00000000
b.arr[6] = 00000000
b.arr[7] = 00000000

And, if we run b.setall(1), this would change to:

b.arr[0] = 00000001
b.arr[1] = 00000001
b.arr[2] = 00000001
b.arr[3] = 00000001
b.arr[4] = 00000001
b.arr[5] = 00000001
b.arr[6] = 00000001
b.arr[7] = 00000001

We can see here that we have 64 bits in total, but we only ever use 8 bits to represent information; the rest is just padding. It would be nice if we could use all the bits in every byte, so in this case for a bitarray of size 8, we just need 1 byte instead of 8 bytes.

Expected Behaviour

Building off the previous example, here's what we should expect to see:

$ b = bitarray(8)
$ len(bytes(b.arr))
1

We should only need 1 byte to represent 8 bits of data (not including the size of the bitarray object itself). In memory we should see something like:

b.arr[0] = 00000000

Now, if we run b.set(3, 1), this would change to:

b.arr[0] = 00001000 

(Here setting the bit at index 3 is a bitwise operation: b.arr[0] |= (1 << 3).)

If we run b.setall(1), this would change to:

b.arr[0] = 11111111

(Here setting all the bits to 1 is a constant operation: b.arr[0] = 0xFF)

Use array

In Python it can be tricky to use fixed width types, so I would recommend using the array library that comes with Python. With that, you can easily construct a byte array, and enforce the size guarantees we want.

So if we want 1000 bits like in the first example, we could say:

$ arr = array.array('B', [0] * math.ceil(1000/8))
$ len(bytes(arr))
125

And it enforces the size constraints:

$ arr[0] = 255 # OK
$ arr[0] = 256
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: unsigned byte integer is greater than maximum
Note: you will probably have to do some math now to compute the array index in set and get

@yianni yianni added the enhancement New feature or request label Dec 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bitarray

5 participants