分割算法

时间:2014-01-15 22:34:27

标签: algorithm division

我刚刚开始设计分析和算法课程,我们从简单的算法开始。

有一种我无法理解的除法算法。

  

功能除(x,)      输入:2个整数x和y,其中y> = 1      输出:x的除数和余数除以y

  if x=0: return (q,r)=(0,0)
   (q,r)=divide(floor (x/2), y)
   q=2q, r=2r

   if x is odd: r=r+1
   if r>=y: r=r-y, q=q+1
   return(q,r)

   * floor is lower bound

我们应该尝试这个算法110011%101(二进制值)...我尝试了一些东西,我得到了一个奇怪的答案...转换成十进制值,这是错误的。

所以我尝试使用简单的十进制值而不是二进制优先。

x=25, y=5

This is what I'm doing

1st: q=x,r= 12,5
2nd: q=x,r= 6,5
3rd: q=x,r= 3,5
4th: q=x,r= 1,5
5th: q=x,r= 0,5

这件事怎么样?每次我运行它,最后一个x的最后一个值将是0(条件)它将停止并返回q = 0,r = 0

有人可以指导我出错的地方......

由于

3 个答案:

答案 0 :(得分:2)

我在Ruby中实现了你的算法(在arg列表中有明显的修正):

$ irb
irb(main):001:0> def div(x,y)
irb(main):002:1>   return [0,0] if x == 0
irb(main):003:1>   q,r = div(x >> 1, y)
irb(main):004:1>   q *= 2
irb(main):005:1>   r *= 2
irb(main):006:1>   r += 1 if x & 1 == 1
irb(main):007:1>   if r >= y
irb(main):008:2>     r -= y
irb(main):009:2>     q += 1
irb(main):010:2>   end
irb(main):011:1>   [q,r]
irb(main):012:1> end
=> nil
irb(main):013:0> div(25, 5)
=> [5, 0]
irb(main):014:0> div(25, 2)
=> [12, 1]
irb(main):015:0> div(144,12)
=> [12, 0]
irb(main):016:0> div(144,11)
=> [13, 1]

它正在工作,因此当您尝试手动跟踪时,您不能正确跟踪递归。我发现在每张递归调用的新纸上写出逻辑并将旧纸张放在一堆先前的调用之上是有帮助的。当我在当前工作表上找到一个return语句时,将其抛弃,扔掉它,然后在堆栈顶部的纸上写下返回值代替递归调用。继续使用此工作表上的逻辑,直到您进入另一个递归调用或返回。继续重复这个,直到你的纸张用完为止 - 最后一张纸的回报是最后的答案。

答案 1 :(得分:1)

该函数具有递归结构,这可能就是为什么它有点棘手。我假设你的函数声明中有一个拼写错误,其中divide(x,)应该除(x,y)。鉴于期望的结果是x / y和余数,让我们继续。函数定义中的第一行声称如果分子为0,则返回0,余数为0.这是有道理的:当b!= 0且a = 0时,a / b = 0表示所有整数。然后我们将结果设置为递归调用,原始分子的一半和当前分母。在某些时候,“原始分子的一半”变为0并且达到基本情况。在每个递归调用结束时有一些计算似乎是尾递归。因为我们在每个深度上除以2,所以乘以2得到原始结果,如果它是奇数,则将余数加1。单独在文本中进行可视化很难,因此在具有给定问题的纸上逐步进行。

在数学上,除法算法(称之为)表示当输入25,5时,余数必须小于或等于5。

算法给出0,5。这可能意味着当商为0或者需要检查余数的大小时不考虑余数。

function divide(x,) Input: 2 integers x and y where y>=1 Output: quotient and remainder of x divided by y

  if x=0: return (q,r)=(0,0)
   (q,r)=divide(floor (x/2), y)
   q=2q, r=2r

   if x is odd: r=r+1
   if r>=y: r=r-y, q=q+1
   return(q,r)

   * floor is lower bound

答案 2 :(得分:1)

如果我没记错的话,这是在简单的ALU中进行积分除法的最基本方法之一。这很好,因为你可以并行运行所有的递归分区,因为每个分区都只基于二进制的一小部分。

要了解这是做什么的,只需在纸上进行,就像Chris Zhang所说的那样。这是divide(25,5)的样子:

(x,y)=(25,5)
    divide(12, 5)
        divide(6,5)
            divide(3,5)
                divide(1,5)
                    divide(0,5) // x = 0!
                    return(0,0)
                (q,r)=(2*0,2*0)
                x is odd, so (q,r)=(0,1)
                r < y
                return(0,1)
            (q,r)=(2*0,2*1)
            x is odd, so (q,r)=(0,3)
            r < y
            return(0,3)
        (q,r)=(2*0,2*3)
        x is even
        r >= y, so (q,r)=(1,1)
        return(1,1)
    (q,r)=(2*1,2*1)
    x is even
    r < y
    return(2,2)
(q,r)=(2*2,2*2)
x is odd, so (q,r)=(4,5)
r >= y, so (q,r)=(5,0)
return(5,0)

正如你所看到的,它有效 - 它给你aq为5和r为0.你注意到的部分,你总是最终有一个0项是Chris正确称之为“基本情况” - 使递归调用展开的情况。

此算法适用于除法和乘法的任何基数。它使用与以下相同的原理:“123/5 =(100 + 20 + 3)/ 5 = 20 + 4 + r3 = 24r3”,只是以二进制形式完成。