这是我的代码:
#include <iostream>
#include <cmath>
using namespace std;
int factorial(int);
int main()
{
for(int k = 0; k < 100000; k++)
{
static double sum = 0.0;
double term;
term = (double)pow(-1.0, k) * (double)pow(4.0, 2*k+1) / factorial(2*k+1);
sum = sum + term;
cout << sum << '\n';
}
}
int factorial(int n)
{
if(n == 0)
{
return 1;
}
return n*factorial(n-1);
}
我只是想使用sine(4)
的{{1}}扩展形式来计算maclaurin
的值。对于每个控制台输出,值为“sine
”。控制台发出错误并在10秒钟后关闭。我在IDE中没有任何错误。
答案 0 :(得分:1)
您的方法存在多个问题。
您的阶乘函数无法返回int
。返回值太大了,非常快。
使用pow(-1, value)
获得交替的正/负效率是非常低效的,并且会很快产生不正确的值。您应该选择1.0或-1.0,具体取决于k的奇偶校验。
当您总结一系列长期术语时,您希望首先对具有最小幅度的术语求和。否则,由于现有的比特限制了您可以达到的范围,您将失去精确度。在您的情况下,四的幂由阶乘控制,因此您首先将最高量值相加。从另一端开始,你可能会获得更好的精确度。
在算法上,如果你要将4增加到2k + 1的幂然后除以(2k + 1)!,你应该保留两个因子列表(4,4,4,4 ...)和(2,3,4,5,6,7,8,9,......)并简化双方。同时有很多四肢要去除分子和分母。
即使有这四个,我也不确定你能在没有专门代码的情况下接近你设定的100000目标。
答案 1 :(得分:0)
正如其他人已经说过的那样,对于大k
,你得到的中间结果的幅度太大而不适合双倍。来自k
上的某个pow
以及factorial
将返回无限。这就是非常大的双打所发生的事情。然后,当你将一个无穷大除以另一个无穷大时,你得到了NaN。
处理过大数字的一个常见技巧是使用对数来表示中间结果,并且最后只应用指数函数一次。
这里需要一些对数的数学知识。要了解我在这里所做的事情,您需要了解exp(log(x)) == x
,log(a^b) == b*log(a)
和log(a/b) == log(a) - log(b)
。
在您的情况下,您可以重写
pow(4, 2*k+1)
到
exp((2*k+1)*log(4))
然后还有阶乘。 factorial(n) == gamma(n+1)
功能可以帮助log(factorial(n)) == lgamma(n+1)
和pow(4, 2*k+1) / factorial(2*k+1)
。简而言之,lgamma为您提供了一个没有巨大中间结果的阶乘对数。
总结一下,替换
exp((2*k+1)*log(4) - lgamma(2*k+2))
使用
lgamma
这可以帮助您使用NaN。此外,这应该会提高效果,因为O(1)
在factorial
中运行,而O(k)
位于{{1}}。
但请注意,我仍然对您的结果在数值上准确无误。 双精度仍然限制在大约16位十进制数字的精度。你的100000次迭代很可能毫无价值,甚至可能有害。