【问题标题】:Implementing c binary division in o(1)在 o(1) 中实现 c 二进制除法
【发布时间】:2015-04-28 00:11:02
【问题描述】:

我发现了这个(稍加修改)代码来实现无符号数的除法:

#include <climits>
#include <stdio.h>



unsigned divide(unsigned dividend, unsigned divisor) { 


    unsigned current = 1;
    unsigned answer=0;

    if ( divisor > dividend) 
        return 0;

    if ( divisor == dividend)
        return 1;

    while (divisor <= dividend) {   // this will not work with UINT_MAX
        divisor <<= 1;
        current <<= 1;
    }

    divisor >>= 1;
    current >>= 1;

    while (current!=0) {
        if ( dividend >= divisor) {
            dividend -= divisor;
            answer |= current;
        }
        current >>= 1;
        divisor >>= 1;
    }    
    return answer;
}
int main()
{
    unsigned int x =0;
    x = divide (UINT_MAX,113);
    printf ("%u",x);

    return 0;
}

它适用于“正常”值,但除以最大 unsigned int 值会产生问题;因为它是 Oxffffffff,所以不可能将 divisor 移动到足以使其更大的位置 - 任何进一步的移动都会将除数推到 32 位限制之上并破坏创建无限循环的值。我可以获得有关如何解决此错误的建议吗?甚至可能创建一个硬代码案例?

【问题讨论】:

  • 我不知道如何硬编码这种特殊情况,因为其他数字仍然是一个变量。这仍然是 O(1),因为循环不会执行超过 32 次。
  • 从技术上讲,它会循环数字中的位数。 Big-O 是一种理论结构,因此通常您使用理论数字。所以您的代码通常会被称为O(log(n))。如果您开始考虑“有限范围数”,那么几乎所有算法都是 O(1),这是一个毫无意义的指标。
  • 如果你觉得这本书很有趣,我会推荐这本很棒的书Hacker's Delight

标签: c binary division


【解决方案1】:

代替

while (divisor <= dividend) {   // this will not work with UINT_MAX
    divisor <<= 1;
    current <<= 1;
}

divisor >>= 1;
current >>= 1;

试试

unsigned k = 1 << (sizeof(unsigned) * 8 - 1);
while (((divisor & k) == 0) && ((divisor << 1) <= dividend)) {
    divisor <<= 1;
    current <<= 1;
}

这个想法是,在建议的算法中,divisorcurrent 的最后左移由稍后的右移来补偿。所以我们可以一开始就避免它。

【讨论】:

  • 谢谢!包括特殊情况的解决方案
  • @abd 略微更新为使用1 &lt;&lt; sizeof ...,而不是硬编码的0x80000000
【解决方案2】:

另一种解决方案是使用无符号长整数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-28
    • 2011-05-09
    • 2012-12-22
    • 1970-01-01
    • 2015-04-30
    • 1970-01-01
    • 2010-12-23
    • 1970-01-01
    相关资源
    最近更新 更多