我搜索了计算数字x的ln的等式,发现这个等式是:
我写了这段代码来实现它:
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
的值是否在该范围内。
我相信C ++语言的自然日志就是日志
使用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位浮点乘法,这涉及将整数转换为浮点。所述浮点表示类似于科学计数法,并且需要对数来找到合适的指数......但它完全是在硬件中完成的并且非常快。
然而,它在每个八度音程中进行线性近似,这不是非常准确。使用查找表来获得这些位会好得多。
该公式不适用于大型输入,因为它需要您考虑最高学位成员,而您不能,因为它们是无限多。它仅适用于小输入,只有系列的第一项是相关的。
你可以在这里找到办法:http://en.wikipedia.or/wiki/Pollard%27s_rho_algorithm_for_logarithms
这应该工作。你只需要一个部分,如果x> = 2缩小x,加上0.6931。 0.6931的原因是ln(2)。如果你想要,你可以添加if(x> = 1024)返回myLN(x / 1024)+ 6.9315,其中6.9315是ln(1024)。这将为x的大值增加速度。带有100的for循环可能更不像20.我相信得到17的整数的精确结果。
double myLN(double x) {
if (x >= 2) {
return myLN(x/2.0) + 0.6931;
}
x = x-1;
double total = 0.0;
double xToTheIPower = x;
for (unsigned i = 1; i < 100; i++) {
if (i%2 == 1) {
total += xToTheIPower / (i);
} else {
total -= xToTheIPower / (i);
}
xToTheIPower *= x;
}
return total;
}