简体   繁体   English

整数除法算法分析

[英]Integer Division Algorithm Analysis

For an assignment we are required to write a division algorithm in order to complete a certain question using just addition and recursion. 对于赋值,我们需要编写除法算法,以便仅使用加法和递归来完成某个问题。 I found that, without using tail recursion, the naive repeated subtraction implementation can easily result in a stack overflow. 我发现,在不使用尾递归的情况下,天真的重复减法实现很容易导致堆栈溢出。 So doing a quick analysis of this method, and correct me if I'm wrong, shows that if you divide A by B, with n and m binary digits respectively, it should be exponential in nm. 所以快速分析这个方法,如果我错了就纠正我,这表明如果你将A除以B,分别用n和m二进制数,它应该是以nm为指数。 I actually get 我真的得到了

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

since you need to subtract an m binary digit number from an n binary digit number 2^(nm) times in order to drop the n digit number to an n-1 digit number, and you need to do this nm times to get a number with at most m digits in the repeated subtraction division, so the runtime should be as mentioned. 因为你需要从n个二进制数字2 ^(nm)次中减去一个m二进制数字,以便将n位数字删除到n-1位数字,你需要这样做nm次来得到一个数字在重复减法除法中最多有m个数字,因此运行时应该如上所述。 Again, I very well may be wrong so someone please correct me if I am. 再说一次,我很可能是错的,所以有人请你纠正我,如果我。 This is assuming O(1) addition since I'm working with fixed size integers. 这是假设O(1)加法,因为我正在使用固定大小的整数。 I suppose with fixed size integers one could argue the algorithm is O(1). 我想用固定大小的整数可以说算法是O(1)。

Back to my main question. 回到我的主要问题。 I developed a different method to perform integer division which works much better, even when using it recursively, based on the idea that for 我开发了一种不同的方法来执行整数除法,即使在递归使用它时,它也可以更好地工作,基于for的想法

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

we have 我们有

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

The algorithm goes as follows to caclulate A/B : 该算法如下计算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)

with the restrictions of using only addition, I simply add B to itself on each recursive call, however here is my code without recursion and with the use of shifts instead of addition. 由于仅使用加法的限制,我只是在每次递归调用时将B添加到自身,但是这里是我的代码没有递归并且使用移位而不是添加。

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;
}

I feel that sum |= (1<<i) may be more appropriate in order to emphasize I'm dealing with a binary representation, but it didn't seem to give any performance boost and may make it harder to understand. 我觉得sum |= (1<<i)可能更合适,以强调我正在处理二进制表示,但它似乎没有给任何性能提升并且可能使它更难理解。 So, if M and N are the number of bits in m and n respectively, an analysis suggests the inner loop is performed M - N times and each time the outer loop is completed that m looses one bit, and it must also be completed M - N times in order for the condition m <= n so I get that it's O( (M - N)^2 ). 因此,如果MN分别是mn的位数,则分析表明内循环执行M - N次,每次外循环完成m失去一位,并且它也必须完成M - N为了条件m <= nM - N次,所以我得到它是O((M - N)^ 2)。

So after all of that, I am asking if I am correct about the runtime of the algorithm and whether it can be improved upon? 毕竟,我问我是否对算法的运行时间是否正确以及是否可以对其进行改进?

Your algorithm is pretty good and your analysis of the running time is correct, but you don't need to do the inner loop every time: 您的算法非常好,您对运行时间的分析是正确的,但您不需要每次都执行内部循环:

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;
}

That makes it O(MN) 这使它成为O(MN)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM