class nBitArray() :
m = 32
f = 'I'
_default_type = None
def __init__(self, n_bit) :
if not (isinstance(n_bit, int) and n_bit > 0) :
raise ValueError
self.n_bit = n_bit
self.n_item = 0
self.b_mask = (2 ** self.n_bit) - 1
self.i_mask = ((0x1 << self.m) - 1)
def _normalize_index(self, index) :
if (-1 * self.n_item) <= index < 0 :
index += self.n_item
if 0 <= index < self.n_item :
return index
raise IndexError
def __getitem__(self, index):
if isinstance(index, int) :
return self._get_at(self._normalize_index(index))
elif isinstance(index, slice) :
return (self._get_at(i) for i in range(* index.indices(self.n_item)))
else:
raise TypeError("index must be int or slice")
def __str__(self) :
u = io.StringIO()
for n, i in enumerate(self._data) :
u.write("{0:08X}".format(i))
u.write('\n' if (n + 1) % 6 == 0 else ' ')
return u.getvalue()
def load_data(self, value_lst) :
""" load a list of n_bit words """
w_curs = 0 # position in the word
word = 0
stack = list()
for n, value in enumerate(value_lst) :
value = value & self.b_mask
v_curs = 0 # position in the value
v_count = self.n_bit - v_curs # number of remaining bits to be written
w_count = self.m - w_curs # number of bits available in the word
while v_count > 0 :
if w_count <= v_count :
p = value >> (v_count - w_count)
word |= p & self.i_mask
v_curs += w_count
w_curs += w_count
else :
p = value << (w_count - v_count)
word |= p & self.i_mask
v_curs += v_count
w_curs += v_count
if w_curs == self.m :
stack.append(word)
word = 0
w_curs = 0
v_count = self.n_bit - v_curs
w_count = self.m - w_curs
if word :
stack.append(word)
self.n_item = len(value_lst)
self._data = array.array(self.f, stack)
return self
def _get_at(self, v_index) :
if not 0 <= v_index < self.n_item :
raise IndexError
b = v_index * self.n_bit
i_index = b // self.m # index of the word
#print(v_index, b, i_index)
v_curs = 0 # position in the value
w_curs = b % self.m # position in the word
v_count = self.n_bit - v_curs # number of remaining bits to append to the value
w_count = self.m - w_curs # number of remaining bits to be read from the word
value = 0
while v_count > 0 :
#print("v curs={0}, count={1} - w curs={2}, count={3}".format(v_curs, v_count, w_curs, w_count))
if w_count <= v_count :
value = (value << self.m) | self._data[i_index]
#print("IF -> value = {0:05X}".format(value & self.b_mask))
v_curs += w_count
w_curs += w_count
else :
value = (value << v_count) | (self._data[i_index] >> (w_count - v_count))
#print("ELSE -> value = {0:05X}".format(value & self.b_mask))
v_curs += v_count
w_curs += v_count
if w_curs == self.m :
i_index += 1
w_curs = 0
v_count = self.n_bit - v_curs
w_count = self.m - w_curs
return value & self.b_mask
if __name__ == '__main__' :
high_res_sinus = [int(math.sin(i) * 0x3FFFFF) & 0x3FFFFF for i in range(10000)]
low_res_sinus = [int(math.sin(i) * 0x3) & 0x3FFFFF for i in range(10000)]
def do(array, name, size) :
data = nBitArray(size).load_data(array)._data.tobytes()
compressed = gzip.compress(data)
print("{3}:{4} bits: {0} -> {1} ({2:0.1f} %)".format(
len(data), len(compressed), 100 * len(compressed) / len(data), name, size)
)
do(high_res_sinus, "high_res_sinus", 22)
do(high_res_sinus, "high_res_sinus", 24)
do(low_res_sinus, "low_res_sinus", 22)
do(low_res_sinus, "low_res_sinus", 24)