Calculer la sum de 1+ (1/2!) +… + (1 / n!) N nombre en langage C

Comme le titre le dit, comment je calcule la sum de n nombre de la forme: 1+ (1/2!) + ⋯ (1 / n!)? J’ai déjà le code de la série harmonic:

#include  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=1; i--) x+=1./i; printf("EL valor de la serie es %f\n", x); getch(); return 0; } 

La question ici est .. J’ai déjà la sum comme fraction, mais comment rendre la variable “i” factorielle?

Note: Je programme en langage C, avec DEV -C ++ 4.9.9.2

Vous avez une réponse un peu plus précise pour la sum des harmoniques 1./i + 1./(i-1) … 1./1. Vous suggère de restr avec cet ordre.

[edit] Rewrite: Merci à @ pablo197 d’avoir signalé l’erreur de mes manières.

Pour calculer les harmoniques et 1+ (1/2!) +… + (1 / n!), Continuez à additionner les termes les moins significatifs en premier car cela permet de minimiser la perte de précision. En commençant par le terme le moins significatif 1/n tant que sum , la sum de celui-ci et le terme n-1 est: sum = (1 + sum)/(n-1) et ainsi de suite. (Voir ci-dessous)

 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 

Ajoutez 1.0 ou 1/0! to one_over_factorial_series , le résultat à propos de e = 2.7182818284...

[Edit] Détail montrant à quel point n! le calcul est évité.

 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) + ... = 

Si vous cherchez simplement à calculer les n premières factorielles, je vous suggère de les calculer récursivement, par exemple:

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

Cependant, à moins que vous ne les stockiez sous forme de nombres à virgule flottante, les grandes factorielles vont déborder très rapidement.

Calculer factorielle dans ce cas est une mauvaise chose à faire car cela peut provoquer un dépassement de capacité pour de petites valeurs de N. Utilisez le pseudo-code suivant pour l’obtenir en O(N) sans débordement.

 double sum = 0.0; double acc = 1; double error = 0.0000001; for(i=1;i<=n;i++) { acc = acc/i; if(acc 

Une façon plus concrète de le faire même si j’estime que cela n’est pas nécessaire en cas de factorielles: -

 double sum = 0.0; double acc = 1; for(i=n;i>=1;i--) { sum = (sum + 1)/i; } print(sum); 

Remarque: - La méthode ci-dessus étant construite en sens inverse, elle est plus précise mais malheureusement plus longue, car elle est O (N) même pour des valeurs plus élevées alors que le gain en précision est négligeable car la fonction factorielle croît très rapidement, d'où que l'erreur continue à diminuer rapidement.

Le nombre n! est égal au produit de n et de la factorielle précédente, soit (n – 1) !.
Si vous calculez n! dans une itération, vous faites n produits.
Dans l’étape suivante, disons n + 1, vous répétez ces n produits suivis de la multiplication par n + 1.
Cela signifie que vous répétez les mêmes opérations encore et encore.

Il est préférable de conserver la factorielle précédente calculée à l’étape n, puis à l’étape n + 1, il suffit de multiplier le n! par n + 1. Cela réduit le nombre de produits à 1 dans chaque itération.

Ainsi, vous pouvez calculer la série de la manière suivante:

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

Cette approche pose quelques problèmes numériques, mais cela dépasse le cadre de votre question.

À propos du débordement: il faut faire attention au débordement des factorielles après plusieurs itérations. Cependant, je n'écrirai pas de code pour gérer les débordements.

MODIFIER

Je pense que vous ne devez pas suivre les suggestions de ces personnes qui conseillent d'utiliser une fonction factorielle. Cette approche est très inefficace, car beaucoup de produits sont fabriqués à chaque itération.
En comparaison de cette approche, la mine est meilleure.

Cependant, si vous avez l’intention de calculer ces séries très souvent, mon approche n’est plus efficace. Ensuite, la bonne technique est celle indiquée dans la réponse du Bli0042 , à savoir: conserver les factorielles dans un tableau, puis les utiliser chaque fois que vous avez besoin, sans avoir besoin de les calculer encore et encore dans le futur.

Le programme résultant serait le suivant:

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

L'itération est effectuée dans l'ordre inverse de la fonction exp_series () afin d'améliorer les problèmes numériques (c'est-à-dire d'amortir la perte de précision lors de la sum de petits termes).

Le dernier code a des effets secondaires, car un tableau externe est appelé dans la fonction exp_series ().
Cependant, je pense que gérer cela rendrait mon explication plus obscure.
Juste, prenez-le en compte.