Ruby中的Karatsuba乘法优化 - 失败

时间:2016-04-27 21:48:37

标签: ruby algorithm math

乘以2个N位数,其中N是偶数。 multiply(1234,5678)返回7006652,这是正确的产品。 #multiply_opt在传递相同的参数时应该返回相同的值,但它不会。

任何想法总是非常受欢迎!

def multiply(x, y)
  return x * y if x.to_s.length <= 1 && y.to_s.length <= 1

  n = x.to_s.length

  x_mid = x.to_s.length / 2
  y_mid = y.to_s.length / 2

  a = x.to_s[0..x_mid-1].to_i
  b = x.to_s[x_mid..-1].to_i
  c = y.to_s[0..y_mid-1].to_i
  d = y.to_s[y_mid..-1].to_i

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

  ((10**n) * ac) + (10**(n/2) * (ad + bc)) + bd
end

def multiply_opt(x, y)
  # Not sure if this base case is correct...
  return x * y if x.to_s.length <= 1 || y.to_s.length <= 1

  # Not sure exactly how to define n
  n = [x.to_s.length, y.to_s.length].max

  x_mid = x.to_s.length / 2
  y_mid = y.to_s.length / 2

  a = x.to_s[0..x_mid-1].to_i
  b = x.to_s[x_mid..-1].to_i
  c = y.to_s[0..y_mid-1].to_i
  d = y.to_s[y_mid..-1].to_i

  # Recursive Calls
  s1 = multiply_opt(a,c)
  s2 = multiply_opt(b,d)
  s3 = multiply_opt((a + b),(b + d))
  s4 = s3 - s1 - s2

  (10**n)*s1 + (10**(n/2)* s4) + s2
end

1 个答案:

答案 0 :(得分:1)

您的问题是您定义了单独的x_midy_mid,这是错误的。并且分裂必须发生在相同的地方,即n/2,从较低的数字看。

你的例子失败的地方是第3次乘法,因为那里的操作数有2位和3位数。拆分应该分开最后一位数字。使用您的方法,3位数字被分为1和2位数,这是错误的。

更多详细信息: Karatsuba首先将您的号码拆分为

x = x1*M+x0
y = y1*M+y0

使产品

x*y = x1*y1*M^2+((x1+x0)*(y1+y0)-x1*y1-x0*y0)*M + x0*y0

可以使用较小数字的三次乘法来计算。热门使用M=B^k,其数字基数为B,因此x0y0包含k和{{1}的最低x位数}}

在您的示例中,您必须决定始终使用yk=1,通过Karatsuba的设计,人们会要求k=2,这意味着x,y<M^2

考虑到这些想法,您的算法应该修改为

k=2

应该相应地修改第一种方法中的分裂和重建语句。