2017-02-14 20 views
0

J'essaie d'approximer sinus (x) en C en utilisant une série de Taylor et l'approximation de Stirling pour les factorielles, mais je reçois des réponses vraiment étranges pour n < 5 et -0 pour tout n => 5. Je littéralement juste commencé à apprendre hier, alors je vous en serais reconnaissant si certains programmeurs plus expérimentés pourraient jeter un coup d'oeil et dites-moi ce qui ne va pasApproximation Sinus (x) avec une série Taylor en C et ayant beaucoup de problèmes

Série Taylor du Sine

approximation de Stirling de factorielles

#include <stdio.h> 
#include <math.h> 

int main(){ 

float x,n,s,i,e,p,f,r; 
f=M_PI; 
e=2.7182818; 
s=0; 

printf("What value of sine do you want to apporximate?"); 
    scanf("%f", &x); 
printf("With what level of precision do you want to calculate it?"); 
    scanf("%f", &n); 
for(i=0;i<=n; ++i);{ 
    r=((2*i)+1); 
    p=(sqrt(2*r*f)*(pow((r/e),r))); 
    s=s+(((pow((-1),i))*(pow(x,((2*i)+1))))/p); 
} 
printf("the value of sine at %f is %f",x,s); 
} 
+0

Vous devez utiliser 'double's au lieu de' float's et 'I' et' n' devrait être 'int's. –

+0

Il y a aussi peu besoin d'approximer la factorielle ici. Calculer chaque terme de façon incrémentielle à la place, c'est-à-dire en multipliant successivement une variable terme par '(-x * x)/(i * (i + 1))' à chaque itération. – doynax

Répondre

0

Cette ligne

for(i = 0; i <= n; ++i);{ 

a un point-virgule supplémentaire. Vous exécutez une boucle vide.

+3

De plus, ceci est détecté par un avertissement dans votre compilateur. Si vous commencez avec C, veuillez activer tous les avertissements et ne poser que des questions sur ce qu'ils signifient quand vous les voyez ou bien vous en débarrasser si vous les comprenez! – dave

0

en fonction de votre formulat c'est le code correct mais générer la mauvaise sortie de sorte que vous devez vérifier à nouveau votre formulat:

#include <stdio.h> 
#include <math.h> 

int main(){ 

double x,n,s,i,e,p,f; 
f=M_PI; 
e=2.7182818; 
s=0; 
int sign=0;// Adding this type to toggle the sign 

printf("What value of sine do you want to apporximate?"); 
    scanf("%lf", &x);// conversion specifier must be %lf for floating number 
printf("With what level of precision do you want to calculate it?"); 
    scanf("%lf", &n); 
for(i=1;i<=n; i=i+2){ // Correcting the for loop 
    p=sqrt(2*i*f)*pow((i/e),i); 
    s=s+(pow(-1,sign++)*pow(x,i))/p; 
} 
printf("the value of sine at %f is %f",x,s); 
} 
-1

Comme le sin() est une fonction périodique, je n'aller plus loin d'une période pour le calculer. Cela simplifie trop les mathématiques, car vous n'avez jamais besoin de calculer de grands nombres factoriels. En effet, vous n'avez même pas besoin de calculer la factorielle pour chaque terme de la série, car les coefficients peuvent être déduits l'un de l'autre, en divisant simplement le coefficient précédent par (n-1) et n. si votre entrée est limitée à une période (eh bien, vous n'avez pas besoin d'utiliser une période fixe de M_PI, vous pouvez aller jusqu'à une valeur maximale de 3.5 et réduire vos réponses pour les valeurs plus grandes en réduisant juste le module de division par M_PI.

une fois dit cela, nous pouvons lier votre erreur maximale, comme pour la plus grande entrée de 3.5 nous aurons 3.5^n/n! comme le dernier terme de notre rapprochement, avec est limitée pour une n être inférieure à une maximale erreur qui fixe le nombre de termes que nous aurons besoin de calculer

Au lieu d'essayer d'être précis avec le nombre de termes nécessaires pour calculer, je vais essayer de faire quelques suppositions , De déduire un algorithme et montrant des valeurs réelles (par exemple, pour la valeur d'entrée maximale de 3.2)

Ce sont les valeurs du terme à la position n pour l'entrée de 3.2 et

n | term at position n for input `3.2` 
======+================= 
    8 | 0.27269634 
    12 | 0.00240693 
    16 | 0.00000578 
    18 | 0.00000019 
    20 | 0.00000001 
    21 | 7.9E-10 

Nous pouvons donc arrêtez de calculer seulement 20 termes de la série. Cela est vrai pour la fonction exp() qui a tous les termes ajoutés et est une fonction simple.Pour le sin() ou cos() vous pouvez deviner qu'une meilleure estimation d'erreur si l'on considère que les deux ont les mêmes termes de la fonction exp(), (bien le premier n'a que les termes impairs, le second n'a que les même termes)

(x^n)/(n!) - (x^(n+2))/((n+2)!) = (n!*x^n*(1 - x^2/((n+1)*(n+2))))/n! 

que pour n > 3.2 signifie que chaque terme est

< x^n/n! 

donc nous pouvons appliquer le même critère que pour l'exponentielle.

Ceci pour dire que nous pouvons arrêter à un moment donné ... si nous continuons notre table, nous verrons que, par exemple à n > 30 le terme global cumulé est inférieur à 5.3E-18 afin que nous puissions arrêter là (pour un certain nombre double , au moins).

#include <stdio.h> 
#include <math.h> /* for the system sin() function */ 

double MySin(double x) /* x must be in the range [0..3.2] */ 
{ 
    int i; 
    const int n = 30; 
    double t = x, acum = x; /* first term, x/1! */ 
    x *= x; /* square the argument so we get x^2 in variable x */ 
    for (i = 3; i < n; i += 2) { 
      t = -t * x/i/(i-1); /* mutiply by -1, x^2 and divide by i and (i-1) */ 
      acum += t; /* and add it to the accum */ 
    } 
    return acum; 
} 

int main() 
{ 
    double arg; 
    for(;;) { 
      if (scanf("%lg", &arg) != 1) 
        break; 
      printf("MySin(%lg) = %lg; sin(%lg) = %lg\n", 
        arg, MySin(arg), arg, sin(arg)); 
    } 
} 

Si vous profitez des symétries que la fonction sin a, vous pouvez réduire votre domaine à M_PI/4 qui est inférieur à un, et vous pouvez arrêter même à terme de puissance 18 pour obtenir environ 17 chiffres significatifs (pour un double) qui rend votre péché plus rapide.

Enfin, nous pouvons obtenir une valable pour tous les biens domaine sin2() fonction par:

double sin2(double x) 
{ 
    bool neg = false; 
    int ip = x/2.0/M_PI; 
    x -= 2.0 * M_PI * ip;     /* reduce to first period [-2PI..2PI] */ 
    if (x < 0.0) x += 2.0*M_PI;    /* reduce to first period [0..2PI] */ 
    if (x > M_PI) { x -= M_PI; neg = true; } /* ... first period negative [ 0..PI ] */ 
    if (x > M_PI/2.0) x = M_PI - x;   /* reflection [0..PI/2] */ 
    return neg ? MySin(-x) : MySin(x); 
}