【问题标题】:Multiplying with divide and conquer乘以分而治之
【发布时间】:2014-12-12 15:43:12
【问题描述】:

下面我已将代码发布到 ruby​​ 中的非工作“分而治之”乘法方法(带有调试打印)。我不知道它的代码是否损坏,或者是 Ruby 中的一个怪癖,比如 L-shift(

是代码损坏(与原始算法不匹配)还是意外行为?

Pseudo code for original algorithm

def multiply(x,y,n, level)
    #print "Level #{level}\n"
    if n == 1
        #print "\tx[#{x.to_s(2)}][#{y.to_s(2)}]\n\n"
        return x*y
    end
    mask = 2**n - 2**(n/2)

    xl = x >> (n / 2)
    xr = x & ~mask
    yl = y >> (n / 2)
    yr = y & ~mask


    print "  #{n} | x =  #{x.to_s(2)} = L[#{xl.to_s(2)}][#{xr.to_s(2)}]R \n"
    print "  #{n} | y =  #{y.to_s(2)} = L[#{yl.to_s(2)}][#{yr.to_s(2)}]R \n"
    #print "\t[#{xl.to_s(2)}][#{yr.to_s(2)}]\n"
    #print "\t[#{xr.to_s(2)}][#{yr.to_s(2)}]\n"
    #print "\t([#{xl.to_s(2)}]+[#{xr.to_s(2)}])([#{yl.to_s(2)}]+[#{yr.to_s(2)}])\n\n"

    p1 = multiply(  xl,     yl,     n/2,    level+1)
    p2 = multiply(  xr,     yr,     n/2,    level+1)
    p3 = multiply(  xl+xr,  yl+yr,  n/2,    level+1)

    return p1 * 2**n + (p3 - p1 - p2) * 2**(n/2) + p2
end


x = 21
y = 22
print "x = #{x} = #{x.to_s(2)}\n"
print "y = #{y} = #{y.to_s(2)}\n"

print "\nDC_multiply\t#{x}*#{y} = #{multiply(x,y,8, 1)} \nregular\t#{x}*#{y} = #{x*y}\n\n "

【问题讨论】:

  • 我在你的代码中没有看到<< ...
  • 正确,因为它只是将东西向左(永远)移动,所以我做了一个面具并从上半部分“和”
  • 你的代码输出了大量的调试数据。预期的输出/行为是什么?
  • 最终是应该做乘法。该算法是递归的,因此它通过调用堆栈创建了一个类似树的“模式”,这也可以通过位数(n)和每个x和y的右/左拆分来看出。
  • 当然可以,但是调试输出与 C++ 实现有何不同?

标签: ruby divide-and-conquer multiplication


【解决方案1】:

我不熟悉 分而治之的算法,但我认为它不包含您在 Ruby 中无法做到的部分。

这是一个快速的尝试:

def multiplb(a,b)
  #Break recursion when a or b has one digit
  if a < 10 || b < 10
    a * b
  else
    #Max number of digits of a and b
    n = [a.to_s.length, b.to_s.length].max

    # Steps to split numbers to high and low digits sub-numbers
    # (1) to_s.split('') => Converting digits to string then arrays to ease splitting numbers digits 
    # (2) each_slice => Splitting both numbers to high(left) and low(right) digits groups
    # (3) to_a , map, join, to_i => Simply returning digits to numbers
    al, ar = a.to_s.split('').each_slice(n/2).to_a.map(&:join).map(&:to_i)
    bl, br = b.to_s.split('').each_slice(n/2).to_a.map(&:join).map(&:to_i) 

    #Recursion
    p1 = multiplb(al, bl)
    p2 = multiplb(al + ar, bl + br)
    p3 = multiplb(ar, br)

    p1 * (10**n) + (p2 - p1 - p3) * (10**(n/2)) + p3
  end

end
#Test
puts multiplb(1980, 2315)
# => 4583700  yeah that's correct :)

这里有一些参考资料可以进一步解释部分代码:

  1. 求最大数 => How do you find a min / max with Ruby?

  2. 将数组分成两半 => Splitting an array into equal parts in ruby

  3. 将fixnum转为数组 => Turning long fixed number to array Ruby

希望对你有帮助!

【讨论】:

  • 哦,对了。是的,这不起作用,但这就是问题所在。 if a.to_s.length == 1 || b.to_s.length == 1 a * b 因为 p2 可以有一个进位位。我的没有抓住进位并将其移开。我想正确的方法是检查 to_s(2) 长度以获得 n。
  • p1 * (10**n) + (p2 - p1 - p3) * (10**(n/2)) + p3 非常完美,谢谢
猜你喜欢
  • 2012-03-04
  • 2020-05-02
  • 2018-07-26
  • 2020-04-11
  • 2017-12-05
  • 1970-01-01
  • 2013-11-09
  • 2019-08-02
  • 2017-07-16
相关资源
最近更新 更多