C program - taylor series_long formula

女生的网名这么多〃 提交于 2019-12-11 09:54:56

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!