Calculating trig functions "from scratch?"

Started by
11 comments, last by Code-R 18 years, 9 months ago
So I have an "infinite precision calculator," and I want to add more complicated functions like sin/cos/etc. I assume that the way to do this would be with a Taylor series, but the numbers get really big, really quickly because of that factorial. Is there a really good way to do this, or should I just use the error bound formula to get a number of required loops and chug it out with the Taylor Series?
Advertisement
There's some forumals here to find sine, cosine, and tangent using calculus and other methods. Clicky!
I'm prety sure calculators like the TI line use Taylor series for their calculations. If it's good enough for TI calcs, it's probably good enough for your purposes.
Quote:Original post by sirSolarius
I assume that the way to do this would be with a Taylor series, but the numbers get really big, really quickly because of that factorial.


It doesn't have to.

After all, if

cos(x) = sum(n=0..∞, an) with
an = (-1)n.x2n / (2n)!

Then an+1 = -an * x*x / ((2n+1)*(2n+2))

So you can write:

multiprecision cosine(mutiprecision x, unsigned long n){   multiprecision result = 0;   multiprecision a = 1;   for(unsigned long i=0; i<=n; ++i)   {      result += a;      a *= -(x*x)/((2*n+1)*(2*n+2));   }   return result;}


No factorials involved.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
double sine(double x){      double xsquared = -1 * x * x, last = x;      for(int i = 3; i <= 21; x+= last *= xsquared/((i*i-i), i+=2);      return x;}


There's sine for you. I wrote it(I'm particularily fond of this nifty piece) in a few minutes right after the Calculus BC exam, since it was fresh on my mind. Basically, you can replace the number 21 with any number, with the higher the number, the higher the accuracy.
Sagar_Indurkhya - there's no need for such obfuscation, it won't make your code any faster.

double sine(double x){      const double xsquared = -1 * x * x;      double last = x;      for(int i = 3; i <= 21; i+=2)      {         x+= last;         last *= xsquared/(i*i-i);      }      return x;}
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:Original post by Mantear
I'm prety sure calculators like the TI line use Taylor series for their calculations. If it's good enough for TI calcs, it's probably good enough for your purposes.
Actually, calculators generaly use the faster 'CORDIC' method for trig.

Sagar's function above (which Fruny beautified) is how I calculate sine for my multi-precision math library. Cosine is very similiar. This method is 'good enough'.
Though to be picky, I'd write -x * x instead of -1 * x * x, and exit the loop only when the answer stops changing.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
Quote:Original post by Fruny
Sagar_Indurkhya - there's no need for such obfuscation, it won't make your code any faster.

(code)


Ok, I feel stupid since I took BC Calc last year, but where does this come from? I think it's just hard to see in c++ code for me.

I just figured that you need more and more loops to get accuracy the further you stray from your "a" value in the Taylor Series. Since the obvious answer is to use McClaurin, I figured that I would find the closest value of 2pi, calculate the offset from that and then put the value between 0 and 2pi. Then I could use McClaurin and add the offset back in.

Edit: Tried this, and got like .9794 for sin(.5) when calc.exe says it should be like .479....
	ChugNumber GetVal()	{		ChugNumber x=m_right->GetVal();		const ChugNumber xsquared = -x * x;		ChugNumber last=x;		int nLoops=21;			// change later		for(int i=3; i <= nLoops; i+=2)		{			x+=last;			last*= xsquared/(i*i-i);		}		return x;	}


[Edited by - sirSolarius on July 18, 2005 1:36:59 PM]
Quote:Original post by sirSolarius
Quote:Original post by Fruny
Sagar_Indurkhya - there's no need for such obfuscation, it won't make your code any faster.

(code)


Ok, I feel stupid since I took BC Calc last year, but where does this come from? I think it's just hard to see in c++ code for me.

I just figured that you need more and more loops to get accuracy the further you stray from your "a" value in the Taylor Series. Since the obvious answer is to use McClaurin, I figured that I would find the closest value of 2pi, calculate the offset from that and then put the value between 0 and 2pi. Then I could use McClaurin and add the offset back in.

Edit: Tried this, and got like .9794 for sin(.5) when calc.exe says it should be like .479....
	not shown here


Well, I am pretty sure I did stuff in my AB/BC class(studied both) your class probably didn't do. It was a self-study, w/o any teachers, at home, etc. Just some prepbooks, a few textbooks(I found the prepbooks better), and me and my computer. Since I have been programming for a long time, longer than I learned calculus, I naturally integrate everything I learn into programming. That probably helped me the most in terms of both my mathematics skills, aswell as my programming skills. So I studied during the year like this:

June 2004 -> February 2005
Mulled over differentiation, daydreamed, programmed, forgot about calculus... etc.

March 2005 - April 2005
Realized the exam was around the corner, finished diff, started integ.
I also did a lot of programming for expression parsers, and built a graphing calculuator application that could do integration and differentiation(numerical). This really helped me.

Last two weeks of April 2005
Studied all BC content.

Took exam

Wrote my math library(3/4th way).

The funny thing is that all these super arrogant BC seniors treated me like some shit on the road, as though I was some ambitious guy who couldn't make it happen. It was pretty depressing, since they effectively shut me out of attending any after school tutorial sessions. I once took home some homework 3 weeks before the exam, and couldn't do a single problem.

I took a practice exam(the released 2003 exam), and got about 68%.

2 days later I took the exam and got a 5. It was honestly my most confident exam in my whole life. I actually enjoyed taking it, and got almost every question right(still not clear over problem 3, last part).

I was surprised, considering I am the guy who got the lowest score on the 1st semester math exam(precalc) and scraped a C. Calculus helped me a lot. It gave me insight into all my other subjects, and extended my ability to understand more difficult topics. Next year(gonna be a junior, woot!), I look forward to multivariable and graph theory.

I know that you probably think that I am just boasting or something(I think I am, sorry), but I feel that if other kids like me come on these forums, they get something out of it. I remember when I use to go and ask for help, people would just tell me to go home, and work on something achievable. It is also something I am extremely proud of myself for. I don't fare well at competitions like AMC or USACO, and after I got a 4 on AP Stats, I was pretty upset, so this really helped me out.

Anyway, long post, but let me get to my function:

double sine(double x){      double xsquared = -1 * x * x, last = x;      for(int i = 3; i <= 21; x+= last *= xsquared/((i*i-i), i+=2);      return x;}


our taylor function looks something like this:

sin(x) = x - (x^3)/(3!) + (x^5)/(5!) - (x^7)/(7!) + ...

which you will notice follows the pattern:

(x^n)/(n!) where n is odd.

so what I did was set xsquared as -1 * x^2

and last as x.

Now x already holds the value of x, something we can take advantage of.

we do x += (last *= xsquared/(i * (i - 1))), and add 2 to i(keeping it odd)

which gives us a very accurate answer.

Note: you can calculuate accuracy in linear time, which is good( O(n) I believe), where n is degree of accuracy.

If you want to use it for any number however, you have to do some tricky manipulation, because all values are essentially between -PI and PI.

hmmm... way to long a post. Hope it helped.
Yeah I definitely did the Taylor Series in my calc class, I just wasn't paying attention to how you were structuring it in your code.

And no offense, but the 5 on the AP probably is the same as your 68%. The scale generally gives a 5 for a 60-70%+ score, without counting the written section. You also cannot ever find out your answers, so saying that you got "almost every question right" is misleading because you could have gotten a 70% for all you know =)

Anyway, I must have done something stupid in my algorithm, since it's so far off. Argh, I'm going to take a look and see what's up...

This topic is closed to new replies.

Advertisement