就像标题所说,我如何计算n个数字的总和:1+(1/2!)+⋯(1 / n!)?我已经得到了谐波系列的代码:
#include <stdio.h>
int main( void )
{
int v=0,i,ch;
double x=0.;
printf("Introduce un número paracalcular la suma: ");
while(scanf("%d",&v)==0 || v<=0)
{
printf("Favor de introducir numeros reales positivos: ");
while((ch=getchar())!='\n')
if(ch==EOF)
return 1;
}
for (i=v; i>=1; i--)
x+=1./i;
printf("EL valor de la serie es %f\n", x);
getch();
return 0;
}
这里的问题是..我已经将总和作为分数,但是如何使变量“i”为阶乘?
注意:我用C语言编程,使用DEV -C ++ 4.9.9.2
答案 0 :(得分:2)
对于谐波求和1. / i + 1./(i-1)... 1./1,您得到了更准确的答案。建议你留下那个订单。
[edit]重写:感谢@ pablo197指出我的方式错误。
要计算谐波和 1+(1/2!)+ ... +(1 / n!),请先将最不重要的项加在一起,因为这有助于最大限度地减少精度损失。从最不重要的字词1/n
开始为sum
,该字词和n-1字词的总和为:sum = (1 + sum)/(n-1)
,依此类推。 (见下文)
double x = 0.0;
double one_over_factorial_series = 0.0;
for (i = v; i >= 1; i--) {
x += 1.0/i;
one_over_factorial_series = (one_over_factorial_series + 1)/i;
}
printf("harmonic:%le\n", x);
// 2.828968e+00
printf("one_over_factorial:%.10le\n", one_over_factorial_series);
// 1.7182815256e+00
将1.0
或1/0!
添加到one_over_factorial_series
,结果为e = 2.7182818284...
[编辑]详细显示如何直接n!计算是避免的。
1 + (1/2!) + … + (1/n!) =
1/n! + 1/((n-1)!) + 1/((n-2)!) + 1/((n-3)!) + ... + 1 =
(1/n + 1)/((n-1)!) + 1/((n-2)!) + 1/((n-3)!) + ... + 1 =
((1/n + 1)/(n-1) + 1)/((n-2)!) + 1/((n-3)!) + ... + 1 =
...
((((1/n + 1)/(n-1) + 1)/(n-2) + 1)/(n-3) + 1)/(n-4) + ... =
答案 1 :(得分:1)
如果您只是想要计算前n个阶乘,我建议只是递归计算它们,例如。
factorial[0] = 1;
for (i = 1; i < n; i++) factorial[i] = factorial[i-1] * i;
但是,除非将它们存储为浮点数,否则大型因子会很快溢出。
答案 2 :(得分:0)
在这种情况下计算阶乘是不好的事情,因为它可能导致N的小值溢出。使用以下伪代码在O(N)
中获取它而不会溢出。
double sum = 0.0;
double acc = 1;
double error = 0.0000001;
for(i=1;i<=n;i++) {
acc = acc/i;
if(acc<error)
break;
sum = sum + acc;
}
print(sum);
虽然我觉得在使用因子的情况下是不必要的,但是更加精确的做法: -
double sum = 0.0;
double acc = 1;
for(i=n;i>=1;i--) {
sum = (sum + 1)/i;
}
print(sum);
注意: - 因为上面的方法反向构建它更准确但不幸的是更耗时,因为即使对于更高的值它也是O(N),而精度的增益可以忽略不计为因子函数增长非常快,因此错误会继续快速下降。
答案 3 :(得分:-1)
数字n!等于n和前一个阶乘的乘积,即(n - 1)! 如果你计算n!在迭代中,你正在做n个产品 在下一步,比如n + 1,你再次重复这些n个产品,然后乘以n + 1 这意味着您一次又一次地重复相同的操作。
保持在步骤n中计算的前一个阶乘是一个更好的策略,然后,在步骤n + 1中,只是为了乘以n!由n + 1。这会在每次迭代中将产品数量减少到1。
因此,您可以通过以下方式计算系列:
int max_n = 20; /* This value can come from another point of the program */
int n; /* Initial value of the index */
double factorial_n = 1; /* It has to be initialized to 1, since the factorial of 0 is 1 */
double sum = 0.0; /* It has to be initialized to 0, in order to calculate the series */
for (n = 0; n <= max_n; )
{
sum += 1.0/factorial_n;
n++;
factorial_n *= n;
}
printf("Series result: %.20f\n", sum);
这种方法存在一些数值问题,但这超出了您的问题的范围。
关于溢出:在几次迭代之后,需要注意阶乘的溢出。但是,我不会编写代码来处理溢出。
编辑
我认为您不必遵循那些建议使用阶乘函数的人的建议。这种方法效率很低,因为很多产品都是在每次迭代中完成的 与那种方法相比,矿井更好。
但是,如果你有计划经常计算这些系列,那么我的方法就不再有效了。然后,正确的技术是在 Bli0042 的答案中指出的,即:将阶乘保持在数组中,然后在每次需要时使用它们,而无需再次计算它们并且在将来再次。
结果程序将是:
#include <stdio.h>
#define MAX_N 100
double factorial[MAX_N+1];
void build_factorials(double *factorial, int max)
{
factorial[0] = 1.0;
for (int j = 0; j <= max; )
{
j++;
factorial[j] = factorial[j-1] * j;
}
}
double exp_series(int n)
{
int j;
double sum;
if (n > MAX_N) /* Error */
return 0.0;
sum = 0.0;
for (j = n; j >= 0; j--)
sum += 1.0/factorial[j];
return sum;
}
int main(void)
{
int n;
double sum;
build_factorials(factorial, MAX_N);
printf("Series (up to n == 11): %.20f\n", exp_series(11));
printf("Series (up to n == 17): %.20f\n", exp_series(17));
printf("Series (up to n == 9): %.20f\n", exp_series(9));
getchar();
}
迭代在函数exp_series()内以相反的顺序完成,以便改进数值问题(即,在对小项求和时减少精度损失)。
最后一个代码有副作用,因为在函数exp_series()中调用了一个外部数组 但是,我认为处理这个问题会让我的解释变得更加模糊 只是,考虑一下。