问题
This formula is from a friend of mine --- and I fixed it up for him. But I can't seem to figure out of how to get the right sine calculations per angle. Can someone please help me in getting the right commands in the sin part?
Code:
#include<stdio.h>
#define PI 3.141592653589
#define NUMBER_OF_TERMS 10
double factorial(double x)
{
double counter, total;
counter=x;
total=x;
while(counter>1)
{
counter--;
total = total * counter;
}
return total;
}
double power(double x, double y)
{
double counter, j;
counter=0;
j = x;
while (counter<(y-1))
{
counter++;
x = x * j;
}
return x;
}
double cosine_func(double radians)
{
int counter, x;
double cosine;
x=0;
counter=0;
cosine = 0;
while(counter<NUMBER_OF_TERMS-1)
{
counter++;
x=x+2;
if(counter%2 == 0)
{
cosine = cosine - (power(radians, x)/factorial(x));
}
else if(counter%2 != 0)
{
cosine = cosine + (power(radians, x)/factorial(x));
}
}
return cosine;
}
double sine_func(double radians)
{
int counter, x;
double sin;
x=0;
counter=0;
sin = 0;
while(counter<NUMBER_OF_TERMS-2)
{
counter++;
x=x+3;
if(counter%2 != 0)
{
sin= sin -(power(radians, x)/factorial(x));
}
else if(counter%2 != 0)
{
sin= sin + (power(radians, x)/factorial(x));
}
}
return sin;
}
main()
{
double counter;
double x_angles;
double x_radians;
double cosine;
double sin;
printf("11526769\n\n");
printf("x(degrees)\t x(radians)\t\t cos x\t\t sin x\t\t");
counter = 0;
x_angles = -185;
while (x_angles<180)
{
counter++;
x_angles+=5;
x_radians=x_angles*PI/180.0;
cosine=1-cosine_func(x_radians);
sin=x_radians-sine_func(x_radians);
printf("%.2lf\t\t%.12lf\t\t%.12lf\t\t%.12lf\n", x_angles, x_radians, cosine, sin);
}
return 0;
}
回答1:
for(f2=3;f2==1;f2--){
fac2*=f2;
}
f2 is initialized with 3 and then in condition portion it is checked that if f2 is equaled to 1 which returns false.
This loop doesn't run for even a single time. Condition is false for the first time. So
fac2*=f2;
is never executed.
And you did same error for every next loop.
回答2:
Most of your for loops never run. Check the correct syntax for them. Example:
for(f2=3;f2==1;f2--)
Is never executed because f2 = 3 and 3 != 1
回答3:
#include<stdio.h>
#define PI 3.141592653589
#define NUMBER_OF_TERMS 10
int
main()
{
double angle_degrees, angle_radians;
double sin, i, i2, i3, i4 , i5, i6, i7, i8, i9, i10;
double fac1, fac2, fac3, fac4, fac5, fac6=1, fac7, fac8, fac9, fac10;
double f1, f2, f3, f4, f5, f6, f7, f8, f9, f10;
double p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
for(angle_degrees = -180; angle_degrees <= 180; angle_degrees += 5){
p1 = angle_radians;
p2 = angle_radians;
p3 = angle_radians;
p4 = angle_radians;
p5 = angle_radians;
p6 = angle_radians;
p7 = angle_radians;
p8 = angle_radians;
p9 = angle_radians;
p10 = angle_radians;
angle_radians = angle_degrees*PI/180;
for(f1=3;f1>=1;f1--){
fac1*=f1;
}
for(f2=5;f2>=1;f2--){
fac1*=f2;
}
for(f3=7;f3>=1;f3--){
fac1*=f3;
}
for(f4=9;f4>=1;f4--){
fac1*=f4;
}
for(f5=11;f5>=1;f5--){
fac1*=f5;
}
for(f6=13;f6>=1;f6--){
fac1*=f6;
}
for(f7=15;f7>=1;f7--){
fac1*=f7;
}
for(f8=17;f8>=1;f8--){
fac1*=f8;
}
for(f9=19;f9>=1;f9--){
fac1*=f9;
}
for(f10=21;f10>=1;f10--){
fac1*=f10;
}
sin = angle_radians - (pow(p1, 3)/fac1) + (pow(p2, 5)/fac2) - (pow(p3, 7)/fac3) + (pow(p4, 9)/fac4) - (pow(p5, 11)/fac5) + (pow(p6, 13)/fac6) - (pow(p7, 15)/fac7) + (pow(p8, 17)/fac8) -(pow(p9, 19)/fac9) - (pow(p10, 21)/fac10);
printf ("%.2lf\t\t%.12lf\t\t%.12lf\n",
angle_degrees, angle_radians, sin);
}
}
Here's a brand new one --- also I forgot these restrictions involved with it: 1)NO other function aside from main(). 2)NO inputs involved. 3) Angles = double data. 4)Output = angles (both degrees and radians), cosine (will work on that once done solving for sine), and sine.
回答4:
The Taylor series of sin(x) is x-x^3/3!+x^5/5!-... . In your code I assume that p1 should mean x^1=x, p2=x^3, .. and f1=1! f2=3!, .. . Now in the result line you write
sin = angle_radians - (p1/fac1) + (p2/fac2) + //...
which has the series with wrong sign + the first term again.
sin = (p1/fac1) - (p2/fac2) + //...
Also the code is overly complicated. You can collect the result in a single loop:
double p=x;
double f=1;
double res=0;
int k=1;
for (int i=0;i<n;i++){
res+=p/f;
p*=-x*x;
k+=2;
f*=(k-1)*k;
}
Here x is the angle in radians p is the current power with right sign and f the factorial of the term.
As commented by LutzL this would overflow at some point because of the factorial. This version is safer against overflows
double res=0;
double term=x;
int k=1;
for (int i=0;i<n;i++){
res+=term;
k+=2;
term*=-x*x/k/(k-1);
}
回答5:
Code can do better than sin(D2R(angle_degrees))
Step 1: Reduce angle to the range 0 to 90 degrees before converting to radians. Take advantage of the usual trig identities. Then we get exact answers for 90*n degrees.
Step 2: Calculate power series from last term up to the first as summing small terms first is more accurate.
#include<stdio.h>
#define PI 3.1415926535897932384626433832795
#define D2R(a) ((a)*PI/180)
#define NUMBER_OF_TERMS 10
int main(void) {
double angle_degrees;
for (angle_degrees = -360; angle_degrees <= 360; angle_degrees += 30) {
double angle_radians = D2R(angle_degrees);
int sign = 1;
double angle_reduced_degrees = fmod(angle_degrees, 360.0);
if (angle_reduced_degrees < 0) {
angle_reduced_degrees = -angle_reduced_degrees;
sign = -1;
}
int quadrant = (int) (angle_reduced_degrees / 90.0);
angle_reduced_degrees -= quadrant * 90;
switch (quadrant) {
case 0:
break;
case 1:
angle_reduced_degrees = 90 - angle_reduced_degrees;
break;
case 2:
angle_reduced_degrees = -angle_reduced_degrees;
sign = -sign;
break;
case 3:
angle_reduced_degrees = 90 - angle_reduced_degrees;
sign = -sign;
break;
}
double angle_reduced_radians = D2R(angle_reduced_degrees);
long long denom = 1;
for (int i = 1; i < NUMBER_OF_TERMS; i++) {
denom *= -(2 * i + 0) * (2 * i + 1);
}
double aa = angle_reduced_radians * angle_reduced_radians;
double sum = 0;
for (int i = NUMBER_OF_TERMS; --i >= 0;) {
double term = 1.0 / (double) denom;
sum = term + sum * aa;
if (i) denom /= (-(2 * i) * (2 * i + 1));
}
sum *= angle_reduced_radians * sign;
sum *= 1.0; // to get rid of -0.0
printf("sine(%+7.2f degrees %+9f radians) = %+20.17f sin()=%+20.17f\n",
angle_degrees, angle_radians, sum, sin(angle_radians));
}
return 0;
}
Output
sine(-360.00 degrees -6.283185 radians) = -0.00000000000000000 sin()=+0.00000000000000024
sine(-330.00 degrees -5.759587 radians) = +0.50000000000000000 sin()=+0.49999999999999967
sine(-300.00 degrees -5.235988 radians) = +0.86602540378443871 sin()=+0.86602540378443860
sine(-270.00 degrees -4.712389 radians) = +0.99999999999999989 sin()=+1.00000000000000000
sine(-240.00 degrees -4.188790 radians) = -0.86602540378443871 sin()=+0.86602540378443882
sine(-210.00 degrees -3.665191 radians) = -0.50000000000000000 sin()=+0.50000000000000011
sine(-180.00 degrees -3.141593 radians) = -0.00000000000000000 sin()=-0.00000000000000012
sine(-150.00 degrees -2.617994 radians) = -0.50000000000000000 sin()=-0.49999999999999994
sine(-120.00 degrees -2.094395 radians) = -0.86602540378443871 sin()=-0.86602540378443860
sine( -90.00 degrees -1.570796 radians) = -0.99999999999999989 sin()=-1.00000000000000000
sine( -60.00 degrees -1.047198 radians) = -0.86602540378443871 sin()=-0.86602540378443871
sine( -30.00 degrees -0.523599 radians) = -0.50000000000000000 sin()=-0.50000000000000000
sine( +0.00 degrees +0.000000 radians) = +0.00000000000000000 sin()=+0.00000000000000000
sine( +30.00 degrees +0.523599 radians) = +0.50000000000000000 sin()=+0.50000000000000000
sine( +60.00 degrees +1.047198 radians) = +0.86602540378443871 sin()=+0.86602540378443871
sine( +90.00 degrees +1.570796 radians) = +0.99999999999999989 sin()=+1.00000000000000000
sine(+120.00 degrees +2.094395 radians) = +0.86602540378443871 sin()=+0.86602540378443860
sine(+150.00 degrees +2.617994 radians) = +0.50000000000000000 sin()=+0.49999999999999994
sine(+180.00 degrees +3.141593 radians) = +0.00000000000000000 sin()=+0.00000000000000012
sine(+210.00 degrees +3.665191 radians) = +0.50000000000000000 sin()=-0.50000000000000011
sine(+240.00 degrees +4.188790 radians) = +0.86602540378443871 sin()=-0.86602540378443882
sine(+270.00 degrees +4.712389 radians) = -0.99999999999999989 sin()=-1.00000000000000000
sine(+300.00 degrees +5.235988 radians) = -0.86602540378443871 sin()=-0.86602540378443860
sine(+330.00 degrees +5.759587 radians) = -0.50000000000000000 sin()=-0.49999999999999967
sine(+360.00 degrees +6.283185 radians) = +0.00000000000000000 sin()=-0.00000000000000024
Some minor improvements could be made.
回答6:
Code allowing for arbitrary number of terms
Copying myself from https://stackoverflow.com/a/28227419/3088138
Avoiding the recomputation of recursive functions like powers of the same argument and factorials is always a good idea. Thus a reduction to (a minimal amount of) elementary arithmetic operations looks like this:
public static double sine(int terms, double x) {
double result = 1;
double mxx = -x*x;
double addens = 1;
double temp = 2;
for(int n = 2; n <= terms; n++) {
addens *= mxx/temp++/temp++;
result += addens;
}
return x*result;
}
To study a production quality implementation, you can visit the math library libmath of the basic calculator bc, the gnu version can be read at http://code.metager.de/source/xref/gnu/bc/1.06/bc/libmath.b
It normalizes the argument wrt. pi and then uses the Taylor series of sin.
Horner-like schema for fixed number of terms
If you are restricted to a fixed number of terms in the power series, you can use a Horner like code for its evaluation. As example, take 4 terms, then
x-x^3/3!+x^5/5!-x^7/7! = x*(1-x²/6*(1-x²/20*(1-x²/42)))
This can be put into a loop
res = 1
for( k=num_terms; k-->1;) {
res = 1-x*x*res/(2*k*(2*k+1))
}
res = res*x;
or you can unroll the loop
res = 1-x*x/42;
res = 1-x*x/20*res;
res = 1-x*x/6*res;
res = x*res;
You are free to combine x2=x*x
or to rename x=angle_radians
.
来源:https://stackoverflow.com/questions/33386361/c-program-taylor-series-long-formula