/
dirobil
/
playbits
Обзор
Документация
Войти
/
dirobil
/
playbits
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
playbits.py
752 строки
21 KB
dirobil
Add BooleanBits and ByteBits
17 янв 2026, 20:05
17 янв 2026, 20:05
c411a17
Код
Авторство
О чём код?
from decimal import Decimal, getcontext from functools import lru_cache getcontext().prec = 8 class FloatBinary: precision_level = [(8, 23, 32), (11, 52, 64)] def __init__(self, precision = 1) -> None: self.change_precision(precision) def change_precision(self, precision=1): pl = FloatBinary.precision_level if len(pl) < precision: precision = len(pl) elif precision < 1: precision = 1 base = pl[precision-1] self.precision = precision self.len_exp = base[0] self.len_mant = base[1] self.size = base[2] # self.bias = (1 << self.len_exp-1)-1 self.bias = 2**(self.len_exp-1)-1 self.m_max = 2**-self.len_mant self.update_pt(self.size) def update_pt(self, size): if not hasattr(self, "pt"): self.pt = self.gen_power_two(size) else: ln = len(self.pt) if ln < size: self.append_power_two(ln, size) def gen_power_two(self, ln): out = [] for i in range(ln): out.append(2**i) return out def append_power_two(self, start, ln=None): if ln is None: ln = start start = len(self.pt) for i in range(start, start+ln): self.pt.append(2**i) def get_numbers(self, f): sign = 0 d = Decimal(str(f)) if d < 0: sign = 1 d = abs(d) exp_bit_mask = 0 exponent_value = 0 mant_bit_mask = 0 for i in range(self.len_exp-1, -1, -1): exponent = Decimal(2 ** ((exp_bit_mask | self.pt[i]) - self.bias)) if d >= exponent: exp_bit_mask |= self.pt[i] exponent_value = Decimal(2 ** (exp_bit_mask - self.bias)) if not exponent_value == d: for i in range(self.len_mant-1, -1, -1): mantissa = Decimal((mant_bit_mask | self.pt[i]) * self.m_max) mantissa = exponent_value * mantissa + exponent_value if d >= mantissa: mant_bit_mask |= self.pt[i] if abs(d - mantissa) <= abs(d - (exponent_value * Decimal(mant_bit_mask * self.m_max) + exponent_value)): mant_bit_mask += 1 return (sign, exp_bit_mask, mant_bit_mask) def combine_numbers(self, tp): sign, exp, mant = tp res = ((sign << (self.len_exp+self.len_mant)) | (exp << self.len_mant) | mant) return res # @lru_cache(maxsize=128) def float_bit_to_number(self, sign, exponent, mantissa): number = Decimal(mantissa * self.m_max) + Decimal(1) number = number * Decimal(2 ** (exponent - self.bias)) if sign: number = number * Decimal(-1) return number @lru_cache(maxsize=128) def float_from_bits(self, bits): assert len(bits) >= self.size sign = int(bits[0], 2) exp = int(bits[1:self.len_exp+1], 2) mant = int(bits[self.len_exp+1:self.len_exp+self.len_mant+1], 2) return self.float_bit_to_number(sign, exp, mant) @lru_cache(maxsize=128) def float_from_rbits(self, bits): assert len(bits) >= self.size sign = int(bits[-1], 2) exp = int(bits[-(self.len_exp+1):-1], 2) mant = int(bits[-(self.len_exp+self.len_mant+1):-(self.len_exp+1)], 2) return self.float_bit_to_number(sign, exp, mant) @lru_cache(maxsize=128) def float_from_int(self, num): bits = f"{num:b}" if len(bits) < self.size: bits = bits.zfill(self.size) return self.float_from_rbits(bits) @lru_cache(maxsize=128) def float_from_int2(self, num): sign = (num >> (self.len_exp+self.len_mant)) & 1 exp = (num >> self.len_mant) & ((1 << self.len_exp)-1) mant = num & ((1 << self.len_mant)-1) return self.float_bit_to_number(sign, exp, mant) class StringBits: def __init__(self, size: int = 256, chunk_size = 64) -> None: # BigEndian (left to right) self.bits = ["0"] * size self.size = size self.length = 0 self.chunk_size = chunk_size self.float_binary = FloatBinary(2) # self.chunk_count = self.size // self.chunk_size def slice_string(self, start, end): # LitEnd return "".join(self.bits[start:end]) def slice_reverse_string(self, start, end): # BigEnd return "".join(reversed(self.bits[start:end])) def set_pyint(self, num, start=0): bits = f"{num:b}" bits_len = len(bits) total_size = bits_len+start if self.size < total_size: prev_size = self.size while self.size < total_size: self.size *= 2 self.bits += ["0"] * (self.size - prev_size) self.bits[start:bits_len] = reversed(bits) def set_float(self, num, start=0): tp = self.float_binary.get_numbers(num) num = self.float_binary.combine_numbers(tp) bits = f"{num:b}" bits_len = len(bits) total_size = bits_len+start if self.size < total_size: prev_size = self.size while self.size < total_size: self.size *= 2 self.bits += ["0"] * (self.size - prev_size) self.bits[start:bits_len] = reversed(bits) def aligned(self): if len(self.bits) < self.size: ost_length = self.size - len(self.bits) self.bits += ["0"] * ost_length def aligned2(self): if len(self.bits) < self.size: new_bits = ["0"] * self.size new_bits[:len(self.bits)] = self.bits self.bits = new_bits def append_from_bytes(self, bytez: bytes, start = 0): count_bits = len(bytez)*8 total_size = start+count_bits if self.length < total_size: self.length = total_size if self.size < total_size: prev_size = self.size while self.size < total_size: self.size *= 2 self.bits += ["0"] * (self.size - prev_size) i = 0 for byte in bytez: bits = f"{byte:b}" if len(bits) < 8: bits.zfill(8) self.bits[i:i+8] = "".join(reversed(bits)) i += 8 self.aligned() def arr_uint(self): arr = [0] * (self.size // self.chunk_size) index = 0 for i in range(0, self.size, self.chunk_size): arr[index] = int(self.slice_reverse_string(i, i+64), 2) index += 1 return arr def arr_bytes(self): align = 8 arr = bytearray([0] * (self.size // align)) index = 0 for i in range(0, self.size, align): arr[index] = int(self.slice_reverse_string(i, i+align), 2) index += 1 return arr def arr_int(self): arr = [0] * (self.size // self.chunk_size) index = 0 full = (1 << self.chunk_size) half = (full >> 1) - 1 for i in range(0, self.size, self.chunk_size): num = int(self.slice_reverse_string(i, i+64), 2) if num > half: num -= full arr[index] = num index += 1 return arr def arr_float(self): float_size = self.float_binary.size arr = [None] * (self.size // float_size) index = 0 for i in range(0, self.size, float_size): arr[index] = self.float_binary.float_from_bits(self.slice_reverse_string(i, i+float_size)) index += 1 return arr def _and(self, string_bits): num = self.to_bigint() & string_bits.to_bigint() return self.op_impl(num) def _or(self, string_bits): num = self.to_bigint() | string_bits.to_bigint() return self.op_impl(num) def _xor(self, string_bits): num = self.to_bigint() ^ string_bits.to_bigint() return self.op_impl(num) def _plus(self, string_bits): num = self.to_bigint() + string_bits.to_bigint() return self.op_impl(num) def _minus(self, string_bits): num = self.to_bigint() - string_bits.to_bigint() return self.op_impl(num) def _multiply(self, string_bits): num = self.to_bigint() * string_bits.to_bigint() return self.op_impl(num) def _divide(self, string_bits): num = self.to_bigint() // string_bits.to_bigint() return self.op_impl(num) def op_impl(self, num): bits = f"{num:b}" size = 256 bits_len = len(bits) while size < bits_len: size *= 2 new_bits = StringBits(size) new_bits.bits[0:bits_len] = reversed(bits) return new_bits def to_hex(self): return hex(self.to_bigint()) def to_string(self): # LE return self.slice_string(0, self.size) def to_reverse_string(self): # BE return self.slice_reverse_string(0, self.size) def to_read_string(self, encoding="utf-8"): return self.arr_bytes().decode(encoding, errors="ignore") def to_bigint(self): return int(self.slice_reverse_string(0, self.size), 2) def toggle_bit(self, index): if index > self.size: return if self.bits[index] == "0": self.bits[index] = "1" else: self.bits[index] = "0" def fill(self): self.bits = ["1"] * self.size def clear(self): self.bits = ["0"] * self.size class BooleanBits: def __init__(self, size: int = 256, chunk_size = 64) -> None: self.bits = [0] * size self.size = size self.length = 0 self.chunk_size = chunk_size self.float_binary = FloatBinary(2) def slice_to_string(self, start, end): return map(str, self.bits[start:end]) def slice_to_int(self, start, end): bn = 1 number = 0 for bit in self.bits[start:end]: if bit: number |= bn bn <<= 1 return number def slice_reverse_to_int(self, start, end): bn = 1 number = 0 for bit in reversed(self.bits[start:end]): if bit: number |= bn bn <<= 1 return number def slice_string(self, start, end): return "".join(self.slice_to_string(start, end)) def slice_reverse_string(self, start, end): return "".join(reversed(self.slice_to_string(start, end))) def set_pyint(self, num, start=0): bn = 1 index = 0 while bn <= num: self.bits[index+start] = int((num & bn == bn)) bn <<= 1 index += 1 def set_float(self, num, start=0): tp = self.float_binary.get_numbers(num) num = self.float_binary.combine_numbers(tp) bits_len = self.float_binary.size total_size = bits_len + start if self.size < total_size: prev_size = self.size while self.size < total_size: self.size *= 2 self.bits += [0] * (self.size - prev_size) self.set_pyint(num, start) def aligned(self): if len(self.bits) < self.size: ost_length = self.size - len(self.bits) self.bits += [0] * ost_length def arr_uint(self): arr = [0] * (self.size // self.chunk_size) index = 0 for i in range(0, self.size, self.chunk_size): arr[index] = self.slice_to_int(i, i+self.chunk_size) index += 1 return arr def arr_int(self): arr = [0] * (self.size // self.chunk_size) index = 0 full = (1 << self.chunk_size) half = (full >> 1) - 1 for i in range(0, self.size, self.chunk_size): num = self.slice_to_int(i, i+self.chunk_size) if num > half: num -= full arr[index] = num index += 1 return arr def arr_float(self): float_size = self.float_binary.size arr = [None] * (self.size // float_size) index = 0 for i in range(0, self.size, float_size): arr[index] = self.float_binary.float_from_int2(self.slice_to_int(i, i+float_size)) index += 1 return arr def arr_bytes(self): align = 8 arr = bytearray([0] * (self.size // align)) index = 0 for i in range(0, self.size, align): arr[index] = self.slice_to_int(i, i+align) index += 1 return arr def append_from_bytes(self, bytez: bytes, start=0): count_bits = len(bytez)*8 total_size = start+count_bits if self.length < total_size: self.length = total_size if self.size < total_size: prev_size = self.size while self.size < total_size: self.size *= 2 self.bits += [0] * (self.size - prev_size) i = 0 for byte in bytez: self.set_pyint(byte, i+start) i += 8 self.aligned() def _and(self, boolean_bits): num = self.to_bigint() & boolean_bits.to_bigint() return self.op_impl(num) def _or(self, boolean_bits): num = self.to_bigint() | boolean_bits.to_bigint() return self.op_impl(num) def _xor(self, boolean_bits): num = self.to_bigint() ^ boolean_bits.to_bigint() return self.op_impl(num) def _plus(self, boolean_bits): num = self.to_bigint() + boolean_bits.to_bigint() return self.op_impl(num) def _minus(self, boolean_bits): num = self.to_bigint() - boolean_bits.to_bigint() return self.op_impl(num) def _multiply(self, boolean_bits): num = self.to_bigint() * boolean_bits.to_bigint() return self.op_impl(num) def _divide(self, boolean_bits): num = self.to_bigint() // boolean_bits.to_bigint() return self.op_impl(num) def op_impl(self, num): size = 256 bits_len = 0 bit = 1 while bit < num: bit <<= 1 bits_len += 1 while size < bits_len: size *= 2 new_bits = BooleanBits(size) new_bits.set_pyint(num) return new_bits def to_string(self): return self.slice_string(0, self.size) def to_read_string(self, encoding="utf-8"): return self.arr_bytes().decode(encoding, errors="ignore") def to_hex(self): return hex(self.to_bigint()) def to_bigint(self): num = 0 for i in range(self.size): num |= self.bits[i] << i return num def toggle_bit(self, index): if index > self.size: return if self.bits[index] == 0: self.bits[index] = 1 else: self.bits[index] = 0 def fill(self): self.bits = [1] * self.size def clear(self): self.bits = [0] * self.size class ByteBits: def __init__(self, size: int = 256) -> None: self.size = size self.arrbyte = bytearray([0] * (self.size//8)) self.length = 0 self.float_binary = FloatBinary(2) def slice_to_int(self, start, end): num = 0 shift = 0 for byte in self.arrbyte[start:end]: num |= byte << shift shift += 8 return num def expand(self, sized): if self.size < sized: prev_size = self.size while self.size < sized: self.size *= 2 self.arrbyte.extend([0] * ((self.size - prev_size)//8)) def aligned(self): bits_len = len(self.arrbyte)*8 if bits_len < self.size: ost_length = (self.size - bits_len)//8 self.arrbyte.extend([0] * ost_length) def set_pyint(self, num, start=0): bits = [] while num: bit = num & 1 bits.append(bit) num >>= 1 self.implication_bits(bits, start) def set_pyint2(self, num, start=0): while num: bit = num & 1 self.implication_bit(start, bit) num >>= 1 start += 1 def set_pyint3(self, num, start=0): index_byte = start // 8 num <<= start % 8 mask = (1 << 8) - 1 while num: byte = num & mask self.arrbyte[index_byte] = self._iset(self.arrbyte[index_byte], byte) num >>= 8 index_byte += 1 def set_float(self, num, start=0): tp = self.float_binary.get_numbers(num) num = self.float_binary.combine_numbers(tp) self.set_pyint(num, start) def arr_bytes(self): return self.arrbyte.copy() def arr_int(self): arr = [0] * (self.size // 8) index = 0 full = (1 << 8) half = (full >> 1) - 1 for byte in self.arrbyte: if byte > half: byte -= full arr[index] = byte index += 1 return arr def arr_uint(self): arr = [0] * (self.size // 8) index = 0 for byte in self.arrbyte: arr[index] = byte index += 1 return arr def arr_float(self): float_size = self.float_binary.size align = float_size // 8 arr = [None] * (self.size // float_size) index = 0 for i in range(0, self.size//8, align): arr[index] = self.float_binary.float_from_int2(self.bytes_to_num(self.arrbyte[i:i+align])) index += 1 return arr def append_from_bytes(self, bytez: bytes, start=0): num = self.bytes_to_num(bytez) self.set_pyint(num, start) def append_from_bytes2(self, bytez: bytes, start=0): self.expand(len(bytez)*8 + start) for byte in bytez: self.set_pyint3(byte, start) start += 8 def _and(self, byte_bits): num = self.to_bigint() & byte_bits.to_bigint() return self.op_impl(num) def _or(self, byte_bits): num = self.to_bigint() | byte_bits.to_bigint() return self.op_impl(num) def _xor(self, byte_bits): num = self.to_bigint() ^ byte_bits.to_bigint() return self.op_impl(num) def _plus(self, byte_bits): num = self.to_bigint() + byte_bits.to_bigint() return self.op_impl(num) def _minus(self, byte_bits): num = self.to_bigint() - byte_bits.to_bigint() return self.op_impl(num) def _multiply(self, byte_bits): num = self.to_bigint() * byte_bits.to_bigint() return self.op_impl(num) def _divide(self, byte_bits): num = self.to_bigint() // byte_bits.to_bigint() return self.op_impl(num) def op_impl(self, num): bytez = self.num_to_bytes(num) size = 256 bits_len = len(bytez)*8 while size < bits_len: size *= 2 new_bits = ByteBits(size) new_bits.append_from_bytes(bytez) return new_bits def _not(self, bit): return 0 if bit > 0 else 1 def _inv(self, num): return num ^ (1 << num.bit_length())-1 def _iset(self, a, b): if a <= b: return b c = b.bit_length() return a >> c << c | b def num_to_bytes(self, num: int): ba = bytearray() mask = (1 << 8) - 1 while num: ba.append(num & mask) num >>= 8 return ba def bytes_to_num(self, bytez): num = 0 shift = 0 for byte in bytez: num |= byte << shift shift += 8 return num def to_bigint(self): num = 0 shift = 0 for byte in self.arrbyte: num |= byte << shift shift += 8 return num def to_string(self): return "".join(format(byte, "08b") for byte in self.arrbyte) def to_read_string(self, encoding="utf-8"): return self.arrbyte.decode(encoding, errors="ignore") def to_hex(self): return hex(self.to_bigint()) def toggle_bit(self, index): self.expand(index) index_byte = 0 if index > 8: index_byte = index // 8 self.arrbyte[index_byte] ^= (1 << index % 8) def implication_bit(self, index, b1): self.expand(index) index_byte = index // 8 shift = 1 << index % 8 b2 = self.arrbyte[index_byte] & shift c = b1 ^ b2 if c: self.arrbyte[index_byte] ^= shift def implication_bits(self, bits, start): self.expand(len(bits) + start) index_byte = start // 8 indexed = start % 8 shift = 1 << indexed for b1 in bits: b2 = self.arrbyte[index_byte] & shift c = b1 ^ b2 if c: self.arrbyte[index_byte] ^= shift indexed += 1 shift <<= 1 if indexed >= 8: indexed = 0 shift = 1 index_byte += 1 def fill(self): self.arrbyte = bytearray([1] * (self.size//8)) def clear(self): self.arrbyte = bytearray([0] * (self.size//8))