这是我在某个网站上看到的一个采访问题。
有人提到答案涉及如下形成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中实现的。
答案 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.3137
和log2(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号“费曼物理学讲座”将首先对日志做出很好的解释,或者或多或少地如何进行这种转换。比维基百科的文章要好得多。