Algorithm 计算一个整数x以2为底的对数的最佳方法是什么?该对数近似于小于或等于它的最大整数?

Algorithm 计算一个整数x以2为底的对数的最佳方法是什么?该对数近似于小于或等于它的最大整数?,algorithm,time-complexity,computer-science,logarithm,Algorithm,Time Complexity,Computer Science,Logarithm,在计算基数2的下限(log(x))的算法中,计算下限(log(x))的最佳摊销时间复杂度是多少?计算对数有许多不同的算法,每种算法都代表某种不同的折衷。这个答案调查了各种方法和一些涉及的权衡 方法1:迭代乘法 一种简单的计算方法⌊logb n⌋ 计算序列b0,b1,b2等,直到我们找到一个大于n的值。在这一点上,我们可以停止,并返回在此之前的指数。这方面的代码相当简单: x = 0; # Exponent bX = 1; # b^Exponent while (bx <= n)

在计算基数2的下限(log(x))的算法中,计算下限(log(x))的最佳摊销时间复杂度是多少?

计算对数有许多不同的算法,每种算法都代表某种不同的折衷。这个答案调查了各种方法和一些涉及的权衡

方法1:迭代乘法 一种简单的计算方法⌊logb n⌋ 计算序列b0,b1,b2等,直到我们找到一个大于n的值。在这一点上,我们可以停止,并返回在此之前的指数。这方面的代码相当简单:

x  = 0;   # Exponent
bX = 1;   # b^Exponent

while (bx <= n) {
    x++;
    bX *= b;
}

return x - 1;
问题是如何进行二进制搜索来解决问题。具体来说,我们知道b2x太大了,但我们不知道有多大。与“猜数字”游戏不同,指数上的二进制搜索有点棘手

一个可爱的解决方案是基于这样一个想法:如果x是我们正在寻找的值,那么我们可以将x写为二进制的一系列位。例如,让我们写x=am-12m-1+am-22m-2+…+a121+a020。然后

bx=bam-12m-1+am-22m-2+…+a121+a020

=2am-12m-1·2am-22m-2·2a0 20

换句话说,我们可以通过一次一点地构建x来尝试发现bx是什么。为此,当我们计算b1、b2、b4、b8等值时,我们可以记下我们发现的值。然后,一旦我们超出了范围,我们可以尝试将它们相乘,看看哪些应该包括,哪些应该排除。下面是它的样子:

x  = 1;       // Exponent
bX = b;       // b^x
powers = [b]; // b^{2^0}
exps   = [1]; // 2^0

while (bX <= n) {
    bX *= bX;     // bX = bX^2
    powers += bX; // Append bX
    x++;
    exps += x;
}

# Overshot, now recover the bits
resultExp = 1
result    = 0;

while (x > 0) {
    # If including this bit doesn't overshoot, it's part of the
    # representation of x.
    if (resultExp * powers[x] <= n) {
        resultExp *= powers[x];
        result += exps[x];
    }

    x--;
}

return result;
x = 1;

while ((1 << x) <= n) {
    x *= 2;
}

# We've overshot the high-order bit. Do a binary search to find it.

low  = 0;
high = x;

while (low < high) {
    mid = (low + high) / 2;

    # Form a bitmask with 1s up to and including bit number mid.
    # This can be done by computing 2^{m+1} - 1.
    mask = (1 << (mid + 1)) - 1

    # If the mask overlaps, branch higher
    if (mask & n) { 
        low = mid + 1
    }
    # Otherwise, branch lower
    else {
        high = mid
    }
}

return high - 1
还有许多我在这里没有提到的算法值得探索。有些算法将机器字分割成固定大小的块,预先计算每个块中前1位的位置,然后一次测试一个块。这些方法的运行时取决于机器字的大小,并且(据我所知)没有一种方法比我在这里概述的方法渐进地快。其他方法的工作原理是,某些处理器的指令可以立即输出数字中最高有效位的位置,或者使用浮点硬件。这些也是有趣和迷人的,一定要看看他们

另一个值得探索的领域是当您有任意精度整数时。在这里,乘法、除法、移位等的代价不是O(1),这些算法的相对代价也会改变。如果你好奇的话,这绝对值得深入探索

这里包含的代码是用伪代码编写的,因为它主要是为了说明而设计的。在实际实现中,您需要担心溢出、处理输入为负或零的情况等。仅供参考。:-)


希望这有帮助

是一个关于数学堆栈交换的类似问题,其答案为这种算法提供了伪代码。另外@jirassimok您链接的答案显示了一种算法,但已知存在更快的算法。Lior Kogan这看起来是一个关于如何计算浮点对数的很好的解释,但由于OP要求的是对数下限,因此还有其他基于离散技术的方法可能也很有用。请登录what base?@templatetypedef这就是为什么我将其作为注释而不是答案发布的原因。这正是我所要求的,我实际上想要基数2,但最终要求的是一般情况。方法1中的小修正,你必须返回x-1。@Shivraj很高兴能帮忙!还有,很好的捕获-现在已经修复了。
x = 0;   # Exponent

while ((1 << x) <= n) {
    x++;
}

return x - 1;
x = 1;

while ((1 << x) <= n) {
    x *= 2;
}

# We've overshot the high-order bit. Do a binary search to find it.

low  = 0;
high = x;

while (low < high) {
    mid = (low + high) / 2;

    # Form a bitmask with 1s up to and including bit number mid.
    # This can be done by computing 2^{m+1} - 1.
    mask = (1 << (mid + 1)) - 1

    # If the mask overlaps, branch higher
    if (mask & n) { 
        low = mid + 1
    }
    # Otherwise, branch lower
    else {
        high = mid
    }
}

return high - 1
Approach              Which Bases?    Time Complexity    Space Complexity
--------------------------------------------------------------------------
Iter. Multiplication      Any            O(log_b n)           O(1)
Repeated Squaring         Any          O(log log_b n)     O(log log_b n)
Zeckendorf Logarithm      Any          O(log log_b n)         O(1)
Bitwise Multiplication     2              O(log n)            O(1)
Bitwise Binary Search      2            O(log log n)          O(1)
Word-Level Parallelism     2                O(1)              O(1)