整数除法算法分析

时间:2015-12-24 20:21:40

标签: c algorithm runtime

对于赋值,我们需要编写除法算法,以便仅使用加法和递归来完成某个问题。我发现,在不使用尾递归的情况下,天真的重复减法实现很容易导致堆栈溢出。所以快速分析这个方法,如果我错了就纠正我,这表明如果你将A除以B,分别用n和m二进制数,它应该是n-m的指数。我实际上得到了

O( (n-m)*2^(n-m) ) 

因为你需要从n个二进制数字2 ^(nm)次中减去一个m二进制数字,以便将n位数字删除到n-1位数字,你需要这样做nm次在重复的减法除法中得到一个最多m位的数字,所以运行时应该如上所述。再说一次,我很可能是错的,所以有人请你纠正我,如果我。 这是假设O(1)添加 ,因为我正在使用固定大小的整数。我想用固定大小的整数可以说算法是O(1)。

回到我的主要问题。我开发了一种不同的方法来执行整数除法,即使在递归使用它时也能更好地工作,基于

的想法

P = 2^(k_i) + ... 2^(K_0)

我们有

A/B = (A - B*P)/B + P

算法如下:caclulate A/B

input:
    A, B

    i) Set Q = 0

   ii) Find the largest K such that B * 2^K <= A < B * 2(K + 1)

  iii) Q -> Q + 2^K

   iv) A -> A - B * 2^k

    v) Repeat steps ii) through iv) until A <= B

   vi) Return Q  (and A if you want the remainder)

由于仅使用了加法的限制,我只是在每次递归调用时将B添加到自身,但是这里是我的代码,没有递归,而是使用shift而不是添加。

int div( unsigned int m, unsigned int n )
{
    // q is a temporary n, sum is the quotient
    unsigned int q, sum = 0;
    int i;

    while( m > n )
    {
         i = 0;
         q = n;

         // double q until it's larger than m and record the exponent
         while( q <= m )
         {
              q <<= 1;
              ++i;
         }

         i--;
         q >>= 1;         // q is one factor of 2 too large
         sum += (1<<i);   // add one bit of the quotient
         m -= q;          // new numerator
    }

    return sum;
}

我认为sum |= (1<<i)可能更合适,以强调我正在处理二进制表示,但它似乎没有给任何性能提升,并且可能使其更难理解。因此,如果MN分别是mn中的位数,则分析表明内循环执行M - N次,每次外部循环完成m失去一位,并且必须完成M - N次以便条件m <= n所以我得到它是O((M - N)^ 2)。

所有这些之后,我问我是否正确算法的运行时间以及是否可以对其进行改进?

1 个答案:

答案 0 :(得分:5)

您的算法非常好,您对运行时间的分析是正确的,但您不需要每次都进行内循环:

unsigned div(unsigned num, unsigned den)
{
    //TODO check for divide by zero
    unsigned place=1;
    unsigned ret=0;
    while((num>>1) >= den) //overflow-safe check
    {
        place<<=1;
        den<<=1;
    }
    for( ;place>0; place>>=1,den>>=1)
    {
       if (num>=den)
       {
           num-=den;
           ret+=place;
       }
    }
    return ret;
}

这使得O(M-N)