def dif(a, b, rus_output=False): """ Return the difference between a-arg and b-arg 2s-complement binary strings. """ a, b = _align(a, b) nb = basic.neg(b) if rus_output: print(('Считаем разность следующих чисел в дополнительном коде:\n' '{0}(2) = {1}(10)\n' '{2}(2) = {3}(10)\n').format( a, bsio.twos_comp_binary_string_to_int(a), b, bsio.twos_comp_binary_string_to_int(b))) print('Она соответствует сумме первого ' 'и отрицания второго, поэтому...') print(('Отрицание второго числа:\n{0}, ошибка {1}.\n').format( nb[0], 'есть' if nb[1] else 'отсутствует')) c = sum(a, nb[0], rus_output) if rus_output: print('Результат разности соответствует ' 'результату суммы в дополнительном коде.') return c
def int_to_twos_comp_binary_string(n, bits=constants.DEF_BIT_NUM): """ Return 2s-complement binary string of the n-arg's value and bits-arg bits. """ # accounting for '-128'-like numbers: if n == -(2**(bits - 1)): return '1' + '0'*(bits - 1) s = '' # accounting for possible negative numbers: pos = True if n < 0: pos = False n *= -1 # writing bits: for _ in range(bits - 1): bit = n % 2 n //= 2 s = str(bit) + s s = '0' + s # pos / neg: if pos: return s else: return basic.neg(s)[0]
def imul(m, r, rus_output=False): """ Return the product of m-arg and r-arg interpreting them as 2s-complement binary strings. Remark: the Booth's algorithm is used (https://en.wikipedia.org/wiki/Booth%27s_multiplication_algorithm). """ if rus_output: print('Перемножим следующие числа в дополнительном коде ' 'по алгоритму Бута:') print('m = {0}(2) = {1}(10)'.format( m, bsio.twos_comp_binary_string_to_int(m))) print('r = {0}(2) = {1}(10)\n'.format( r, bsio.twos_comp_binary_string_to_int(r))) x = len(m) y = len(r) m = m[0] + m A = m + (y + 1) * '0' S = basic.neg(m)[0] + (y + 1) * '0' P = '0' + x * '0' + r + '0' if rus_output: print('Установим значения регистров A, S и P:\n' + 'A = {0} {1} {2} {3}\n'.format(A[0], A[1:(x + 1)], A[ (x + 1):(x + y + 1)], A[-1]) + 'S = {0} {1} {2} {3}\n'.format(S[0], S[1:(x + 1)], S[ (x + 1):(x + y + 1)], S[-1]) + 'P = {0} {1} {2} {3}\n'.format(P[0], P[1:(x + 1)], P[ (x + 1):(x + y + 1)], P[-1])) if rus_output: print('P:') for _ in range(y): two_last_bits_of_p = P[-2:] if two_last_bits_of_p == '01': P = basic.sum(A, P)[0] elif two_last_bits_of_p == '10': P = basic.sum(S, P)[0] P = basic.arithmetic_shift_right(P) if rus_output: print('{0} {1} {2} {3}'.format(P[0], P[1:(x + 1)], P[(x + 1):(x + y + 1)], P[-1])) if rus_output: print('\nОтбрасываем крайние биты. Результат умножения:\n' + 'm * r = {0}(2) = {1}(10)'.format( P[1:-1], bsio.twos_comp_binary_string_to_int(P[1:-1]))) return P[1:-1]
def twos_comp_binary_string_to_int(s): """ Return the python integer-type value of the s-arg 2s-complement binary string. """ pos = True if s[0] == '1': pos = False s = basic.neg(s)[0] n = 0 for bit in s: if bit != '0' and bit != '1': continue n = n*2 + (1 if bit == '1' else 0) return n if pos else -n
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