【问题标题】:Python Binary Multiplication. Divide and ConquerPython二进制乘法。分而治之
【发布时间】:2018-07-26 15:57:58
【问题描述】:

我需要了解为什么我的代码给出了错误的答案。任务是通过分治法创建二进制乘法。我发现了一些描述此类问题的论文: 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。实际上,因为这个算法是递归的,所以它有很多不同的值。我使用的是 Debug,但似乎问题出在算法本身。
  • 因为我认为这是作业,我不会给你解决方案,但我会给你这个指针:考虑 MSB/LSB。哪些位是哪些?
  • 哇,我发现了错误。谢谢。

标签: python binary multiplication divide-and-conquer


【解决方案1】:

正确的乘法函数:

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)

【讨论】:

  • 我没有检查您的解决方案,但我想它会生成正确的结果,但是,它有非常奇怪的变量名称,因为 xlyl 包含高位和 xhyh 包含低位。我认为更好的解决方案是将(在原始实现中)'xl, xh = A[:half], A[half:]` 更改为xh, xl = A[:half], A[half:]yl, yhB。即,我刚刚颠倒了xlxh
【解决方案2】:
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)

【讨论】:

  • 请解释一下你的代码在做什么!代码是answering a question 帮助提问者的一个重要方面,但比显示有效解决方案更重要的是解释您如何修复它。这可以帮助人们将来分析和解决同样的问题,如果他们也遇到同样的问题,也可以帮助提问者理解为什么你的解决方案有效。
  • 它通过使用分而治之方法将两个数字相乘,例如 981 , 1234 它是如何工作的?假设我们有 (981) * (1234) 首先检查整数的长度 09* 12 = --- 81*34= ---
猜你喜欢
  • 2012-03-04
  • 2014-12-12
  • 2017-07-16
  • 2020-05-02
  • 1970-01-01
  • 2020-04-11
  • 2017-12-05
  • 2019-08-02
  • 2016-03-11
相关资源
最近更新 更多