Calculer la fonction sin ()

Pour mes études, je dois coder un algorithme pour calculer sin() avec cette fonction:

Cependant, dans mon algorithme, je dois garder la valeur de X entre 0 et Pi / 2. J’ai donc écrit mon algorithme mais tous les résultats sont faux.

Voici mon code:

 double sinX(double x){ double resultat = 0; int i; if(x  M_PI_2) x = fmod(x,M_PI_2); for(i = 1;i<=30;i++){ resultat += -1 * ((x*x)/(2*i*(2*i+1)))*(pow(-1,i-1))*((pow(x,2*i-1))/(factorielle(2*i-1))); } return resultat; } 

Je n’ai pas trouvé la raison. Pouvez-vous m’aider?

Voici quelques valeurs de X et le résultat avec fmod

 1 / 1 2 / 0.429204 3 / 1.4292 4 / 0.858407 5 / 0.287611 6 / 1.28761 7 / 0.716815 8 / 0.146018 9 / 1.14602 10 / 0.575222 11 / 0.00442571 12 / 1.00443 13 / 0.433629 14 / 1.43363 15 / 0.862833 16 / 0.292037 17 / 1.29204 18 / 0.72124 19 / 0.150444 20 / 1.15044 

et le résultat avec l’algorithme

 1 / -0.158529 2 / -0.0130568 3 / -0.439211 4 / -0.101605 5 / -0.00394883 6 / -0.327441 7 / -0.0598281 8 / -0.000518332 9 / -0.234888 10 / -0.0312009 11 / -1.44477e-008 12 / -0.160572 13 / -0.0134623 14 / -0.443022 15 / -0.103145 16 / -0.00413342 17 / -0.330639 18 / -0.0609237 19 / -0.000566869 20 / -0.237499 

Voici ma définition “factorielle”

 double factorielle(double x){ double resultat = 1; int i; if(x != 0){ for (i=2;i<=x;i++) { resultat *= i; } } else{ resultat = 1; } return resultat; } 

Et des valeurs:

 1 / 1 2 / 2 3 / 6 4 / 24 5 / 120 6 / 720 7 / 5040 8 / 40320 9 / 362880 10 / 3.6288e+006 11 / 3.99168e+007 12 / 4.79002e+008 13 / 6.22702e+009 14 / 8.71783e+010 15 / 1.30767e+012 16 / 2.09228e+013 17 / 3.55687e+014 18 / 6.40237e+015 19 / 1.21645e+017 20 / 2.4329e+018 

    Vous comprenez mal le but de la deuxième formule que vous montrez. L’idée est que vous utilisiez cette formule pour calculer chaque terme de la sum du terme précédent , vous évitant ainsi d’avoir à utiliser des appels de pow ou factorial .

     #include  double sinX(double x) { double term, total_so_far; int i; term = x; /* First term in the expansion. */ total_so_far = 0.0; for (i = 1; i <= 30; i++) { /* Add current term to sum. */ total_so_far += term; /* Compute next term from the current one. */ term *= -(x * x) / (2*i) / (2*i + 1); } return total_so_far; } int main(void) { /* testing */ double x; int i; for (i = 0; i <= 10; i++) { x = i / 10.0; printf("sin(%f) is %f\n", x, sinX(x)); } return 0; } 

    Et les résultats de l'exécution de ce code, sur ma machine:

     sin(0.000000) is 0.000000 sin(0.100000) is 0.099833 sin(0.200000) is 0.198669 sin(0.300000) is 0.295520 sin(0.400000) is 0.389418 sin(0.500000) is 0.479426 sin(0.600000) is 0.564642 sin(0.700000) is 0.644218 sin(0.800000) is 0.717356 sin(0.900000) is 0.783327 sin(1.000000) is 0.841471 

    Cela devrait vous donner des résultats raisonnables pour la plage de 0 à pi / 2 . En dehors de cette plage, vous devrez être un peu plus intelligent sur la réduction que vous utilisez: réduire simplement modulo pi / 2 ne donnera pas des résultats corrects. (Astuce: vous pouvez réduire modulo 2 * pi sans danger, car la fonction sin est périodique avec la période 2 * pi . Utilisez maintenant les symésortinges de la fonction sin pour réduire la plage de 0 à pi / 2 )


    EDIT Une explication de la raison pour laquelle le code actuel donne des résultats incorrects: mis à part l'étape de réduction imparfaite, vous commencez par le terme i = 1 . Mais le premier terme devrait être pour i = 0 (c'est le terme x , alors que le terme i=1 est le terme -x^3 / 3! ). Une solution rapide et délicate consiste à supprimer l'étape de réduction et à initialiser votre variable resultat sur x plutôt que sur 0 . Cela devrait vous donner de bons résultats pour les petits x , et ensuite vous pourrez comprendre comment remplacer l’étape de réduction. Je serais surpris que vous ayez réellement l'intention de calculer la réponse en utilisant des appels factoriels et puissants explicites, cependant - je suis presque sûr que vous êtes censé calculer chaque terme du précédent, comme décrit ci-dessus.

    Votre code pose deux problèmes:

    1. sin(x+k*π/2) n’est pas nécessairement égal à sin(x)
    2. Votre expression pour le terme est un peu foiré. Les instructions semblent suggérer que vous calculiez le terme suivant dans la série à partir du terme précédent. Commencez avec la valeur pour i=0 , puis utilisez l’équation de votre question pour calculer le terme suivant à chaque itération.

    Enfin, j’ai suivi vos indications. Voici mon code final:

     double sinX(double x) { double result = 1.0; double term_i = 1.0; int i = 2; x = fmod(x, 2*M_PI); for(i = 2; i<= 30; i+=2) { term_i = (-term_i * (x*x)) / (i*(i+1)); result += term_i; } return x * result; } 

    Idée sur le nombre de termes avec la réponse affichée par OP.

    Tant que l’on fmod() abord une limitation de plage, comme fmod() , le nombre de termes nécessaires peut être raisonnablement déterminé de manière dynamic. (Utilise 1 à 23 itérations pour x: 0 à 2 * pi.)

     double sinX1(double x) { double result = 1.0; double term_i = 1.0; int i = 2; x = fmod(x, 2*M_PI); // for(i = 2; i<= 30; i+=2) for(i = 2; ((1.0 + term_i) != 1.0); i+=2) { term_i = (-term_i * (x*x)) / (i*(i+1)); result += term_i; } return x * result; }