Python二进制乘法。分而治之

时间:2018-02-15 19:33:57

标签: python binary multiplication divide-and-conquer

我需要理解为什么我的代码会给出错误的答案。任务是通过分而治之的方法创建二进制乘法。我找到了一些描述这类问题的论文: wikibooks algorithms UTSC paper (page 4)

这是我的Python代码(3.5.2)

def add(A, B):
    a_str = "".join([str(a) for a in A])
    b_str = "".join([str(b) for b in B])

    bin_a = int(a_str, 2)
    bin_b = int(b_str, 2)

    return [int(a) for a in str(bin(bin_a + bin_b))[2:]]


def add_n(*args):
    if len(args) <= 1:
        return args[0]

    bin_sum = [0]
    for num in args:
        bin_sum = add(bin_sum, num)

    return bin_sum


def shift(A, n):
    if n <= 0:
        return A

    a_str = "".join([str(a) for a in A])

    bin_a = int(a_str, 2)
    bin_a = bin(bin_a << n)
    return [int(a) for a in str(bin_a)[2:]]


def lfill(A, n):
    return [0] * (n - len(A)) + A


def multiply(A, B):
    n = len(A)
    half = n // 2

    if n <= 1:
        return [A[0] * B[0]]

    xl, xh = A[:half], A[half:]
    yl, yh = B[:half], B[half:]

    a = multiply(xh, yh)
    b = multiply(xh, yl)
    c = multiply(xl, yh)
    d = multiply(xl, yl)

    b = add(b, c)
    a = shift(a, n)
    b = shift(b, half)

    return add_n(a, b, d)

有问题的测试1:

A = [1, 1, 1, 1]
B = [0, 1, 0, 0]
result: [1, 1, 1, 1, 0]
real result: [1, 1, 1, 1, 0, 0]

有问题的测试2:

A = [1, 1, 1, 1]
B = [0, 0, 0, 1]
result: [1, 1, 1, 1, 0, 0, 0]
real result: [1, 1, 1, 1]

测试2的值跟踪:

              n half
Before Shift [2, 1]: a: [1] b:[1]
After Shift:         a: [1, 0, 0] b:[1, 0]
Before Shift [2, 1]: a: [0] b:[0]
After Shift:         a: [0] b:[0]
Before Shift [2, 1]: a: [1] b:[1]
After Shift:         a: [1, 0, 0] b:[1, 0]
Before Shift [2, 1]: a: [0] b:[0]
After Shift:         a: [0] b:[0]
Before Shift [4, 2]: a: [1, 1, 0] b:[1, 1, 0]
After Shift:         a: [1, 1, 0, 0, 0, 0, 0] b:[1, 1, 0, 0, 0]

所以,正如你所看到的那样,问题在于零的数量,但是从不确定的情况来看它是不同的。此代码不适用于所有未配对长度的二进制文件,但它不是问题,因为它可以很容易地规范化。

2 个答案:

答案 0 :(得分:0)

正确的乘法函数:

def multiply(A, B):
n = len(A)
half = n // 2

if n <= 1:
    return [A[0] * B[0]]

xl, xh = A[:half], A[half:]
yl, yh = B[:half], B[half:]

a = multiply(xh, yh)
b = multiply(xh, yl)
c = multiply(xl, yh)
d = multiply(xl, yl)

b = add(b, c)

d = shift(d, n)
b = shift(b, half)

return add_n(a, b, d)

答案 1 :(得分:-1)

def divide_conquer_mul(num1 , num2):
    #base Case for Reccursion
    if len(str(num1)) == 1 or len(str(num2)):
        return num1 * num2
    
    #length of the multiplier & multiplicand
    num1 = str(num1)
    num2 = str(num2)
    len_num1 = len(num1)
    len_num2 = len(num2)
    
    # ...and their 'ceil' halves used for combining parts
    nby2 = len_num1//2 + 1 if len_num1 % 2 == 1 else len_num1//2
    mby2 = len_num2//2 + 1 if len_num2 % 2 == 1 else len_num2//2
    
    # halving multiplier and multiplicand into a,b and c,d...this where we are getting the pairs
    #   using 'floor' halves of lengths
    a , b = num1[ : len_num1 // 2] , num1[len_num1 // 2 : ]
    c , d = num2[ : num2 // 2] , num2[num2 // 2 : ]
    
    # recursively multiply ac, ad, bc and bd...this is where we multiply 
        #the pairs form from the step above
    ac , ad = divide_conquer_mul(int(a) , int(c)) , divide_conquer_mul(int(a) , int(d))
    bc , bd = divide_conquer_mul(int(b) , int(c)) , divide_conquer_mul(int(b) , int(d))
    
    # combine adding zeros and return.... this is where summation addition of zeros occur
    summation = ac * 10**(nby2 + mby2)
    summation += ad * 10**(nby2)
    summation += bc * 10**(mby2)
    summation += bd
    
    return summation
    
if __name__ == "__main__": 
    x = divide_conquer_mul(981 , 1234)
    print(x)