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", °ree);
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 int
past, 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 double
zonder te weten hoeveel termen je nodig hebt. Dat laat ik als oefening aan de lezer over.
Antwoord 2, autoriteit 20%
In de functie factorial
voer je een int
vermenigvuldiging uit voordat deze wordt toegewezen aan de double
-retourwaarde van de functie. Faculteiten kunnen gemakkelijk het bereik van int
breken, 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 rad
en 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;
}