def mul(a, b): """ Return the unsigned product of a-arg and b-arg unsigned binary strings. Remark: the product is of the same bit number as the bigger argument so this method is to be used with small numbers to avoid overflows. """ p = '0' a, b = _align(a, b) for bit in reversed(a): if bit == '1': p = basic.sum(p, b) b = basic.shift_left(b) return p
def idiv(a, b, rus_output=False): """ Return tuple of quotient and remainder of a-arg / b-arg as well as boolean indicating whether an error has occured. Remark: a-arg and b-arg are 2s-complement binary strings. Another remark: (here I am using python int variables and binary string variables interchangeably since any one of the former type corresponds to the one of the latter) Let's say q, r = idiv(a, b). Well, while a is indeed equal to q*b + r, q is not necessary a // b and r is not necessary a % b. """ if rus_output: print('Поделим следующие числа в дополнительном коде:') print('a = {0}(2) = {1}(10)'.format( a, bsio.twos_comp_binary_string_to_int(a))) print('b = {0}(2) = {1}(10)\n'.format( b, bsio.twos_comp_binary_string_to_int(b))) if bsio.twos_comp_binary_string_to_int(b) == 0: print('Ошибка: деление на ноль.') raise ZeroDivisionError a, b = _align(a, b) M = b AQ = basic.expand_to_len(a, len(a) * 2) A, Q = AQ[:len(a)], AQ[-len(a):] if rus_output: print('Установим значения регистров A, Q и M:') print('A: {0}'.format(A)) print('Q: {0}'.format(Q)) print('M: {0}\n'.format(M)) print('A:' + ' ' * (len(A) - 2) + ' Q:\n') for _ in range(len(a)): AQ = basic.shift_left(A + Q) A, Q = AQ[:len(a)], AQ[-len(a):] old_A = A if M[0] == A[0]: A = dif(A, M)[0] else: A = basic.sum(A, M)[0] if old_A[0] == A[0] or A == Q == basic.expand_to_len('0', len(A)): Q = Q[:-1] + '1' else: Q = Q[:-1] + '0' A = old_A if rus_output: print('{0} {1}'.format(A, Q)) r = A q = Q if a[0] == b[0] else basic.neg(Q)[0] if rus_output: print('') error_bool = False if basic.neg(Q)[1]: error_bool = True if rus_output: print('Произошло переполнение.') if rus_output: print('Результат деления:\n' + 'q = {0}(2) = {1}(10)\n'.format( q, bsio.twos_comp_binary_string_to_int(q)) + 'r = {0}(2) = {1}(10)'.format( r, bsio.twos_comp_binary_string_to_int(r))) return q, r, error_bool
def __mul__(self, other): """ Return product of two Floats. (a draft; seems to be working with 1 bit error) """ # step 1: account for special cases. # i.e. nans present -> nan # zeros present -> zeros # infs present -> signed inf # # but also (this overrides what's above): # inf * zero -> nan # TODO: step 1. # interstep: setup. sign_one = self.sign_bit exponent_one = self.exponent mantissa_one = self.mantissa sign_two = other.sign_bit exponent_two = other.exponent mantissa_two = other.mantissa prod_sign = '0' if sign_one == sign_two else '1' # step 2: get exponents' sum. # 2a: get it: exponent_sum = basic.sum(exponent_one, exponent_two) exponent_sum = ('0' + ('1' if exponent_sum[1] else '0') + exponent_sum[0]) exponent_sum = basic.sum(exponent_sum, '01')[0] exponent_sum = arth.dif(exponent_sum, '0' + '1' * (EXPONENT_BIT_COUNT - 1))[0] # 2b: check the overflow or the underflow or whatever. # (just whether exponents' sum fits in 8 bits) if set(exponent_sum[:2]) != set('0'): return (self.pos_infinity() if (prod_sign == '0') else self.neg_infinity()) prod_exponent = exponent_sum[2:] # step 3: get mantissas' 48-bit product. # the following line is a bit crappy but it works as it should. prod_mantissa = arth.imul('0' + mantissa_one, '0' + mantissa_two)[2:] # step 4: normalize the result. # (if during normalization exponent goes zero, break the loop) while (prod_mantissa[0] == '0' and prod_exponent != '0' * EXPONENT_BIT_COUNT): prod_mantissa = basic.shift_left(prod_mantissa) # decrementing exponent: prod_exponent = basic.sum(prod_exponent, '11')[0] prod_mantissa = prod_mantissa[:(MANTISSA_BIT_COUNT + 1)] # finally return the result. prod_binary = prod_sign + prod_exponent + prod_mantissa[1:] prod = deepcopy(self) prod.binary = prod_binary return prod
def __truediv__(self, other): """ Return quotient of two Floats. (a draft; seems to be working with 2 bit error) NOTE: denormal numbers are processed as zeros for now. this could be changed but meh. """ # step 1: account for special cases. # (zero implies zero or denormal rn) # i.e. divisor is zero -> error # nans present -> nan # inf / inf -> nan # num / inf = signed zero # TODO: implement step 1. # interstep: setup. sign_one = self.sign_bit exponent_one = self.exponent mantissa_one = self.mantissa sign_two = other.sign_bit exponent_two = other.exponent mantissa_two = other.mantissa q_sign = '0' if sign_one == sign_two else '1' # step 2: calculating the difference of exponents. # 2a: get it. exponent_dif = arth.dif('0' + exponent_one, '0' + exponent_two)[0] exponent_dif = arth.sum(exponent_dif, '0' + '1' * (EXPONENT_BIT_COUNT - 1))[0] # 2b: validate quotient's exponent. # NOTE: I hope this works. if exponent_dif[0] == '1': if binstrings.first_is_bigger(exponent_one, exponent_two): return (self.pos_infinity() if q_sign == '0' else self.neg_infinity()) else: return (self.pos_zero() if q_sign == '0' else self.neg_zero()) q_exponent = exponent_dif[1:] # step 3: divide mantissas. mantissa_one_double = mantissa_one + '0' * MANTISSA_BIT_COUNT q_mantissa = arth.idiv('0' + mantissa_one_double, '0' + mantissa_two)[0][-24:] # step 4: normalize the result. while q_mantissa[0] == '0' and q_exponent != '0' * EXPONENT_BIT_COUNT: q_mantissa = basic.shift_left(q_mantissa) # decrementing exponent: q_exponent = basic.sum(q_exponent, '11')[0] # finally return the result. q_binary = q_sign + q_exponent + q_mantissa[1:] q = deepcopy(self) q.binary = q_binary return q
def __add__(self, other): """ Return sum of two Floats. (works for random big and small pos and neg floats; to be tested w/ special cases; 1 bit error sometimes - dunno why) """ # step 1 (account for special cases): # a. NaNs: if self.is_nan() or other.is_nan(): return Float(float('nan')) # b. two infinities: if self.is_infinity() and other.is_infinity(): if self.sign_bit != other.sign_bit: return self.nan else: return deepcopy(self) # c. one infinity: if self.is_infinity(): return deepcopy(self) elif other.is_infinity(): return deepcopy(other) # d. one or two zeros: if self.is_zero(): return deepcopy(other) elif other.is_zero(): return deepcopy(self) # at this point any of the two arguments is # either normal or denormal # step 2: deconstructing arguments' binaries: bigger, smaller = (self, other) if (self.abs() >= other.abs()) else (other, self) biggers_sign = bigger.sign_bit smallers_sign = smaller.sign_bit biggers_exponent = bigger.exponent smallers_exponent = smaller.exponent biggers_mantissa = bigger.mantissa smallers_mantissa = smaller.mantissa # step 3: aligning the exponents: while biggers_exponent != smallers_exponent: # incrementing exponent of the smaller number and shifting # its mantissa to the right. smallers_exponent = basic.sum(smallers_exponent, '01')[0] smallers_mantissa = basic.logical_shift_right(smallers_mantissa) # if mantissa of the smaller one goes zero, return # the bigger operand copy. if binstrings.is_zero(smallers_mantissa): return deepcopy(bigger) # step 4: getting mantissas' sum and setting up # sum's sign, exponent and mantissa: sum_sign = biggers_sign sum_exponent = biggers_exponent sum_mantissa = (basic.sum(biggers_mantissa, smallers_mantissa) if biggers_sign == smallers_sign else basic.oc_sum( biggers_mantissa, basic.invert_bits(smallers_mantissa))) if (biggers_sign != smallers_sign and sum_mantissa == '1' * (MANTISSA_BIT_COUNT + 1)): sum_mantissa = '0' * MANTISSA_BIT_COUNT # shifting mantissa to fit if neccesary: if type(sum_mantissa) is tuple: if sum_mantissa[1]: sum_mantissa = '1' + sum_mantissa[0][:-1] sum_exponent = basic.sum(sum_exponent, '01')[0] # if exponent overflows, return infinity: if sum_exponent == '1' * EXPONENT_BIT_COUNT: return (Float(float('inf')) if sum_sign == '0' else Float( float('-inf'))) else: sum_mantissa = sum_mantissa[0] # in case sum's mantissa is zero return zero Float. if (binstrings.is_zero(sum_mantissa)): return Float(0.) # step 5: normalize the number if possible. while sum_mantissa[0] == '0': sum_mantissa = basic.shift_left(sum_mantissa) # decrementing exponent: sum_exponent = basic.sum(sum_exponent, '11')[0] if sum_exponent == '0' * EXPONENT_BIT_COUNT: break # TODO: do this the normal way. sum_binary = sum_sign + sum_exponent + sum_mantissa[1:] sum_float = deepcopy(self) sum_float.binary = sum_binary return sum_float