Author Topic: question about sine series in C programming  (Read 1430 times)

0 Members and 1 Guest are viewing this topic.

Offline khatusTopic starter

  • Regular Contributor
  • *
  • Posts: 147
  • Country: gl
question about sine series in C programming
« on: May 27, 2020, 04:13:39 am »
Code: [Select]
#include<stdio.h>

 
int main()
{
    int i, n;
    float x, sum, t;

     
    printf(" Enter the value for x : ");
    scanf("%f",&x);
     
    printf(" Enter the value for n : ");
    scanf("%d",&n);
     
    x=x*3.14159/180;
    sum = t=x;

     
    /* Loop to calculate the value of Sine */
    for(i=1;i<=n;i++)
    {
        t=(t*(-1)*x*x)/(2*i*(2*i+1));
        sum=sum+t;
        printf(" The value of Sin(%f) = %.4f\n",x,sum);
    }
     
    printf(" The value of Sin(%f) = %.4f",x,sum);
   
}



Hello guys in the above program

Let the value of x be 30.



So, Radian value for 30 degree is 0.52359.



but if i enter n=0 and x= 30 then the sum = 0.5236. But it should print the sum = 0.5236 for n=1 and x=30.because the first term in the series is x. why it prints 0.4997 instaed of 0.5236.
« Last Edit: May 27, 2020, 04:15:33 am by khatus »
 

Offline wizard69

  • Super Contributor
  • ***
  • Posts: 1184
  • Country: us
Re: question about sine series in C programming
« Reply #1 on: May 27, 2020, 06:54:25 am »
It is 2:30 in the morning so I'm only going to make a couple of suggestions.

Code: [Select]
#include<stdio.h>

 
int main()
{
    int i, n;
    float x, sum, t;

     
    printf(" Enter the value for x : ");
    scanf("%f",&x);
[/quote]
comments in your code are wonderful even better us variable names that are actually meaningful.   a reader of your code should be ble to understand what a variable represents any place in your code.
[quote]     
    printf(" Enter the value for n : ");
    scanf("%d",&n);
     
    x=x*3.14159/180;
    sum = t=x;

     
    /* Loop to calculate the value of Sine */
    for(i=1;i<=n;i++)
    {
        t=(t*(-1)*x*x)/(2*i*(2*i+1));
        sum=sum+t;
        printf(" The value of Sin(%f) = %.4f\n",x,sum);
    }
[/quote]
This would make more sense as a function.   More importantly a function like this should contain a comment that expresses exactly what formula it is trying to implement.   More importunity most programming languages come with factorial functions and power functions.   Use those to implement your code first.   If there is some reason not to; worry about it after getting the code to work.
[quote]     
    printf(" The value of Sin(%f) = %.4f",x,sum);
   
}



Hello guys in the above program

Let the value of x be 30.


It isn't clear that your code even implements this.
Quote
So, Radian value for 30 degree is 0.52359.



but if i enter n=0 and x= 30 then the sum = 0.5236. But it should print the sum = 0.5236 for n=1 and x=30.because the first term in the series is x. why it prints 0.4997 instaed of 0.5236.

Concentrate on order of operations or operator precedence.   Like I said it is late.
 

Offline Rick Law

  • Super Contributor
  • ***
  • Posts: 3476
  • Country: us
Re: question about sine series in C programming
« Reply #2 on: May 27, 2020, 07:51:01 am »
...
...
but if i enter n=0 and x= 30 then the sum = 0.5236. But it should print the sum = 0.5236 for n=1 and x=30.because the first term in the series is x. why it prints 0.4997 instaed of 0.5236.

Unless I misunderstood what you wrote (which is possible, it is 3:30am now)...

It is printing the right thing!

n=0, you have  0.5236, as you said, that is right

for n=1, you loop once.  Since your loop condition is i<=n and first loop i is 1 and n is 1.  So, you loop once.  You now have the second term in there:
0.5236 - ( x3 / 3!)
= 0.5236 - (0.5236*0.5236*0.5236)/(3*2)
= 0.5236 - 0.1435/6
= 0.5236 - 0.0239
= 0.4997

Think about if you mean i<n or i<=n...
 

Offline pwlps

  • Frequent Contributor
  • **
  • Posts: 372
  • Country: fr
Re: question about sine series in C programming
« Reply #3 on: May 28, 2020, 09:21:50 am »
You should learn using the debugger, this is typically a problem where running the code under debugger step by step will help a lot, if the loop count is incorrect you will see it immediately.
 

Offline Rick Law

  • Super Contributor
  • ***
  • Posts: 3476
  • Country: us
Re: question about sine series in C programming
« Reply #4 on: May 28, 2020, 09:46:14 pm »
You should learn using the debugger, this is typically a problem where running the code under debugger step by step will help a lot, if the loop count is incorrect you will see it immediately.

