除以2和天花板直到1

时间:2013-02-27 13:08:24

标签: math complexity-theory logarithm

仅针对自然数具有以下算法: rounds(n)= {1,如果n = 1; 1 +轮(ceil(n / 2)),否则} 所以用编程语言写这将是

int rounds(int n){
    if(n==1)
        return 1;
    return 1+rounds(ceil(n/2));
}

我认为这有时间复杂度O(log n)

是否有更好的复杂性?

2 个答案:

答案 0 :(得分:1)

如果你认为算法是迭代的并且数字是二进制的,那么这个函数会移出最低位,如果它是一个被移出的1,则将数字增加1。因此,除了增量之外,它计算数字中的位数(即,最高位置1)。增量最终会将结果增加1,除非数字的形式为1000 ....因此,您获得的位数加1,或者如果数字是2的幂,则获得位数。根据您的机器型号,计算速度可能比O(log n)更快。

答案 1 :(得分:1)

首先列出1向上的结果,

rounds(1) = 1
rounds(2) = 1 + rounds(2/2) = 1 + 1 = 2

接下来,当ceil(n/2)为2时,rounds(n)将为3.这是n = 3n = 4

rounds(3) = rounds(4) = 3

然后,当ceil(n/2)为3或4时,结果为4. 3 <= ceil(n/2) <= 4当且仅当2*3-1 <= n <= 2*4发生时,

round(5) = ... = rounds(8) = 4

继续,你可以看到

rounds(n) = k+2 if 2^k < n <= 2^(k+1)

通过归纳。

您可以将其重写为

rounds(n) = 2 + floor(log_2(n-1)) if n > 1 [and rounds(1) = 1]

并且在数学上,您还可以通过将其重写为

来统一处理n = 1
rounds(n) = 1 + floor(log_2(2*n-1))

如果使用固定宽度类型,最后一个公式可能会溢出。

所以问题是

  • 您可以多快将数字与1进行比较,
  • 你能以多快的速度从数字中减去1,
  • 你能以多快的速度计算一个正整数的基数为2的对数(

对于固定宽度类型,因此是一个有界范围,所有这些当然是O(1)操作,但是你可能仍然有兴趣使其尽可能高效,即使计算复杂性没有进入游戏。

对于本机类型 - intlong通常是 - 比较和减去整数是非常快的机器指令,因此唯一可能存在问题的是基数2对数。

许多处理器都有一个机器指令来计算机器类型值中的前导0位,如果编译器可以访问它,您将获得基本2对数的非常快速的实现。如果没有,您可以使用one of the classic bit-hacks获得比递归更快的版本。

例如,gcc和clang的最新版本具有__builtin_clz(对于64位类型,分别为__builtin_clzl),如果该指令存在,则映射到bsr*指令如果处理器没有提供处理器,那么可能是一个很好的实现,使用一些bit-twiddling。

版本

unsigned rounds(unsigned long n) {
    if (n <= 1) return n;
    return sizeof n * CHAR_BIT + 1 - __builtin_clzl(n-1);
}

使用bsrq指令(在我的方框中)0.165秒来计算rounds 1到100,000,000,比特黑客

unsigned rounds(unsigned n) {
    if (n <= 1) return n;
    --n;
    n |= n >> 1;
    n |= n >> 2;
    n |= n >> 4;
    n |= n >> 8;
    n |= n >> 16;
    n -= (n >> 1) & 0x55555555;
    n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
    n = (n & 0x0F0F0F0F) + ((n >> 4) & 0x0F0F0F0F);
    return ((n * 0x01010101) >> 24)+1;
}

需要0.626秒,而天真循环

unsigned rounds(unsigned n) {
    unsigned r = 1;
    while(n > 1) {
        ++r;
        n = (n+1)/2;
    }
    return r;
}

需要1.865秒。

如果你不使用固定宽度类型,但是使用任意精度整数,事情会有所改变。天真循环(或递归)仍然使用Θ(log n)步骤,但这些步骤平均花费Θ(log n)时间(或更差),因此整体上您有Θ(log² n)算法(或更糟)。然后使用上面的公式不仅可以提供具有较低常数因子的实现,而且可以提供具有较低算法复杂度的实现。

  • 对于合适的表示,可以在恒定时间内完成比较,O(log n)是合理表示的最坏情况。
  • 从正整数中减去1需要O(log n)才能得到合理的表示。
  • 对于某些表示,可以在恒定时间内计算基数为2的对数(基数);对于其他合理的表示,可以在O(log n)中进行计算[如果它们使用2次幂的基数,则全部任意我熟悉的精密图书馆;如果他们使用10次幂的基数,则会有所不同]。