1

I'm working on a project for our school and we are required to create a program that computes the approximation of the Taylor Expansion Series of sin x and cos x, only using <stdio.h> and without user-defined functions other than int main(), of all angles from -180 to 180 in increments of +5. the following is my code:

#include <stdio.h>
#define PI   3.141592653589
#define NUMBER_OF_TERMS    10

int
main()
{
    int cosctr, sinctr;
    double ctr, radi;
    double cosaccu, costerm, sinaccu, sinterm;

    for (ctr = -180; ctr < 185; ctr = ctr + 5) {
        radi = ctr * PI/180.0;
        cosctr = 1;
        cosaccu = 1;
        costerm = 1;
        sinctr = 2;
        sinaccu = radi;
        sinterm = radi;
        while (cosctr <= 2*NUMBER_OF_TERMS) {
            costerm = costerm*(-1)*(radi*radi)/(cosctr*(cosctr + 1));
            cosaccu = cosaccu + costerm;
            cosctr+=2;
        } do {
            sinterm = sinterm*(-1)*(radi*radi)/(sinctr*(sinctr + 1));
            sinaccu = sinaccu + sinterm;
            sinctr+=2;
        } while (sinctr <= 2*NUMBER_OF_TERMS);
        printf("%.2lf      %.12lf      %.12lf      %.12lf\n", ctr, radi, cosaccu, sinaccu);
    } return 0;
}

The code above is accurate for a 15 terms expansion approximation. however, if I change NUMBER_OF_TERMS to, for example, 5 or 10, the approximation is flawed.
Any suggestions?

Let me clarify: I need to obtain an approximation of 5 terms, 10 terms, and 15 terms. I cannot use any other library other than <stdio.h>. I cannot use any other functions outside of int main() (I apologize for the vagueness of my explanation before).
Please answer with the included corrected code.

cadaniluk
  • 15,027
  • 2
  • 39
  • 67
