Calculate sum of 1+(1/2!)+…+(1/n!) n number in C l

2020-04-21 04:38发布

Like the title say, how I calculate the sum of n number of the form: 1+(1/2!)+⋯(1/n!)? I already got the code for the harmonic series:

#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;
}

The question here is.. I already got the sum as the fraction, but how make the variable "i" factorial?

Note: I´m programming in language C, with DEV -C++ 4.9.9.2

标签: c algorithm
4条回答
甜甜的少女心
2楼-- · 2020-04-21 04:59

If you're just looking for computing the first n factorials, I would suggest just computing them recursively, e.g.

factorial[0] = 1;
for (i = 1; i < n; i++) factorial[i] = factorial[i-1] * i;

However, unless you store them as floating point numbers, the large factorials are going to overflow really quickly.

查看更多
Summer. ? 凉城
3楼-- · 2020-04-21 04:59

The number n! is equal to the product of n and the preceding factorial, that is, (n - 1)!.
If you calculate n! in an iteration, you are doing n products.
In the next step, say n+1, you repeat again these n products followed by the multiplication by n+1.
This means that you are repeating the same operations again and again.

It is a better strategy to hold the previous factorial that was calculated in the step n, and then, in the step n+1, just to multiply the n! by n+1. This reduces the number of products to 1 in each iteration.

Thus, you can calculate the series in the following way:

 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);

There are some numerical issues with this approach, but this go beyond the scope of your question.

About overflow: It is necessary to be carefull about the overflow of factorials after several iterations. However, I will not write code to handle overflow.

EDIT

I think that you have not to follow the suggestions of those people that advice to use a factorial function. This approach is very unefficient, since a lot of products are done in every iteration.
IN comparisson with that approach, the mine is better.

However, if you have plans to calculate these series very often, then my approach is not efficient anymore. Then, the right technique is that pointed out in the Bli0042's answer, that is: to hold the factorials in an array, and then just use them every time you need, without need to calculate them again and again in the future.

The resulting program would be this:

#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();    
}

The iteration is done in reverse order inside the function exp_series() in order to improve the numerical issues (that is, to amortiguate the loss of precision when summing small terms).

The last code has side effects, because an external array is invoked inside the function exp_series().
However, I think that handling this would become my explanation more obscure.
Just, take it in account.

查看更多
家丑人穷心不美
4楼-- · 2020-04-21 05:01

Calculating factorial in this case is bad thing to do because it can cause overflow for small values of N . Use following pseudo code to get it in O(N) without overflow.

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);

More acurrate way of doing it though i feel it is unnecessary in case of factorials : -

double sum = 0.0;
double acc = 1;

for(i=n;i>=1;i--) {

   sum = (sum + 1)/i;
}

print(sum);

Note:- Because the above method is built in reverse it more accurate but unfortunately more time consuming because it is O(N) even for higher values whereas the gain in accuracy is negligible as factorial function grows very fast hence error keeps on decreasing quickly.

查看更多
姐就是有狂的资本
5楼-- · 2020-04-21 05:16

You got a slightly more accurate answer for the harmonic summing 1./i + 1./(i-1) ... 1./1. Suggest you stay with that order.

[edit] Rewrite: Thanks to @pablo197 for pointing out the error of my ways.

To calculate harmonic and 1+(1/2!)+…+(1/n!), continue summing the least significant terms together first as that helps to minimize precision loss. Starting with the least significant term 1/n as sum, sum of that and the n-1 term is : sum = (1 + sum)/(n-1) and so on. (See below)

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

Add 1.0 or 1/0! to one_over_factorial_series, the result about e = 2.7182818284...

[Edit] Detail showing how direct n! calculation is avoided.

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) + ... =  
查看更多
登录 后发表回答