使用sqrt()查找log2()

时间:2011-04-18 09:40:32

标签: logarithm sqrt

这是我在某个网站上看到的一个采访问题。

有人提到答案涉及如下形成log2()的重现:

double log2(double x )
{
if ( x<=2 ) return 1;
 if ( IsSqureNum(x) )
   return log2(sqrt(x) ) * 2;
 return log2( sqrt(x) ) * 2 + 1; // Why the plus one here.
}

至于复发,显然+1是错误的。而且,基本情况也是错误的。 有谁知道更好的答案? log()和log10()实际上是如何在C中实现的。

2 个答案:

答案 0 :(得分:10)

也许我已经找到了面试官正在寻找的确切答案。就我而言,我会说在面试压力下得出这个有点困难。这个想法是,你想要找到log2(13),你可以知道它位于 3到4 之间。还3 = log2(8) and 4 = log2(16)

来自对数属性,我们知道log( sqrt( (8*16) ) = (log(8) + log(16))/2 = (3+4)/2 = 3.5

现在,sqrt(8*16) = 11.3137log2(11.3137) = 3.5。自11.3137<13以来,我们知道我们想要的log2(13)位于 3.5和4 之间,我们继续找到它。很容易注意到它有一个二进制搜索解决方案,当我们的值收敛到我们希望找到log2()的值时,我们迭代到一个点。代码如下:

double Log2(double val)
{
    int lox,hix;
    double rval, lval;
    hix = 0;
    while((1<<hix)<val)
        hix++;
    lox =hix-1;
    lval = (1<<lox) ;
    rval = (1<<hix);
    double lo=lox,hi=hix;
   // cout<<lox<<" "<<hix<<endl;
    //cout<<lval<<" "<<rval;
    while( fabs(lval-val)>1e-7)
    {
        double mid = (lo+hi)/2;
        double midValue = sqrt(lval*rval);

        if ( midValue > val)
        {
             hi = mid;
             rval = midValue;
        }
        else{
            lo=mid;
            lval = midValue;
        }
    }
    return lo;

}

答案 1 :(得分:-1)

自从我编写纯C以来已经很长时间了,所以这里是C ++(我认为唯一的区别是输出函数,所以你应该能够遵循它):

#include <iostream>
using namespace std;

const static double CUTOFF = 1e-10;

double log2_aux(double x, double power, double twoToTheMinusN, unsigned int accumulator) {
     if (twoToTheMinusN < CUTOFF)
       return accumulator * twoToTheMinusN * 2;
     else {
       int thisBit;
       if (x > power) {
            thisBit = 1;
            x /= power;
       }
       else
            thisBit = 0;
       accumulator = (accumulator << 1) + thisBit;
       return log2_aux(x, sqrt(power), twoToTheMinusN / 2.0, accumulator);
     }
}

double mylog2(double x) {
     if (x < 1)
       return -mylog2(1.0/x);
     else if (x == 1)
       return 0;
     else if (x > 2.0)
       return mylog2(x / 2.0) + 1;
     else
       return log2_aux(x, 2.0, 1.0, 0);
}

int main() {
     cout << "5 " << mylog2(5) << "\n";
     cout << "1.25 " << mylog2(1.25) << "\n";
     return 0;
}

函数'mylog2'用一些简单的日志技巧来获取1到2之间的相关数字,然后用该数字调用log2_aux。

log2_aux或多或少遵循Scorpi0链接到上面的算法。在每一步,您得到1位结果。当你有足够的位时,停止。

如果你可以获得一份副本,那么第23号“费曼物理学讲座”将首先对日志做出很好的解释,或者或多或少地如何进行这种转换。比维基百科的文章要好得多。