def __add__(self, other: "Float") -> "Float": """ Binary Add 연산 ( + )을 위한 operator overloading exponent를 같은 값으로 만든 후 fraction 덧셈 연산 :param other: Float 타입 가정 :return: 새로운 Float 객체로 return """ exp, a_frac, b_frac = Arithmetic.equalize_exponent(self.exponents, self.fractions, other.exponents, other.fractions) if BitOperation.raw_ge_bits(a_frac, b_frac): sign = self.sign else: sign = other.sign if self.sign ^ other.sign: res, overflow = Arithmetic.sub_bits(a_frac, b_frac, self.fraction_len+1) if sign: res = Arithmetic.decomplement_bits(res, self.fraction_len+1) else: res, overflow = Arithmetic.add_bits(a_frac, b_frac, self.fraction_len+1) if overflow: res.insert(0, overflow) res = res[:-1] exp, _ = Arithmetic.add_bits(exp, BitOperation.num_map['1'], self.exponent_len) first = BitOperation.first_bit_index(res) if first != 0: res, _ = Arithmetic.add_bits(res, BitOperation.num_map['1'], self.fraction_len + 1) exp, _ = Arithmetic.raw_sub_bits(exp, Arithmetic.str_to_integer(str(first), self.exponent_len)) frac = BitOperation.raw_lshift_bits(res, first)[1:] return Float(exp, frac, sign)
def is_zero(self) -> bool: """ 모든 비트가 0인지 확인하는 함수 :return: 모든 비트가 0인지 여부 """ return not self.sign and BitOperation.is_empty(self.exponents) and BitOperation.is_empty(self.fractions)
def raw_div_bits(a: List[Bit], b: List[Bit]) -> List[Bit]: """ 같은 길이의 Bit List를 나누는 ( / ) 함수 left-shift ( << ) 연산과 add ( + ) 연산, lower-equal ( <= ) 연산을 통해 나눗셈 구현 상위 비트부터 하위 비트까지 값을 빼면서 몫을 구함 :param a: / 앞의 Bit List :param b: 나눌 Bit List :return: a / b의 값인 Bit List """ if BitOperation.is_empty(b): raise ZeroDivisionError() remain = BitOperation.empty_bits(len(a)) res = BitOperation.empty_bits(len(a)) one = BitOperation.fit_bits(BitOperation.num_map['1'], len(a)) for i in range(len(a) - 1, -1, -1): first_bit = BitOperation.first_bit_index(b) if first_bit < i: continue div = BitOperation.raw_lshift_bits(b, i) sum_val, overflow = Arithmetic.raw_add_bits(remain, div) if overflow: continue if BitOperation.raw_le_bits(sum_val, a): remain, _ = Arithmetic.raw_add_bits(remain, div) quotient = BitOperation.raw_lshift_bits(one, i) res = BitOperation.raw_or_bits(res, quotient) return res
def complement_bits(a: List[Bit], length: int) -> (List[Bit], Bit): """ Bit List의 2의 보수를 계산 - 연산을 하기 위해 2의 보수 계산 :param a: 2의 보수를 계산하는 Bit List :param length: 원하는 Bit List의 길이 :return: Bit List의 2의 보수 값 """ a = BitOperation.fit_bits(a, length) a = BitOperation.invert_bits(a) return Arithmetic.add_bits(a, [Bit(True)], length)
def __le__(self, other: "Integer") -> bool: """ Low Equal 연산 ( <= )을 위한 operator overloading :param other: Integer 타입 가정 :return: 새로운 Integer 객체로 return """ if self.sign != other.sign: return self.sign == Bit() if self.is_negative(): return BitOperation.le_bits(other.bits, self.bits, self.field_len) return BitOperation.le_bits(self.bits, other.bits, self.field_len)
def decomplement_bits(a: List[Bit], length: int) -> List[Bit]: """ 2의 보수 값을 되돌리는 함수 signed number 값에서 연산 후 2의 보수 값을 되돌리기 위한 함수 :param a: 2의 보수로 표현된 Bit List :param length: 원하는 Bit List의 길이 :return: 2의 보수를 되돌린 Bit List 값 """ a = BitOperation.fit_bits(a, length) a, _ = Arithmetic.add_bits(a, [Bit(True) for _ in range(len(a))], length) return BitOperation.invert_bits(a)
def __init__(self, bits: list or str or int = None, sign: Bit = Bit()): if type(bits) == str: res = self.str_to_int(bits) self.sign = res.sign self.bits = res.bits elif type(bits) == int: self.sign = sign self.bits = BitOperation.empty_bits(self.field_len) self._set(bits) elif type(bits) == list: self.sign = sign self.bits = bits else: self.sign = sign self.bits = BitOperation.empty_bits(self.field_len)
def __or__(self, other: "Integer") -> "Integer": """ Bit OR 연산( | )을 위한 operator overloading :param other: Integer 타입 가정 :return: 새로운 Integer 객체로 return """ return Integer(BitOperation.or_bits(self.bits, other.bits, self.field_len), self.sign | other.sign)
def __and__(self, other: "Integer") -> "Integer": """ Bit And 연산( & )을 위한 operator overloading :param other: Integer 타입 가정 :return: 새로운 Integer 객체로 return """ return Integer(BitOperation.and_bits(self.bits, other.bits, self.field_len), self.sign & other.sign)
def char_to_dec(cls, val: str) -> list: """ character 0-10의 값으로 읽음 :param val: 0-10의 문자열 :return: Integer 객체 """ return BitOperation.fit_bits(BitOperation.num_map[val], cls.field_len)
def val(self) -> int: """ bit 들로 이루어진 값을 int 값으로 읽을 수 있도록 만드는 함수 음수 값이 없으므로 모두 양수 읽는 것처럼 읽 :return: """ return BitOperation.binary_to_decimal(self.bits)
def min_value(cls) -> "UnsignedInteger": """ UnsignedInteger 의 최소값 :return: UnsignedInteger 의 최소값 0 """ min_list = BitOperation.empty_bits(cls.field_len) return UnsignedInteger(min_list)
def raw_mul_bits(a: List[Bit], b: List[Bit]) -> List[Bit]: """ 같은 길이의 Bit List를 곱하는 ( * ) 함수 b Bit List의 값을 하위 비트부터 상위 비트까지 1인 비트가 있을 때마다 a bit를 left-shift하여 더함 :param a: * 앞의 Bit List :param b: 곱할 Bit List :return: a * b의 값인 Bit List """ res = BitOperation.empty_bits(len(a)) for i, bit in enumerate(b[::-1]): if bit: mul2 = BitOperation.raw_lshift_bits(a, i) res, _ = Arithmetic.raw_add_bits(res, mul2) return res
def __xor__(self, other: "UnsignedInteger") -> "UnsignedInteger": """ Bit XOR 연산( ^ )을 위한 operator overloading :param other: UnsignedInteger 타입 가정 :return: 새로운 UnsignedInteger 객체로 return """ return UnsignedInteger(BitOperation.xor_bits(self.bits, other.bits, self.field_len))
def __le__(self, other: "UnsignedInteger") -> bool: """ Low Equal 연산 ( <= )을 위한 operator overloading :param other: UnsignedInteger 타입 가정 :return: 새로운 UnsignedInteger 객체로 return """ return BitOperation.le_bits(self.bits, other.bits, self.field_len)
def __lshift__(self, num: int) -> "Integer": """ num 만큼 left shift ( << ) 연산을 위한 operator overloading :param num: shift 하는 크기 :return: 새로운 Integer 객체로 return """ res, _ = BitOperation.lshift_bits(self.bits, num, self.field_len) return Integer(res)
def __init__(self, bits: list or str = None): if type(bits) == str: res = self.str_to_unsigned_int(bits) self.bits = res.bits elif type(bits) == list: self.bits = bits else: self.bits = BitOperation.empty_bits(self.field_len)
def raw_add_bits(a: List[Bit], b: List[Bit]) -> (List[Bit], Bit): """ 같은 길이의 Bit List를 더하는 ( + ) 함수 덧셈 결과 overflow 되었는지 여부를 함께 return and ( & ) 연산, xor ( ^ ) 연산과 left-shift ( << ) 연산을 통해 덧셈을 구현 :param a: 더할 Bit List :param b: 더할 Bit List :return: a + b의 값인 Bit List, overflow 된 Bit """ if BitOperation.is_empty(b): return a, Bit() carry_0 = BitOperation.raw_and_bits(a, b) remain = BitOperation.raw_xor_bits(a, b) carry = BitOperation.raw_lshift_bits(carry_0, 1) res, overflow = Arithmetic.raw_add_bits(remain, carry) return res, overflow ^ carry_0[0]
def str_to_integer_until_overflow(val: str, length: int) -> (List[Bit], int): """ 문자열을 읽어 overflow가 발생할 때까지 Bit List를 생성하는 함수 :param val: 숫자를 표현하는 정수 문자열 :param length: 원하는 Bit List의 길이 :return: 문자열 실수값에 해당하는 Bit List, 자리수 """ res, ten = BitOperation.equalize_bit_length(BitOperation.num_map['0'], BitOperation.num_map['10'], length) for i, c in enumerate(val): res = Arithmetic.raw_mul_bits(res, ten) res, res2 = Arithmetic.add_bits(res, BitOperation.num_map[c], length) if res2: return res, len(val) - i return res, length - BitOperation.first_bit_index(res) - 1
def shift_fraction(a_exp: List[Bit], b_exp: List[Bit], b_frac: List[Bit]): """ float의 exponent 값 차이만큼 shift 한 fraction 값 연산 right-shift 연산 할 때 생략된 값이 있을 때 1을 더함 :param a_exp: 비교하는 exponent :param b_exp: 비교하는 exponent :param b_frac: shift 연산할 fraction :return: shift 연산 된 fraction """ diff, _ = Arithmetic.raw_sub_bits(a_exp, b_exp) diff = BitOperation.binary_to_decimal(diff) b_fraction = BitOperation.raw_rshift_bits(b_frac, diff) if not BitOperation.is_empty(b_frac[:diff]): b_fraction, _ = Arithmetic.add_bits(b_fraction, BitOperation.num_map['1'], len(b_fraction)) return b_fraction return b_fraction
def mul_bits(a: List[Bit], b: List[Bit], length: int) -> List[Bit]: """ Bit List의 길이를 length로 맞춘 후 값을 곱하는 ( * ) 함수 이진수를 곱하는 함수 raw_mul_bits 함수를 통해 계산 :param a: * 앞의 Bit List :param b: 곱할 Bit List :param length: 원하는 Bit List의 길이 :return: a * b의 값인 Bit List """ a, b = BitOperation.equalize_bit_length(a, b, length) return Arithmetic.raw_mul_bits(a, b)
def val(self) -> int: """ bit 들로 이루어진 값을 int 값으로 읽을 수 있도록 만드는 함수 음수 확인은 signed bit를 통해 확인 테스트 및 출력을 위해 사용하는 함수 :return: int 값으로 리턴 """ res = BitOperation.binary_to_decimal(self.bits) if self.sign: return -res return res
def equalize_exponent(a_exp: List[Bit], a_frac: List[Bit], b_exp: List[Bit], b_frac: List[Bit]): """ 두 float 값의 exponent 값이 같게 만들고 fraction을 조정함 :param a_exp: a의 exponent ( 지수 ) :param a_frac: a의 fraction ( 가수 ) :param b_exp: b의 exponent ( 지수 ) :param b_frac: b의 fraction ( 가수 ) :return: 같은 exponent, exponent에 맞춰 조정된 a의 fraction, exponent에 맞춰 조정된 b의 fraction """ a_frac = BitOperation.fraction_bits(a_frac) b_frac = BitOperation.fraction_bits(b_frac) if BitOperation.raw_ge_bits(a_exp, b_exp): b_frac = Arithmetic.shift_fraction(a_exp, b_exp, b_frac) exp = a_exp else: a_frac = Arithmetic.shift_fraction(b_exp, a_exp, a_frac) exp = b_exp return exp, a_frac, b_frac
def div_bits(a: List[Bit], b: List[Bit], length: int) -> List[Bit]: """ Bit List의 길이를 length로 맞춘 후 값을 나누는 ( / ) 함수 이진수를 나누는 함수 raw_div_bits 함수를 통해 계산 :param a: / 앞의 Bit List :param b: 나눌 Bit List :param length: 원하는 Bit List의 길이 :return: a / b의 값인 Bit List """ a, b = BitOperation.equalize_bit_length(a, b, length) return Arithmetic.raw_div_bits(a, b)
def sub_bits(a: List[Bit], b: List[Bit], length: int) -> (List[Bit], Bit): """ Bit List의 길이를 length로 맞춘 후 값을 빼는 ( - ) 함수 이진수를 빼는 함수 overflow 될 경우 overflow 값을 함께 return raw_sub_bits 함수를 통해 계산 :param a: - 앞의 Bit List :param b: 뺄 Bit List :param length: 원하는 Bit List의 길이 :return: a - b의 값인 Bit List, overflow 된 Bit """ a, b = BitOperation.equalize_bit_length(a, b, length) return Arithmetic.raw_sub_bits(a, b)
def add_bits(a: List[Bit], b: List[Bit], length: int) -> (List[Bit], Bit): """ Bit List의 길이를 length로 맞춘 후 값을 더하는 ( + ) 함수 이진수를 더하는 함수 overflow 될 경우 overflow 값을 함께 return raw_add_bits 함수를 통해 계산 :param a: 더할 Bit List :param b: 더할 Bit List :param length: 원하는 Bit List의 길이 :return: a + b의 값인 Bit List, overflow 된 Bit """ a, b = BitOperation.equalize_bit_length(a, b, length) return Arithmetic.raw_add_bits(a, b)
def str_to_integer(val: str, length: int) -> List[Bit]: """ 문자열을 읽어 Bit List를 생성하는 함수 10진수에서 2진수로 변환하는 함수 :param val: 숫자를 표현하는 정수 문자열 :param length: 원하는 Bit List의 길이 :return: 문자열 숫자에 해당하는 Bit List """ res, ten = BitOperation.equalize_bit_length(BitOperation.num_map['0'], BitOperation.num_map['10'], length) for c in val: res = Arithmetic.raw_mul_bits(res, ten) res, _ = Arithmetic.add_bits(res, BitOperation.num_map[c], length) return res
def str_to_unsigned_int(cls, val: str) -> "UnsignedInteger": """ String 값을 통해 integer 값 read :param val: String 으로 표현된 정수 값 (공백이 없다는 가정) :return: UnsignedInteger 의 값 """ if val[0] == '-': sign = Bit(True) val = val[1:] else: sign = Bit() res = Arithmetic.str_to_integer(val, cls.field_len) res = BitOperation.fit_bits(res, cls.field_len) if sign: res, _ = Arithmetic.complement_bits(res, cls.field_len) return UnsignedInteger(res) return UnsignedInteger(res)
def str_to_int(cls, val: str) -> "Integer": """ String 값을 통해 integer 값 read :param val: String 으로 표현된 정수 값 (공백이 없다는 가정) :return: Integer 의 값 """ if val[0] == '-': sign = Bit(True) val = val[1:] else: sign = Bit() bits = Arithmetic.str_to_integer(val, cls.field_len) if len(bits) > cls.field_len: sign ^= bits[-cls.field_len-1] bits = BitOperation.fit_bits(bits, cls.field_len) return Integer(bits, sign)
def val(self) -> float: """ bit 들로 이루어진 값을 float 값으로 읽을 수 있도록 만드는 함수 음수 확인은 signed bit를 통해 확인 테스트 및 출력을 위해 사용하는 함수 :return: float 값으로 리턴 """ if self.is_zero(): return 0 if self.is_nan(): return float('nan') if self.is_inf(): if self.sign: return -float('inf') return float('inf') res = BitOperation.binary_to_float(self.exponents, self.fractions) if self.sign: return -res return res