#logarithm #sqrt
#логарифм #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.
Комментарии:
1. 1 за вопрос. Я только что попробовал ввести 100 в качестве входных данных, и он вернул 30. Метод не завершен.
2. В Википедии есть алгоритм en.wikipedia.org/wiki/Binary_logarithm
Ответ №1:
Возможно, я нашел точные ответы, которые искали интервьюеры. Со своей стороны, я бы сказал, что это немного сложно вывести под давлением собеседования. Идея в том, что, допустим, вы хотите найти log2(13)
, вы можете знать, что оно лежит между 3-4. Также 3 = log2(8) and 4 = log2(16)
,
из свойств logarithm мы знаем, что 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;
}
Ответ №2:
Прошло много времени с тех пор, как я писал чистый 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, начинаются с отличного объяснения журналов и более или менее того, как выполнить это преобразование. Значительно превосходит статью в Википедии.
Комментарии:
1. Я думаю, вам не хватает некоторых угловых случаев, для 4 я получаю 1.5, где явно должно быть 2.