question about sine series in C programming - Page 1
Forum section: electronics / beginners

author: khatus
author_rank: Regular Contributor
timestamp: May 27, 2020, 04:13:39 am
content: Code:#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 programLet 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.

author: wizard69
author_rank: Super Contributor
timestamp: May 27, 2020, 06:54:25 am
content: It is 2:30 in the morning so I'm only going to make a couple of suggestions.Quote from: khatus on May 27, 2020, 04:13:39 amIt isn't clear that your code even implements this.QuoteConcentrate on order of operations or operator precedence. Like I said it is late.

author: Rick Law
author_rank: Super Contributor
timestamp: May 27, 2020, 07:51:01 am
content: Quote from: khatus on May 27, 2020, 04:13:39 amUnless 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 rightfor n=1,you loop once. Since your loop condition isi<=nand first loopiis 1 andnis 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.4997Think about if you meani<nori<=n...

author: pwlps
author_rank: Frequent Contributor
timestamp: May 28, 2020, 09:21:50 am
content: 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.

author: Rick Law
author_rank: Super Contributor
timestamp: May 28, 2020, 09:46:14 pm
content: Quote from: pwlps on May 28, 2020, 09:21:50 am++ on pwlps' pointDebugger 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 thatthe 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.Quote from: wizard69 on May 27, 2020, 06:54:25 amWizard69'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 betweenlarge numbers and small numbersis 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 asfloat. I don't know what compiler you are using, so I can just apply "standard" or "typical" -- Withfloat, you would be having 32 bit "single precision" with is 6 to 7 digits only.doubleorlong 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 implementationsx=x*3.14159/180;Yourxisfloatas declared.3.14159isdoublesince it is a literal number with a decimal.180is a literal without decimal so it is anint, whereas180.0would have been adouble.So, as entered, you have:float = float * double / intI 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 floatx = x*3.14159/180.0; // if your x is declared as double(b.2) Propagation of accuracy errorInside 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_valueNot 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 Denominatorfor ( .... ) {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 thesumand 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 thesum, the next loop you use the less precisetto 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 insumis unavoidable, the error propagate intis avoidable. Each time you do thet*, 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 thetwith 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...

author: Picuino
author_rank: Super Contributor
timestamp: May 28, 2020, 09:55:00 pm
content: 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/CORDIChttp://www.dcs.gla.ac.uk/~jhw/cordic/