gabriel_741
  • 29
  • 1
  • 5
  • 1
    There's only so much you can do, does your assignment require more than number of iterations? How many digits of accuracy do you need? – Dai Oct 30 '15 at 09:12
  • "Without user-defined functions". You're not allowed to define functions? Or do you mean without using libraries? – Arc676 Oct 30 '15 at 09:15
  • 1
    In that program, `main()` is certainly a user-defined function. In other words, your requirements are strange and ... misleading. – unwind Oct 30 '15 at 09:34
  • Writing a program in c where you cannot make your own functions is a) impossible because main() is one, and b) if you can only use main() asinine and unhelpful. – Magisch Oct 30 '15 at 10:13
  • have a look at http://www.coranac.com/2009/07/sines/ –  Oct 30 '15 at 15:29
  • 1
    What do you mean by 'the approximation is flawed'? The approximation is more accurate, the more terms you include. That's how it works. Is the approximation more inaccurate than you expected? What output do you expect and what is it giving? – Marco Tompitak Nov 01 '15 at 09:41
  • 7
    "Please answer with the included corrected code." Uhm, no. You write the code, we'll *help* you. – cadaniluk Nov 01 '15 at 09:57
  • 1
    Actually it needs is the calculation of 0-45(0,5,10,15,20,25,30,35,40,45degrees). – BLUEPIXY Nov 01 '15 at 10:07
  • The Taylor expensions that you are computing are the Taylor expensions of sin and cos around zero. The closer you are from zero, the more precise it gets. Hence, the remark of @BLUEPIXY is really useful. Indeed, compute approximations of sin and cos in the range [-PI/4,PI/4] degrees and then use formulas like `sin(PI/2-x)=cos(x)` for x in [0,PI/4] to gain precision in the range [PI/4,PI/2]. – francis Nov 01 '15 at 10:19
  • 1
    Possible duplicate of [Taylor Series Expansion of cos x and sin x in C Programming without using math.h or user-defined functions](http://stackoverflow.com/questions/33432298/taylor-series-expansion-of-cos-x-and-sin-x-in-c-programming-without-using-math-h) – Jongware Nov 01 '15 at 11:31
  • Gratuitous rant: I can understand why they don't want you to use any built-in math routines (this is teaching you how those routines are typically implemented), but making you do everything in `main` is teaching bad programming practice IMO. What's the reason for disallowing additional user-defined functions? – John Bode Nov 01 '15 at 12:02

5 Answers5

1

I tried your code; it works fine for me, in that it does what it looks like it's designed to do. Here's a comparison between your code's output for the cosine at 5 and 10 terms and the same approximation as calculated by Mathematica. They agree up to <10^-12, i.e. your outputted precision.:

enter image description here

The only problem I see with your code is that, with the way you designed your loops, you're actually taking into account NUMBER_OF_TERMS + 1 terms if you count the first terms in the expansion (i.e. the constant term for the cosine, the linear term for the sine.) You start with this first term, and then your loop adds another NUMMBER_OF_TERMS terms. If that is not by design, you're actually approximating the functions with higher precision that you are expecting.

Marco Tompitak
  • 648
  • 1
  • 5
  • 12
  • would you please expand on your answer? i cannot seem to find NUMBER_OF_TERMS + 1 – gabriel_741 Nov 02 '15 at 01:58
  • Your loop calculates `NUMBER_OF_TERMS` terms but you already calculate one additional term before the loop starts. – Marco Tompitak Nov 02 '15 at 08:34
  • which loop? your answer is very vague, though i am extremely thankful you are answering. i know it's a pain, but i'm new to this and my professor is very strict regarding the specifications of the project – gabriel_741 Nov 03 '15 at 13:23
  • What's vague about it? You have two `while` loops in your code. These you use to successively calculate higher-order terms in your approximation. The code inside the loops is run a set number of times, namely `NUMBER_OF_TERMS`. Suppose `NUMBER_OF_TERMS` is 10. You get 10 terms in your approximation from the `while` loops. However, you already calculate one term before your loops start. So in total you get 11 terms. – Marco Tompitak Nov 03 '15 at 13:27
  • @gabriel_741 Is there a reason you unaccepted the answer? – Marco Tompitak Nov 04 '15 at 15:54
1

The key to high precession, yet simple calculation of sind(degrees) and cosd(degrees) is to reduce the range of degree to 0 to 90 first (or even 0 to 45), using the usual trigonometric adjustments with degree arrangements first.

Reductions:
angle = fmod(angle, 360) // reduce (-360..360) or use a = a - (int)(a/360)
sin(x) = -sin(-x) // reduce to [0..360)
cos(x) = cos(-x) // reduce to [0..360)
sin(x) = -sin(x-180) // reduce to [0..180)
cos(x) = -cos(x-180) // reduce to [0..180)
sin(x) = cos(90-x) // reduce to [0..90)
Further reductions:
For [45-90) use sin(x) = cos(90-x) // reduce to [0..45)

then convert to radians and use Taylor series expansion.

Example

Note: Since code is dealing with double, typically 17 digits of precision, no need to use a course PI approximation.

// #define PI   3.141592653589
#define PI   3.1415926535897932384626433832795
Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

By its very definition, a Taylor series is a summation of an infinite series of terms.

Thus, a Taylor finite expansion only is an approximation of the true result: as the number of terms increases, the accuracy of this approximation improves.

If there are enough terms, the approximation error at some point becomes unnoticeable. However, if you try lowering the number of terms, the approximation error increases and can detected.

In your case, the approximation error is below the detection threshold for NUMBER_OF_TERMS= 15, but becomes noticeable when NUMBER_OF_TERMS= 10 or less.

Daniel Strul
  • 1,458
  • 8
  • 16
  • thank you, but your answer does not answer my question. you explain WHY the inaccuracies occur, but you do not answer how to correct the code. – gabriel_741 Oct 31 '15 at 13:32
  • 1
    On common trick is to sum the terms backwards. Imagine you sum 1/2 + 1/4 + 1/8 etc. forwards. At some point the terms become negligible wrt to the sum due to limited precision, and the sum doesnt change anymore (the harmonic series 1/1 + 1/2 + 1/3 ... is a classic example, and seems to converge). A simple solution is to compute and store the terms in an array, and sum then backwards, starting from the smallest values. – Michel Billaud Oct 31 '15 at 14:40
0

The Taylor expansions of sin(x) and cos(x) takes longer to converge as x increases. But since these are periodic functions, you don't actually need to bother expanding the series for values outside the range 0-90°.

For values of x outside this range, use the following identities:

sin(x) = -sin(x+180°) = -sin(-x) = sin(180°-x)
cos(x) = -cos(x+180°) = cos(-x) = -cos(180°-x)

For example, sin(175°) = sin(5°), cos(-120°) = -cos(60°)

r3mainer
  • 23,981
  • 3
  • 51
  • 88
  • would you please clarify? preferably i would like to see your suggestion inserted into my code in a semantically acceptable way. your cooperation is appreciated. – gabriel_741 Oct 31 '15 at 13:33
0

i figured it out with help from another user. turns out i was calculating terms + 1, making the answer more accurate than intended. after 15 terms the changes are past the 12th decimal point, and therefore did not show on the results.

#include <stdio.h>
#define PI   3.141592653589
#define NUMBER_OF_TERMS 10 // 5 and 15 work as well

int
main()
{
    int cosctr, sinctr;
    double ctr, radi;
    double cosaccu, costerm, sinaccu, sinterm; // accu will be final answer, term will be added to accu

    for (ctr = -180; ctr < 185; ctr+=5) { // for loop; ctr initialized at -185 and added to in increments of 5 to produce degrees
        radi = ctr * PI/180.0; // calculation for radians (assigned to radi)
        cosctr = 1; // initialization for cos counter; must be included in loop to allow correct calculations of cos
        cosaccu = 1; // first term is 1
        costerm = 1; // base term, to be multiplied with termcalc formula
        sinctr = 2; // initialization for sin counter; must be included in loop to allow correct calculations of sin
        sinaccu = radi; // first term is x, or degrees in radians (radi)
        sinterm = radi; // base term for sin
     // cos calculation
     while (cosctr < 2*NUMBER_OF_TERMS-1) { // accuracy check, 2* since increments of 2; NOTE: actual values are (1, 3, 5,...)
        costerm = costerm*(-1)*(radi*radi)/(cosctr*(cosctr + 1)); // TERMCALC FORMULA; multiplying previous term with formula creates next term
        cosaccu = cosaccu + costerm; // addition of new term to previous sum; dependent on accuracy (NUMBER_OF_TERMS)
        cosctr+=2;
     } do { // sin calculation; identical to cos, albeit with substituted vars
        sinterm = sinterm*(-1)*(radi*radi)/(sinctr*(sinctr + 1));
        sinaccu = sinaccu + sinterm;
        sinctr+=2;
     } while (sinctr < 2*NUMBER_OF_TERMS-1); // accuracy check, 2* since increments of 2; NOTE: actual values are (2, 4, 6,...)
     printf("%.2lf\t%.12lf\t%.12lf\t%.12lf\n", ctr, radi, cosaccu, sinaccu); // final display; /t used for convenience
 } return 0; // finally!!!
}
gabriel_741
  • 29
  • 1
  • 5