def add_two_numbers(operand1, operand2, mode='same'): ''' Parameters ---------- operand1 : np.dnarray. 1-dimension. operand2 : np.dnarray. 1-dimension. This should have the same dimension as operand2. Returns ------- result : np.dnarray. 1-dimension. The result of addtion. n_carries : int. The number of carries occurred while addition. ''' operand_digits = operand1.shape[0] result_digits = get_result_digits(operand_digits, 'add', mode='fit') result = np.zeros((result_digits), dtype=config.np_type()) carry = 0 n_carries = 0 for i in range(1, operand_digits + 1): (carry, digit_result) = add_two_digits(operand1[-i], operand2[-i], carry) n_carries = n_carries + carry result[-i] = digit_result if i == (operand_digits): # Last digit result[-(i + 1)] = carry # Concatenate in front of the array. if mode == 'same': final_result_digits = get_result_digits(operand_digits, 'add', mode='same') leading_zeros = np.zeros((final_result_digits - result_digits), dtype=config.np_type()) result = np.concatenate((leading_zeros, result)) return (result, n_carries)
def multiply_two_numbers(operand1, operand2, mode='same'): ''' Parameters ---------- operand1 : np.ndarray. 1-dimension. shape==(operand_digits). operand2 : np.ndarray. 1-dimension. shape==(operand_digits). Returns ------- result : np.ndarray. result = operand1 - operand2. 1-D. shape==(operand_digits). n_carries : int. The number of carries that occurred while multiplication. ''' operand_digits = operand1.shape[0] result_digits = get_result_digits(operand_digits, 'multiply', mode='fit') result = np.zeros((result_digits), dtype=config.np_type()) # To return carry_buffer = np.zeros( (result_digits), dtype=config.np_type()) # To save carries while addition # The multiplying phase multiply_result_to_sum = np.zeros((operand_digits, result_digits), dtype=config.np_type()) for i in range(operand_digits): if operand2[-(i + 1)] == 1: start_index = (result_digits - operand_digits - i) end_index = (result_digits - i) multiply_result_to_sum[i, start_index:end_index] = operand1 # The summation and carrying phase n_carries = 0 # total carries in one multiplication operation. for i in range(1, result_digits + 1): digit_wise_sum = np.sum(multiply_result_to_sum[:, -i]) + carry_buffer[-i] carry, remainder = divmod(digit_wise_sum, 2) n_carries = n_carries + carry if i < result_digits: # except the last digit carry_buffer[-(i + 1)] = carry result[-i] = remainder # Concatenate in front of the array. if mode == 'same': final_result_digits = get_result_digits(operand_digits, 'multiply', mode='same') leading_zeros = np.zeros((final_result_digits - result_digits), dtype=config.np_type()) result = np.concatenate((leading_zeros, result)) return (result, n_carries)
def modulo_two_numbers(operand1, operand2, mode='same'): ''' Parameters ---------- operand1 : np.ndarray. 1-dimension. shape==(operand_digits). operand2 : np.ndarray. 1-dimension. shape==(operand_digits). - operand2 must not be zero. Returns ------- result : np.ndarray. result = operand1 % operand2. 1-D. shape==(operand_digits). n_carries : int. The number of carries that occurred while multiplication. remainder : np.ndarray. shape==(operand_digits). ''' operand_digits = operand1.shape[0] result_digits = get_result_digits(operand_digits, 'modulo', mode='fit') _, n_carries, result = divide_two_numbers(operand1, operand2) # Concatenate in front of the array. if mode == 'same': final_result_digits = get_result_digits(operand_digits, 'modulo', mode='same') leading_zeros = np.zeros((final_result_digits - result_digits), dtype=config.np_type()) result = np.concatenate((leading_zeros, result)) return (result, n_carries)
def subtract_two_numbers(operand1, operand2, mode='same'): ''' Parameters ---------- operand1 : np.ndarray. 1-dimension. shape==(operand_digits). operand2 : np.ndarray. 1-dimension. shape==(operand_digits). - Always operand1 >= operand2. Returns ------- result : np.ndarray. result = operand1 - operand2. 1-D. shape==(operand_digits). - Beacuse operand1 >= operand2, result >= 0. n_carries : int. The number of carries that occurred while subtraction. ''' operand_digits = operand1.shape[0] result_digits = get_result_digits(operand_digits, 'subtract', mode='fit') cp_operand1 = np.copy(operand1) cp_operand2 = np.copy(operand2) result = np.zeros((result_digits), dtype=config.np_type()) n_carries = 0 for i in range(1, operand_digits + 1): if cp_operand1[-i] >= cp_operand2[-i]: result[-i] = cp_operand1[-i] - cp_operand2[-i] else: for j in range(i + 1, operand_digits + 1): n_carries = n_carries + 1 if cp_operand1[-j] == 1: cp_operand1[-j] = 0 for k in range(i + 1, j): cp_operand1[-k] = 1 break result[-i] = 1 # Concatenate in front of the array. if mode == 'same': final_result_digits = get_result_digits(operand_digits, 'subtract', mode='same') leading_zeros = np.zeros((final_result_digits - result_digits), dtype=config.np_type()) result = np.concatenate((leading_zeros, result)) return (result, n_carries)
def get_np_bin(str_bin, np_bin_digits): ''' Parameters ---------- str_bin Return ------ np_bin: numpy.ndarry. binary number. The smaller index, the higher digit. ''' assert str_bin[0] != '-' np_bin = np.zeros((np_bin_digits), dtype=config.np_type()) # Should be initialized as 0. for i in range(1, len(str_bin) + 1): np_bin[-i] = int(str_bin[-i]) return np_bin
def generate_random_datasets(operand_digits): ''' Parameters ---------- operand_digits: int. the number of the digits of an operand. Returns ------- zero_output_dataset: dict. - zero_output_dataset['input']: numpy.ndarray. shape == (n_operations, operand_digits * 2). - zero_output_dataset['output']: numpy.ndarray. shape == (n_operations, result_digits). one_output_dataset: dict. - one_output_dataset['input']: numpy.ndarray. shape == (n_operations, operand_digits * 2). - one_output_dataset['output']: numpy.ndarray. shape == (n_operations, result_digits). random_output_dataset: dict. - random_output_dataset['input']: numpy.ndarray. shape == (n_operations, operand_digits * 2). - random_output_dataset['output']: numpy.ndarray. shape == (n_operations, result_digits). ''' zero_output_dataset = {'input': list(), 'output': list()} one_output_dataset = {'input': list(), 'output': list()} fixed_random_output_dataset = {'input': list(), 'output': list()} random_output_dataset = {'input': list(), 'output': list()} result_digits = get_result_digits(operand_digits, 'add', mode='same') # Get a fixed numpy.ndarray binary random integer. np_bin_fixed_rand_output = get_np_bin( get_str_bin(np.random.randint(2**result_digits)), result_digits).reshape(1, -1) for dec_op1 in range(2**operand_digits): for dec_op2 in range(2**operand_digits): # Get numpy.ndarray binary operands. np_bin_op1 = get_np_bin(get_str_bin(dec_op1), operand_digits) np_bin_op2 = get_np_bin(get_str_bin(dec_op2), operand_digits) # Get a numpy.ndarray binary random integer. np_bin_rand_output = get_np_bin( get_str_bin(np.random.randint(2**result_digits)), result_digits).reshape(1, -1) # Append the input of addition. input = np.concatenate((np_bin_op1, np_bin_op2)).reshape(1, -1) zero_output_dataset['input'].append(input) one_output_dataset['input'].append(input) fixed_random_output_dataset['input'].append(input) random_output_dataset['input'].append(input) # Append the output of addition. zero_output_dataset['output'].append( np.zeros((1, result_digits), dtype=config.np_type())) one_output_dataset['output'].append( np.ones((1, result_digits), dtype=config.np_type())) fixed_random_output_dataset['output'].append( np_bin_fixed_rand_output) random_output_dataset['output'].append(np_bin_rand_output) # List to one numpy.ndarray zero_output_dataset['input'] = np.concatenate(zero_output_dataset['input'], axis=0) zero_output_dataset['output'] = np.concatenate( zero_output_dataset['output'], axis=0) one_output_dataset['input'] = np.concatenate(one_output_dataset['input'], axis=0) one_output_dataset['output'] = np.concatenate(one_output_dataset['output'], axis=0) fixed_random_output_dataset['input'] = np.concatenate( fixed_random_output_dataset['input'], axis=0) fixed_random_output_dataset['output'] = np.concatenate( fixed_random_output_dataset['output'], axis=0) random_output_dataset['input'] = np.concatenate( random_output_dataset['input'], axis=0) random_output_dataset['output'] = np.concatenate( random_output_dataset['output'], axis=0) # Shuffle the pairs of input and output of op_dataset. zero_output_dataset['input'], zero_output_dataset[ 'output'] = shuffle_io_pairs(zero_output_dataset['input'], zero_output_dataset['output']) one_output_dataset['input'], one_output_dataset[ 'output'] = shuffle_io_pairs(one_output_dataset['input'], one_output_dataset['output']) fixed_random_output_dataset['input'], fixed_random_output_dataset[ 'output'] = shuffle_io_pairs(fixed_random_output_dataset['input'], fixed_random_output_dataset['output']) random_output_dataset['input'], random_output_dataset[ 'output'] = shuffle_io_pairs(random_output_dataset['input'], random_output_dataset['output']) return zero_output_dataset, one_output_dataset, fixed_random_output_dataset, random_output_dataset
def divide_two_numbers(operand1, operand2, mode='same'): ''' Parameters ---------- operand1 : np.ndarray. 1-dimension. shape==(operand_digits). operand2 : np.ndarray. 1-dimension. shape==(operand_digits). - operand2 must not be zero. Returns ------- result : np.ndarray. result = operand1 // operand2. 1-D. shape==(operand_digits) n_carries : int. The number of carries that occurred while multiplication. remainder : np.ndarray. shape==(operand_digits). ''' operand_digits = operand1.shape[0] result_digits = get_result_digits(operand_digits, 'divide', mode='fit') result = np.zeros((result_digits), dtype=config.np_type()) leading_zeros = get_leading_zeros(operand2) valid_operand2_digits = operand_digits - leading_zeros division_steps = operand_digits - valid_operand2_digits + 1 n_total_carries = 0 for i in range(division_steps): division_index = valid_operand2_digits + i - 1 division_range = division_index + 1 # Assignment: local_divide_operand1 local_divide_operand1 = np.zeros((division_range), dtype=config.np_type()) if i == 0: local_divide_operand1 = operand1[:division_range] else: local_divide_operand1[:division_index] = local_subtract_result local_divide_operand1[division_index] = operand1[division_index] # Assignment: local_divide_operand2 local_divide_operand2 = np.zeros((division_range), dtype=config.np_type()) local_divide_operand2[-valid_operand2_digits:] = operand2[ -valid_operand2_digits:] #local_divide_operand2[-division_range:] = operand2[-division_range:] # Division: If condition. less_than # Subtraction: Get a remainder if less_than(local_divide_operand1, local_divide_operand2): result[division_index] = 0 # Division result local_subtract_result = np.copy( local_divide_operand1[:division_range]) # Get the remainder n_carries = 0 else: result[division_index] = 1 # Division result local_subtract_result, n_carries = subtract_two_numbers( local_divide_operand1, local_divide_operand2, mode='fit') # Get the remainder n_total_carries = n_total_carries + n_carries remainder = local_subtract_result # Concatenate in front of the array. if mode == 'same': final_result_digits = get_result_digits(operand_digits, 'divide', mode='same') leading_zeros = np.zeros((final_result_digits - result_digits), dtype=config.np_type()) result = np.concatenate((leading_zeros, result)) return (result, n_carries, remainder)