Karatsuba乘法实现

时间:2017-02-19 06:40:00

标签: python algorithm recursion karatsuba

我最近实施了Karatsuba Multiplication作为个人练习。我在pseudocode provided on wikipedia之后用Python编写了我的实现:

procedure karatsuba(num1, num2)
if (num1 < 10) or (num2 < 10)
    return num1*num2
  /* calculates the size of the numbers */
  m = max(size_base10(num1), size_base10(num2))
  m2 = m/2
  /* split the digit sequences about the middle */
  high1, low1 = split_at(num1, m2)
  high2, low2 = split_at(num2, m2)
  /* 3 calls made to numbers approximately half the size */
  z0 = karatsuba(low1, low2)
  z1 = karatsuba((low1+high1), (low2+high2))
  z2 = karatsuba(high1, high2)
  return (z2*10^(2*m2)) + ((z1-z2-z0)*10^(m2)) + (z0)

这是我的python实现:

def karat(x,y):
    if len(str(x)) == 1 or len(str(y)) == 1:
        return x*y
    else:
        m = max(len(str(x)),len(str(y)))
        m2 = m / 2

        a = x / 10**(m2)
        b = x % 10**(m2)
        c = y / 10**(m2)
        d = y % 10**(m2)

        z0 = karat(b,d)
        z1 = karat((a+b),(c+d))
        z2 = karat(a,c)

        return (z2 * 10**(2*m2)) + ((z1 - z2 - z0) * 10**(m2)) + (z0)

我的问题是关于z0z1z2的最终合并。
z2 移位 m 位数(其中 m 是两个相乘数字中最大的数字的长度)。
算法使用* 10 ^(2 * m2)*而不是简单地乘以 10 ^(m),而 m2 m / 2

我尝试用 m 替换 2 * m2 ,结果不正确。我认为这与数字如何分裂有关,但我不确定是怎么回事。

7 个答案:

答案 0 :(得分:7)

根据您的Python版本,您必须或应该使用显式的分区运算符/替换//,这是适当的;它向下舍入,确保你的指数保持整数。

这对于将操作数分成高位(按楼层除以10^m2)和低位(通过取残差模10^m2)这一点非常重要。这对于小数{{{ 1}}。

它还解释了为什么m2不一定等于2 * (x // 2),而是x,如果x是奇数。 在算法的最后一行x-1是正确的,因为您正在做的是将2 m2a归为零。

如果您使用较旧的Python版本,则代码可能仍然有效,因为c在应用于整数时曾被解释为分层。

/

答案 1 :(得分:2)

我实现了相同的想法但我限制为2位乘法作为基本情况,因为我可以减少函数中的浮点乘法

import math

def multiply(x,y):
    sx= str(x)
    sy= str(y)
    nx= len(sx)
    ny= len(sy)
    if ny<=2 or nx<=2:
        r = int(x)*int(y)
        return r
    n = nx
    if nx>ny:
        sy = sy.rjust(nx,"0")
        n=nx
    elif ny>nx:
        sx = sx.rjust(ny,"0")
        n=ny
    m = n%2
    offset = 0
    if m != 0:
        n+=1
        offset = 1
    floor = int(math.floor(n/2)) - offset
    a = sx[0:floor]
    b = sx[floor:n]
    c = sy[0:floor]
    d = sy[floor:n]
    print(a,b,c,d)

    ac = multiply(a,c)
    bd = multiply(b,d)

    ad_bc = multiply((int(a)+int(b)),(int(c)+int(d)))-ac-bd
    r = ((10**n)*ac)+((10**(n/2))*ad_bc)+bd

    return r

print(multiply(4,5))
print(multiply(4,58779))
print(int(multiply(4872139874092183,5977098709879)))
print(int(4872139874092183*5977098709879))
print(int(multiply(4872349085723098457,597340985723098475)))
print(int(4872349085723098457*597340985723098475))
print(int(multiply(4908347590823749,97098709870985)))
print(int(4908347590823749*97098709870985))

答案 2 :(得分:1)

  

我尝试用m替换2 * m2并得到不正确的结果。我认为这与数字如何分裂有关,但我不确定发生了什么。

这就是你如何分割递归调用的数字的核心。 如果您选择使用奇数n,那么n//2将向下舍入到最接近的整数,这意味着您的第二个数字的长度为floor(n/2),您必须填写第一个使用floor(n/2)零。 由于我们对两个数字使用相同的n,因此这适用于两者。这意味着如果您坚持最后一步的原始奇数n,那么您将使用原始n零填充第一个术语,而不是第一个术语由第一个组合填充的零个数。填充加上第二个填充(floor(n/2)*2

答案 3 :(得分:0)

您的代码和逻辑是正确的,基本情况只是问题。由于根据算法a,b,c,d是2位数字,因此您应该修改基本情况,并在基本情况下将x和y的长度保持等于2。

答案 4 :(得分:0)

我认为最好使用LD_LIBRARY_PATH函数来计算位数而不是转换为字符串,例如

unsets

答案 5 :(得分:0)

您已将m2用作浮点数。它必须是整数。

def karat(x,y):
    if len(str(x)) == 1 or len(str(y)) == 1:
        return x*y
    else:
        m = max(len(str(x)),len(str(y)))
        m2 = m // 2

        a = x // 10**(m2)
        b = x % 10**(m2)
        c = y // 10**(m2)
        d = y % 10**(m2)

        z0 = karat(b,d)
        z1 = karat((a+b),(c+d))
        z2 = karat(a,c)

        return (z2 * 10**(2*m2)) + ((z1 - z2 - z0) * 10**(m2)) + (z0)

答案 6 :(得分:-1)

基本情况ERROR: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VISIBLE, CONSTRAINT `fk_CUSTOMER_BARBER` FOREIGN KEY (`BARBER_ID`) REF' at line 12 SQL Code: -- ----------------------------------------------------- -- Table `barberDB`.`CUSTOMER` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `barberDB`.`CUSTOMER` ( `ID` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(45) NULL, `isHaircut` INT NULL, `isBeard` INT NULL, `isEyebrows` INT NULL, `BARBER_ID` INT NOT NULL, PRIMARY KEY (`ID`), INDEX `fk_CUSTOMER_BARBER_idx` (`BARBER_ID` ASC) VISIBLE, CONSTRAINT `fk_CUSTOMER_BARBER` FOREIGN KEY (`BARBER_ID`) REFERENCES `barberDB`.`BARBER` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE = InnoDB SQL script execution finished: statements: 6 succeeded, 1 failed Fetching back view definitions in final form. Nothing to fetch 不正确。如果您针对大整数运行答案中给出的任何python代码,则if len(str(x)) == 1 or len(str(y)) == 1: return x*y函数将不会产生正确的答案。

要使代码正确,您需要将基本情况更改为karat()

下面是Paul Panzer的答案的修改后的实现,它正确地将大整数相乘。

if len(str(x) < 3 or len(str(y)) < 3: return x*y