Я искал уравнение, которое вычисляет ln числа x и выясняет, что это уравнение:
и я написал этот код для его реализации:
double ln = x-1 ;
for(int i=2;i<=5;i++)
{
double tmp = 1 ;
for(int j=1;j<=i;j++)
tmp *= (x-1) ;
if(i%2==0)
ln -= (tmp/i) ;
else
ln += (tmp/i) ;
}
cout << "ln: " << setprecision(10) << ln << endl ;
но, к сожалению, я получаю результаты, совершенно отличные от вывода на моем калькуляторе, особенно для больших чисел, может ли кто-нибудь сказать мне, где проблема?
Уравнение, на которое вы ссылаетесь, представляет собой бесконечную серию, которая подразумевается эллипсисом, следующим за основной частью уравнения, и, как указано более подробно предыдущей формулировкой на той же странице:
В вашем случае вы вычисляете только первые четыре условия. Более поздние термины добавят небольшие уточнения к результату, чтобы приблизиться к фактическому значению, но в конечном счете для вычисления всех бесконечных шагов потребуется бесконечное время.
Однако, что вы можете сделать, это приблизительный ответ на что-то вроде:
double ln(double x) {
// validate 0 < x < 2
double threshold = 1e-5; // set this to whatever threshold you want
double base = x-1; // Base of the numerator; exponent will be explicit
int den = 1; // Denominator of the nth term
int sign = 1; // Used to swap the sign of each term
double term = base; // First term
double prev = 0; // Previous sum
double result = term; // Kick it off
while (fabs(prev - result) > threshold) {
den++;
sign *=- 1;
term *= base;
prev = result;
result += sign * term / den;
}
return result;
}
Осторожно: я на самом деле не проверял это, поэтому может потребоваться некоторая настройка.
То, что это делает, вычисляет каждый термин до тех пор, пока абсолютная разница между двумя последовательными терминами будет меньше определенного порога, который вы устанавливаете.
Теперь это не особенно эффективный способ сделать это. Лучше работать с функциями используемого вами языка (в данном случае C++) позволяет вычислить естественный журнал (который, как мне кажется, уже показал вам другой плакат). Но может быть какая-то ценность, пытаясь понять, как это работает.
Кроме того, как отмечает Barak manos ниже, эта серия Тейлора сходится только в диапазоне (0, 2), поэтому вам нужно будет проверить значение x
в этом диапазоне, прежде чем пытаться выполнить фактическое вычисление.
x
между 0 и 2. См. En.wikipedia.org/wiki/… .
Не помешало бы использовать long
и long double
вместо int
и double
. Это может получить немного большую точность на некоторых более крупных значениях. Кроме того, ваша серия, расширяющая только 5 уровней, также ограничивает вашу точность.
Использование такой серии в основном является приближением логарифмического ответа.
Эта версия должна быть несколько быстрее:
double const scale = 1.5390959186233239e-16;
double const offset = -709.05401552996614;
double fast_ln(double x)
{
uint64_t xbits;
memcpy(&xbits, &x, 8);
// if memcpy not allowed, use
// for( i = 0; i < 8; ++i ) i[(char*)xbits] = i[(char*)x];
return xbits * scale + offset;
}
Хитрость заключается в том, что в ней используется 64-разрядное целочисленное * 64-разрядное умножение с плавающей запятой, которое включает преобразование целого числа в плавающую точку. Указанное представление с плавающей запятой аналогично научной нотации и требует логарифма, чтобы найти соответствующий показатель степени... но это делается исключительно в аппаратном обеспечении и очень быстро.
Однако он выполняет линейное приближение в каждой октаве, что не очень точно. Использование таблицы поиска для этих бит будет намного лучше.
Я считаю, что естественный журнал в C++ языке - это просто журнал
Эта формула не будет работать для больших ресурсов, потому что это потребует от вас учета члена самой высокой степени, которого вы не можете, потому что они бесконечны. Он будет работать только для небольших входов, где важны только первые условия вашей серии.
Вы можете найти способы сделать это здесь: http://en.wikipedia.or/wiki/Pollard%27s_rho_algorithm_for_logarithms
x > 2
, поэтому вычисление pow(9,20)/20
совершенно бессмысленно ,
x
tmp *= (x-1)
наиболее вероятно переполняется в течение нескольких итераций. Кроме того, ваша формула верна только дляx
между 0 и 2.