++ on pwlps' point

Debugger will help you a lot in learning the language.  A good practice is right after you write the code, walk through the code pretending you are the computer - do each step yourself and ask yourself is that correct?  When you are looping as you did in the code, you should walk the loop more than once:
1, the condition when it doesn't run,
2, the condition when it run the first time,
3, the middle while it is running,
4, the condition when it was about to exit,
5, the condition after it exits (after #4 is satisfied), would it restart?  Should it restart?

I mentally walk your code, and when I got to the loop condition, I discern that the way it works is not the same as you expected.  So that may be where the issue is - but then, may be not...  May be your expectation is wrong instead of the code being wrong.

You have to walk that and decide for yourself whether it was your expectation is wrong or the code is wrong.  Doing so, you will learn and understand it a hack of a lot better. 

It is 2:30 in the morning so I'm only going to make a couple of suggestions.
...
...
Concentrate on order of operations or operator precedence.   Like I said it is late.

Wizard69's point is important, people get trip up by that all the time.  When in doubt, add parenthesis.

That brings us to another important point often missed.  The manner you do things affects accuracy.  Doing arithmetic operations between large numbers and small numbers is where you must do considerable thinking about precision.  You have in your loop:
small_number * expression_with_very_large_number / even_larger_number;
So considerable thought must be done to avoid precision lost.

(a) What variable type you use:

You define your sum, t, and x as float.  I don't know what compiler you are using, so I can just apply "standard" or "typical" --  With float, you would be having 32 bit "single precision" with is 6 to 7 digits only.   double or long double (if your system supports that) would have a lot more precision.

(b.1) The way you enter it:

Be explicit, it will help as you look at the code during development and help in debugging when you look at the code a year later.  Being explicit will rely less on defaults which may differ from compiler implementations

x=x*3.14159/180;
Your x is float as declared.
3.14159 is double since it is a literal number with a decimal.
180 is a literal without decimal so it is an int, whereas 180.0 would have been a double.

So, as entered, you have:
float = float * double / int

I wont go too deep, but you can figure out why I would recommend this:
x = (double) x*3.14159/180.0;   // if you have to store x as a float
x = x*3.14159/180.0;   // if your x is declared as double

(b.2)  Propagation of accuracy error

Inside the loop, you have:
t=(t*(-1)*x*x)/(2*i*(2*i+1));
So the line expressed in value:
reused_small_value = reused_small_value* very_big_value / even_bigger_value

Not all numbers are divisible within given precision.  So when that occurs, you have a lost of precision.

I will start with my recommendation first, the explanation is easier to understand this way.
Store the numerator and the denominator separate:
// don't forget to first initialized Numerator and Denominator
for ( .... ) {
    Numerator = (Numerator*(-1)*x*x);
    Denominator = (Denominator *(2*i*(2*i+1)));
    sum = sum + (Numerator /Denominator);
}

Pretend in one of the loop you have a 20/60, you have 0.33 vs 0.3333 (I am truncating it shorter to illustrate the point),  the 0.0033 lost occur only in that loop when you keep the Numerator and Denominator separate.  So, once you leave that loop, you have that lost in the division accumulated in the sum and that is it (until you meet another similar situation).

Verses what you have:
for ( .... ) {
        t=(t*(-1)*x*x)/(2*i*(2*i+1));
        sum=sum+t;;
        ....
}
Your 0.0033 lost cause by the division will propagate into the next loop and beyond.  Besides the one time in the sum, the next loop you use the less precise t to do the multiplication when t=(t*(-1)*x*x)/... is next done, and again, and again in all future loops this point forward.

0.0033 propagate in sum is unavoidable, the error propagate in t is avoidable.  Each time you do the t*, you are using a less precise numerator.  Worst yet, you multiply that number with a very_large_value, which magnifies that error before you do the next division with an_ever_larger_value.

When you keep Numerator and Denominator separate, each division lost of precision is lost only once in the sum.  You don't propagate the prior division precision lost by reusing the t with inaccuracy from the last precision lost.

EDITed for typo - In an attempt to explain clearly, I was too wordy but that would be too much to change...
« Last Edit: May 28, 2020, 10:00:21 pm by Rick Law »
 

Offline Picuino

  • Super Contributor
  • ***
  • Posts: 1032
  • Country: es
    • Picuino web
Re: question about sine series in C programming
« Reply #5 on: May 28, 2020, 09:55:00 pm »
This series is very inefficient.
You should use chebyshev polynomials or the CORDIC algorithm.

http://mooooo.ooo/chebyshev-sine-approximation/
https://en.wikipedia.org/wiki/CORDIC
http://www.dcs.gla.ac.uk/~jhw/cordic/
 
The following users thanked this post: Tom45


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf