用C语言计算1+(1/2!)+ ... +(1 / n!)n数的和

时间:2014-01-14 23:48:28

标签: c algorithm

就像标题所说,我如何计算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

4 个答案:

答案 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.01/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()中调用了一个外部数组 但是,我认为处理这个问题会让我的解释变得更加模糊 只是,考虑一下。