Thread: program for calculation of the sine of an angle using the sine series

  1. #16
    Registered User
    Join Date
    Oct 2009
    Posts
    27
    thanks a lot to everyone of you for this valuable enlightening.....i was completely baffled by the large values.....
    Last edited by Pulock2009; 10-26-2013 at 11:28 PM.

  2. #17
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Quote Originally Posted by Pulock2009 View Post
    thanks a lot to everyone of you for this valuable enlightening.....i was completely baffled by the large values.....
    Well unfortunately large values are not your only error (see my post) :-(

    But anyway, once you've fixed things I'd strongly consider only ever calculating values of sin(0) through to sin(90). Some may see this as an "optimisation" which in a way it is, but the more important thing is that it keeps the error (error in the sense of distance from ideal value) consistent. The two sources of error are the floating point numbers themselves and also the summation. By only calculating sin 0-90 you can derive the other values and have the same magnitude of error (which is desirable) for "related values". So, it's not an optimization in my point of view, its something to improve precision.

    Edit: if the (consistency of) margin of error is not important to you, at least consider deriving the sin of the angles 181-360 from the sin of the angles 0-179 basically because this allows you to use more iterations of the series before the factorial overflows.
    Last edited by SirPrattlepod; 10-26-2013 at 11:55 PM.

  3. #18
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Ok, I revisited this today. I don't think I can improve it any further... (apart from optimisations). The "Expect" column is using sin() from glibc (math.h)

    Code:
          Angle     Expect        n=4        n=5        n=6        n=7        n=8        n=9   Err. n=9
              0    0.00000    0.00000    0.00000    0.00000    0.00000    0.00000    0.00000    0.00000000000000
             10    0.17365    0.17365    0.17365    0.17365    0.17365    0.17365    0.17365    0.00000000000000
             20    0.34202    0.34202    0.34202    0.34202    0.34202    0.34202    0.34202    0.00000000000000
             30    0.50000    0.50000    0.50000    0.50000    0.50000    0.50000    0.50000    0.00000000000000
             40    0.64279    0.64279    0.64279    0.64279    0.64279    0.64279    0.64279    0.00000000000000
             50    0.76604    0.76604    0.76604    0.76604    0.76604    0.76604    0.76604   -0.00000000000000
             60    0.86603    0.86603    0.86603    0.86603    0.86603    0.86603    0.86603   -0.00000000000000
             70    0.93969    0.93969    0.93969    0.93969    0.93969    0.93969    0.93969    0.00000000000000
             80    0.98481    0.98481    0.98481    0.98481    0.98481    0.98481    0.98481   -0.00000000000000
             90    1.00000    1.00000    1.00000    1.00000    1.00000    1.00000    1.00000    0.00000000000000
            100    0.98481    0.98481    0.98481    0.98481    0.98481    0.98481    0.98481   -0.00000000000000
            110    0.93969    0.93969    0.93969    0.93969    0.93969    0.93969    0.93969    0.00000000000000
            120    0.86603    0.86603    0.86603    0.86603    0.86603    0.86603    0.86603    0.00000000000000
            130    0.76604    0.76604    0.76604    0.76604    0.76604    0.76604    0.76604    0.00000000000000
            140    0.64279    0.64279    0.64279    0.64279    0.64279    0.64279    0.64279    0.00000000000000
            150    0.50000    0.50000    0.50000    0.50000    0.50000    0.50000    0.50000    0.00000000000000
            160    0.34202    0.34202    0.34202    0.34202    0.34202    0.34202    0.34202    0.00000000000000
            170    0.17365    0.17365    0.17365    0.17365    0.17365    0.17365    0.17365    0.00000000000000
            180   -0.00000    0.00000    0.00000    0.00000    0.00000    0.00000    0.00000    0.00000000000000
            190   -0.17365   -0.17365   -0.17365   -0.17365   -0.17365   -0.17365   -0.17365    0.00000000000000
            200   -0.34202   -0.34202   -0.34202   -0.34202   -0.34202   -0.34202   -0.34202    0.00000000000000
            210   -0.50000   -0.50000   -0.50000   -0.50000   -0.50000   -0.50000   -0.50000    0.00000000000000
            220   -0.64279   -0.64279   -0.64279   -0.64279   -0.64279   -0.64279   -0.64279    0.00000000000000
            230   -0.76604   -0.76604   -0.76604   -0.76604   -0.76604   -0.76604   -0.76604    0.00000000000000
            240   -0.86603   -0.86603   -0.86603   -0.86603   -0.86603   -0.86603   -0.86603    0.00000000000000
            250   -0.93969   -0.93969   -0.93969   -0.93969   -0.93969   -0.93969   -0.93969    0.00000000000000
            260   -0.98481   -0.98481   -0.98481   -0.98481   -0.98481   -0.98481   -0.98481    0.00000000000000
            270   -1.00000   -1.00000   -1.00000   -1.00000   -1.00000   -1.00000   -1.00000    0.00000000000000
            280   -0.98481   -0.98481   -0.98481   -0.98481   -0.98481   -0.98481   -0.98481    0.00000000000000
            290   -0.93969   -0.93969   -0.93969   -0.93969   -0.93969   -0.93969   -0.93969   -0.00000000000000
            300   -0.86603   -0.86603   -0.86603   -0.86603   -0.86603   -0.86603   -0.86603   -0.00000000000000
            310   -0.76604   -0.76604   -0.76604   -0.76604   -0.76604   -0.76604   -0.76604   -0.00000000000000
            320   -0.64279   -0.64279   -0.64279   -0.64279   -0.64279   -0.64279   -0.64279   -0.00000000000000
            330   -0.50000   -0.50000   -0.50000   -0.50000   -0.50000   -0.50000   -0.50000   -0.00000000000000
            340   -0.34202   -0.34202   -0.34202   -0.34202   -0.34202   -0.34202   -0.34202   -0.00000000000000
            350   -0.17365   -0.17365   -0.17365   -0.17365   -0.17365   -0.17365   -0.17365   -0.00000000000000
            360   -0.00000    0.00000    0.00000    0.00000    0.00000    0.00000    0.00000    0.00000000000000
    Edit: Thanks Pulock2009 for an interesting thing to do in my spare time

    Edit 2: Some different values for 'n' and the columns now print the difference (error) from the expected value instead
    Code:
     Angle       Expect      Err n=1      Err n=3      Err n=5      Err n=7      Err n=9     Err n=11           |Error|
      -360  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
      -340  0.342020143 -0.000043062 -0.000000000 -0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
      -320  0.642787610 -0.001366063 -0.000000108 -0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
      -300  0.866025404 -0.010224622 -0.000004132 -0.000000000 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
      -280  0.984807753 -0.042225583 -0.000054610 -0.000000012 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
      -260  0.984807753 -0.042225583 -0.000054610 -0.000000012 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
      -240  0.866025404 -0.010224622 -0.000004132 -0.000000000 -0.000000000  0.000000000  0.000000000  0.00000000000000
      -220  0.642787610 -0.001366063 -0.000000108 -0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
      -200  0.342020143 -0.000043062 -0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
      -180  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
      -160  0.342020143 -0.000043062 -0.000000000 -0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
      -140  0.642787610 -0.001366063 -0.000000108 -0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
      -120  0.866025404 -0.010224622 -0.000004132 -0.000000000 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
      -100  0.984807753 -0.042225583 -0.000054610 -0.000000012 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
       -80  0.984807753 -0.042225583 -0.000054610 -0.000000012 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
       -60  0.866025404 -0.010224622 -0.000004132 -0.000000000 -0.000000000  0.000000000  0.000000000  0.00000000000000
       -40  0.642787610 -0.001366063 -0.000000108 -0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
       -20  0.342020143 -0.000043062 -0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
         0  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
        20  0.342020143 -0.000043062 -0.000000000 -0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
        40  0.642787610 -0.001366063 -0.000000108 -0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
        60  0.866025404 -0.010224622 -0.000004132 -0.000000000 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
        80  0.984807753 -0.042225583 -0.000054610 -0.000000012 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
       100  0.984807753 -0.042225583 -0.000054610 -0.000000012 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
       120  0.866025404 -0.010224622 -0.000004132 -0.000000000 -0.000000000  0.000000000  0.000000000  0.00000000000000
       140  0.642787610 -0.001366063 -0.000000108 -0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
       160  0.342020143 -0.000043062 -0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
       180 -0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
       200 -0.342020143  0.000043062  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
       220 -0.642787610  0.001366063  0.000000108  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
       240 -0.866025404  0.010224622  0.000004132  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
       260 -0.984807753  0.042225583  0.000054610  0.000000012  0.000000000  0.000000000  0.000000000  0.00000000000000
       280 -0.984807753  0.042225583  0.000054610  0.000000012  0.000000000  0.000000000  0.000000000  0.00000000000000
       300 -0.866025404  0.010224622  0.000004132  0.000000000  0.000000000 -0.000000000 -0.000000000  0.00000000000000
       320 -0.642787610  0.001366063  0.000000108  0.000000000 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
       340 -0.342020143  0.000043062  0.000000000 -0.000000000 -0.000000000 -0.000000000 -0.000000000  0.00000000000000
       360 -0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.000000000  0.00000000000000
    Last edited by SirPrattlepod; 10-27-2013 at 07:57 PM. Reason: New Table

  4. #19
    Registered User
    Join Date
    Oct 2013
    Posts
    3
    mistake in your fraction expression.

  5. #20
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Well, this assignment is well and truly over I think, so I'll paste. I can't get better than 15 decimal places of accuracy using this method.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <assert.h>
    #include <limits.h>
    #include <float.h>
    
    double rrduce(double x, double *sign);
    double deg2rad(double x);
    double mysin(double x);
    
    #define PI_DIV180   0.01745329251994329576923690768489
    
    void testsin(void)
    {
        int i;
        double esign;
        
        printf(" %6s %22s %22s %22s\n", "Angle", "Expect", "Got", "Error");
        
        for (i = 0; i <= 360; i += 1) {
            double angle = i/4.0;
            double r = mysin(angle);            
            double expected = sin(deg2rad(rrduce(angle, &esign)));
            expected *= esign;
            
            printf(" %6.2f %22.18f", angle, expected);
            printf(" %22.18f", r);
            printf(" %22.18f", r - expected);
            putchar('\n');
        }
    }
      
    int main(void)
    {
        testsin();
    
        return 0;
    }
    
    /* Range reduce */
    double rrduce(double x, double *sign)
    {
        if (x < 0)
            x = -x;         /* sin(-x) == -sin(x) */
        
        x = fmod(x, 360);
            
        if (x > 180) {       /* Mirror values > 180; those below the x-axis */
            x = x - 180; 
            *sign = -1;
        } else 
            *sign = 1;
        if (x > 90)         /* Reflect around x = 90 */
            x = 180 - x;
        
        return x;
    }
    
    double deg2rad(double x)
    {
        return x * PI_DIV180;
    }
    
    /* Calculate sin(x). 'x' is the angle in **degrees**
     */
    double mysin(double x)
    {
        double sign;
        unsigned i;
        double term, sum;
        double xsq;
        static const unsigned nterms = 10; // Max iterations
    
        x = deg2rad(rrduce(x, &sign));
        xsq = x*x;
            
        term = sum = x;
             
        /* Sum successive terms of the sine Taylor series */
        for(i = 0; i < nterms; i++) {
            //term = - term * x*x / (2*i+2) / (2*i+3);  // Less precise than (1)...
            //term = -term * x*x / ((2*i+2) * (2*i+3)); // Less precise than (1)...
            //(1) term = -term / ((2*i+2) * (2*i+3)) * x*x;
            //(2) term = -term / (10*i + 4*i*i + 6) * x*x;
            //(3) term = -term * 1 / (10*i + 4*i*i + 6) * x*x;
                    
            //term = -term * 1 / (4*i*i + 10*i + 6) * x*x;    // same as (1)...
            //term = 1 / (4*i*i + 10*i + 6) * x*x * (-term);  // a LOT less accurate
            //term = -term * x * 1 / (4*i*i + 10*i + 6) * x;  // a bit less accurate
            
            /* Also experimented with calcuating series using fraction and
             * 2^(exp); c.f. frexp(). No improvement.
             */
            
            term = -term / (10*i + 4*i*i + 6) * xsq;
    
    #ifdef MYSINEEARLYEXIT              // Makes no difference to final result
            if (fabs(term) <= 1e-17) {
                break;
            }
    #endif
            
            sum += term;
        }
    
        return sum * sign;
    }
    Last edited by SirPrattlepod; 10-30-2013 at 11:07 PM. Reason: removed rot13

  6. #21
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Lol does that code come in English? And I think you're right, I've noticed in some code that I've written that doubles will go down to like 15 or 16 decimal places. What about __float128 types?

  7. #22
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Quote Originally Posted by MutantJohn View Post
    Lol does that code come in English? And I think you're right, I've noticed in some code that I've written that doubles will go down to like 15 or 16 decimal places. What about __float128 types?
    I can do much better with long double[1], but I didn't want to go down that path mainly because I learned there are better methods for approximating sine :-) Floating point numbers are certainly tricky.

    Use rot13.com on the code

    [1] Edit: long double for the calcuations within mysin() that is... it still returns a double, just change the doubles to long doubles in mysin() if you want to play
    Last edited by SirPrattlepod; 10-30-2013 at 10:27 PM.

  8. #23
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Oops. I meant to edit not post a new post

  9. #24
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Lol I literally forgot the long double type existed. I do know though that long doubles were supposed to use like 80 bits but __float128 was supposed use the full 128 bits.

  10. #25
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by MutantJohn View Post
    Lol I literally forgot the long double type existed. I do know though that long doubles were supposed to use like 80 bits but __float128 was supposed use the full 128 bits.
    In the case of microsoft compilers, support for long doubles was dropped during the transition from 16 bit to 32/64 bit compilers. The old 16 compilers, like VC 2.2 or older, support 80 bit long doubles, but 32 bit and later compilers, like VC 4.0 or Visual Studio, treat long doubles the same as regular double, as 64 bit values. There's a call in VS2005 or later to set the internal floating point precision, but the variables are stuck with the 64 bit format unless you write a program in assembly language or use a different compiler tool set.

  11. #26
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    But gcc works "properly" right?

  12. #27
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Quote Originally Posted by MutantJohn View Post
    But gcc works "properly" right?
    Well, that's a good question.

    6.5.2s10
    There are three real floating types, designated as float, double, and long
    double.32) The set of values of the type float is a subset of the set of values of the
    type double; the set of values of the type double is a subset of the set of values of the
    type long double.
    I regard a subset not to be a subset if the subset is exactly the same as the superset (wow)

    But then Annex E says that the following are the minimum for those 3 types

    #define DBL_MAX 1E+37
    #define FLT_MAX 1E+37
    #define LDBL_MAX 1E+37
    And similarly DBL_EPSILON and LDBL_EPSILON appear to be allowed the same minimum

    #define DBL_EPSILON 1E-9
    #define DBL_MIN 1E-37
    #define FLT_EPSILON 1E-5
    #define FLT_MIN 1E-37
    #define LDBL_EPSILON 1E-9
    #define LDBL_MIN 1E-37
    Then we get to F.2 Types
    — The double type matches the IEC 60559 double format.
    — The long double type matches an IEC 60559 extended format,307) else a
    non-IEC 60559 extended format, else the IEC 60559 double format.

    ...
    307) ‘‘Extended’’ is IEC 60559’s double-extended data format. Extended refers to both the common 80-bit
    and quadruple 128-bit IEC 60559 formats.
    So I guess there's nothing really wrong with the Visual C interpretation.

    GCC must use 80-bit long doubles though because they're clearly more precise than double. I suppose I could look at float.h but I'm exhausted now!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Sine Rule calculation.
    By headshot119 in forum C++ Programming
    Replies: 3
    Last Post: 09-23-2009, 01:22 PM
  2. Sine series summation
    By kashya in forum C Programming
    Replies: 3
    Last Post: 12-17-2008, 08:00 PM
  3. Computing the sine of an angle
    By Bearcat in forum C Programming
    Replies: 1
    Last Post: 02-13-2002, 12:46 PM
  4. Sine Wave Program Help
    By Unregistered in forum C Programming
    Replies: 3
    Last Post: 10-19-2001, 12:33 AM
  5. sine C program with Power Series
    By Unregistered in forum C Programming
    Replies: 1
    Last Post: 10-08-2001, 10:46 AM

Tags for this Thread