Esempio n. 1
0
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)
Esempio n. 2
0
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)
Esempio n. 3
0
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)
Esempio n. 4
0
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)
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
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)