Taylor-reeks implementeren voor sinus en cosinus in C

Ik heb de gids gevolgd die mijn prof ons heeft gegeven, maar ik kan gewoon niet vinden waar ik fout ging. Ik heb ook wat andere vragen doorgenomen over het implementeren van de Taylor Series in C.

Ga er maar vanuit dat RaiseTo(verhoog een getal tot de macht x) er is.

double factorial (int n)
{
    int fact = 1,
    flag;
   for (flag = 1; flag <= n; flag++)
   {
        fact *= flag;
   }
   return flag;
}
double sine (double rad)
{
int flag_2,
    plusOrMinus2 = 0; //1 for plus, 0 for minus 
double sin, 
    val2 = rad,
    radRaisedToX2,
    terms;
terms = NUMBER_OF_TERMS; //10 terms
    for (flag_2 = 1; flag_2 <= 2 * terms; flag_2 += 2)
    {
        radRaisedToX2 = RaiseTo(rad, flag_2);   
        if (plusOrMinus2 == 0)
        {
            val2 -=  radRaisedToX2/factorial(flag_2);
            plusOrMinus2++; //Add the next number
        }
        else
        {
            val2 += radRaisedToX2/factorial(flag_2);
            plusOrMinus2--; //Subtract the next number
        }
    }
    sin = val2;
    return sin;
 }
int main()
{
    int degree;
    scanf("%d", &degree);
    double rad, cosx, sinx;
    rad = degree * PI / 180.00;
    //cosx = cosine (rad);
    sinx = sine (rad);
    printf("%lf \n%lf", rad, sinx);
}

Dus tijdens de lus krijg ik de rad^x, deel deze door de faculteit van de oneven getallenreeksen beginnend bij 1, voeg deze vervolgens toe of trek deze af, afhankelijk van wat nodig is, maar wanneer ik het programma uitvoer, krijg ik de outputs weg boven één, en we weten allemaal dat de limieten van sin(x) 1 en -1 zijn, ik zou heel graag willen weten waar ik de fout in ging, zodat ik het kan verbeteren, sorry als het een nogal slechte vraag is.


Antwoord 1, autoriteit 100%

Alles boven 12!is groter dan in een 32-bits intpast, dus dergelijke waarden zullen overlopen en daarom niet opleveren wat u verwacht.

p>

In plaats van elke keer de volledige faculteit te berekenen, moet je elke term in de reeks bekijken ten opzichte van de vorige. Voor een bepaalde term is de volgende -((x*x)/(flag_2*(flag_2-1))maal de vorige. Begin dus met een term van x, vermenigvuldig dan met die factor voor elke volgende term.

Er is ook een truc om het resultaat te berekenen met de precisie van een doublezonder te weten hoeveel termen je nodig hebt. Dat laat ik als oefening aan de lezer over.


Antwoord 2, autoriteit 20%

In de functie factorialvoer je een intvermenigvuldiging uit voordat deze wordt toegewezen aan de double-retourwaarde van de functie. Faculteiten kunnen gemakkelijk het bereik van intbreken, zoals 20! = 2432902008176640000.

Je hebt ook de verkeerde variabele geretourneerd – de lusteller!

Verander de lokale variabele in double, als

double factorial (int n)
{
    double fact = 1;
    int flag;
    for (flag = 1; flag <= n; flag++)
    {
        fact *= flag;
    }
    return fact;    // it was the wrong variable, and wrong type
}

Er is ook geen behoefte aan een factoriële berekening. Merk op dat elke looptijd van de serie de vorige term vermenigvuldigt met raden verdeelt bij het Term-nummer – met een tekenwijziging.


Antwoord 3

Nog een redelijk naïef, 5-minuten benadering omvat het berekenen van een opzoektabel met de eerste 20 of zo’n faciliteiten, d.w.z.e 1! .. 20! Dit vereist heel weinig geheugen en kan de snelheid verhogen over de ‘elke keer’ computatiemethode. Een verdere optimalisatie kan eenvoudig worden gerealiseerd in de functie die de faciliteiten pre-berekent, waardoor de relatie ook is voor de vorige.

Een aanpak die efficiënt geëlimineerd vertakt (als x do y anders do z) in de lussen van de twee trigfuncties opnieuw meer snelheid verstrekken.

C-code

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
const int nMaxTerms=20;
double factorials[nMaxTerms];
double factorial(int n)
{
    if (n==1)
        return 1;
    else
        return (double)n * factorial(n - 1.0);
}
void precalcFactorials()
{
    for (int i=1; i<nMaxTerms+1; i++)
    {
        factorials[i-1] = factorial(i);
    }
}
/*
    sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! .......
*/
double taylorSine(double rads)
{
    double result = rads;
    for (int curTerm=1; curTerm<=(nMaxTerms/2)-1; curTerm++)
    {
        double curTermValue = pow(rads, (curTerm*2)+1);
        curTermValue /= factorials[ curTerm*2 ];
        if (curTerm & 0x01)
            result -= curTermValue;
        else
            result += curTermValue;
    }
    return result;
}
/*
    cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! .......
*/
double taylorCos(double rads)
{
    double result = 1.0;
    for (int curTerm=1; curTerm<=(nMaxTerms/2)-1; curTerm++)
    {
        double curTermValue = pow(rads, (curTerm*2) );
        curTermValue /= factorials[ (curTerm*2) - 1 ];
        if (curTerm & 0x01)
            result -= curTermValue;
        else
            result += curTermValue;
    }
    return result;
}
int main()
{
    precalcFactorials();
    printf("Math sin(0.5) = %f\n", sin(0.5));
    printf("taylorSin(0.5) = %f\n", taylorSine(0.5));
    printf("Math cos(0.5) = %f\n", cos(0.5));
    printf("taylorCos(0.5) = %f\n", taylorCos(0.5));
    return 0;
}

Uitgang

Math sin(0.5) = 0.479426
taylorSin(0.5) = 0.479426
Math cos(0.5) = 0.877583 
taylorCos(0.5) = 0.877583

Javascript

geïmplementeerd in JavaScript, de code produceert schijnbaar identieke resultaten (ik heb niet erg veel getest) naar de ingebouwde wiskundebibliotheek bij het optillen slechts 7 termen in de SIN / COS-functies.

window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
	console.log('starting');
	for (var i=1; i<21; i++)
		factorials[i-1] = factorial(i);
	console.log('calculated');
	console.log(" Math.cos(0.5) = " + Math.cos(0.5));
	console.log("taylorCos(0.5) = " + taylorCos(0.5));
	console.log('-');
	console.log("  Math.sin(0.5) = " + Math.sin(0.5));
	console.log("taylorSine(0.5) = " + taylorSine(0.5));
}
var factorials = [];
function factorial(n)
{
	if (n==1)
		return 1;
	else
		return n * factorial(n-1);
}
/*
	sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! .......
*/
function taylorSine(x)
{
	var result = x;
	for (var curTerm=1; curTerm<=7; curTerm++)
	{
		var curTermValue = Math.pow(x, (curTerm*2)+1);
		curTermValue /= factorials[ curTerm*2 ];
		if (curTerm & 0x01)
			result -= curTermValue;
		else
			result += curTermValue;
	}
	return result;
}
/*
	cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! .......
*/
function taylorCos(x)
{
	var result = 1.0;
	for (var curTerm=1; curTerm<=7; curTerm++)
	{
		var curTermValue = Math.pow(x, (curTerm*2));
		curTermValue /= factorials[ (curTerm*2)-1 ];
		if (curTerm & 0x01)
			result -= curTermValue;
		else
			result += curTermValue;
	}
	return result;
}

Other episodes