我最近实施了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)
我的问题是关于z0
,z1
和z2
的最终合并。
z2 移位 m 位数(其中 m 是两个相乘数字中最大的数字的长度)。
算法使用* 10 ^(2 * m2)*而不是简单地乘以 10 ^(m),而 m2 m / 2 。
我尝试用 m 替换 2 * m2 ,结果不正确。我认为这与数字如何分裂有关,但我不确定是怎么回事。
答案 0 :(得分:7)
根据您的Python版本,您必须或应该使用显式的分区运算符/
替换//
,这是适当的;它向下舍入,确保你的指数保持整数。
这对于将操作数分成高位(按楼层除以10^m2
)和低位(通过取残差模10^m2
)这一点非常重要。这对于小数{{{ 1}}。
它还解释了为什么m2
不一定等于2 * (x // 2)
,而是x
,如果x是奇数。
在算法的最后一行x-1
是正确的,因为您正在做的是将2 m2
和a
归为零。
如果您使用较旧的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