General Discussion > Math and Science

Approximating Tangent

(1/2) > >>

Xeda112358:
Hi again! This time I was fooling around with tangent (who knows why? I don't .__.) Anyways, I was having some fun and I figured out that Horner's method can be abused to approximate tangent by a similar logic I used to approximate arctangent: all you have to do is approximate infinitely many terms of the Maclaurin series with one simple function!


So before the fun, I'll show what Horner's method is (it's a super simple idea):
If you've never seen the identity that ##sin(x)=x-\frac{x^{3}}{3!}+\frac{x^{5}}{5!}-\frac{x^{7}}{7!}+...##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727d80")]);console.log("Queued!");, that's fine, just trust me (you'll get to that in calculus and it's crazy cool stuff). Horner's method is like what a true 31337 programmer would come up with if you want to efficiently approximate that polynomial. First, factor out the first term in the series (##x##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727d91")]);console.log("Queued!");):
##\sin(x)=x(1-\frac{x^{2}}{3!}+\frac{x^{4}}{5!}-\frac{x^{6}}{7!}+...##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727d9c")]);console.log("Queued!");
Now in that inside term, factor out the ##-\frac{x^{2}}{3!}##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727da6")]);console.log("Queued!");:

##\sin(x)=x(1-\frac{x^{2}}{3!}(1-\frac{x^{2}}{4\cdot 5}+\frac{x^{4}}{4\cdot 5\cdot 6\cdot 7\cdot }-\frac{x^{6}}{4\cdot 5\cdot 6\cdot 7\cdot 8\cdot 9}+...##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727db0")]);console.log("Queued!");
Rinse, repeat:

##\sin(x)=x(1-\frac{x^{2}}{3!}(1-\frac{x^{2}}{4\cdot 5}(1-\frac{x^{2}}{6\cdot 7}(1-\frac{x^{2}}{8\cdot 9}-...##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727dba")]);console.log("Queued!");
So the programmer sees, "aw, shweet, I only need to compute x2 once and reuse it a bunch of times with some constant multiplications!" So yeah, Horner's method is snazztacular, and I urge you to use it when possible.


Now let's look at tan(x). The Maclaurin series expansion for tan(x) is uuuugly. Each term uses Bernoulli numbers which are recursively computed and are intricately linked with some really cool functions like the Riemann Zeta function. For comparison (thanks to Mathworld for the table):

##\cos(x)=\sum\limits_{k=0}^{\infty}{\frac{(-1)^{k}}{(2k)!}x^{2k}}##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727dd1")]);console.log("Queued!"); (simple, cute, compact)
##\sin(x)=\sum\limits_{k=0}^{\infty}{\frac{(-1)^{k}}{(2k+1)!}x^{2k+1}}##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727ddc")]);console.log("Queued!"); (simple, cute, compact)
##\tan(x)=\sum\limits_{k=0}^{\infty}{\frac{(-1)^{k}4^{k+1}\left(4^{k+1}-1\right)B_{2k+2}}{(2k+2)!}x^{2k+1}}##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727de6")]);console.log("Queued!"); (wtf are math)
That's what it looks like to divide sine by cosine. Not pretty (well, okay, it is actually pretty gorgeous, but whatevs). So the first few terms of tan(x) are:
##\tan(x)=x+\frac{x^{3}}{3}+\frac{2x^{5}}{15}+\frac{17x^{7}}{315}+\frac{62x^{9}}{2835}+\frac{1382x^{11}}{155925}+...##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727df0")]);console.log("Queued!");
Nasty gorgeous, but applying Horner's Method, we end up with:
##\tan(x)=x(1+\frac{x^{2}}{3}(1+\frac{2x^{2}}{5}(1+\frac{17x^{2}}{42}(1+\frac{62x^{2}}{153}(1+...##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727e18")]);console.log("Queued!");

So seeing this, I realized, "wait a minute, those coefficients sure don't look like they are converging to zero or one, but something in between!" And that made me think about how ##\frac{1}{1-ax^{2}}=(1+ax^{2}(1+ax^{2}(1+ax^{2}(1+ax^{2}(1+...##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727e30")]);console.log("Queued!");. Now, I am a mathematician, but I am also a programmer so what I am about to say is blasphemous and I am sorry, but I decided to numerically evaluate and assume those constants converge. I ended up with approximately .405285. What I am saying is:

##\tan(x)\approx x(1+\frac{x^{2}}{3}(1+\frac{2x^{2}}{5}(1+\frac{17x^{2}}{42}(1+\frac{62x^{2}}{153}(1+.405285x^{2}(1+.405285x^{2}(1+.405285x^{2}(1+...##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727e3b")]);console.log("Queued!");
So then I ended up with:

##\tan(x)\approx x(1+\frac{x^{2}}{3}(1+\frac{2x^{2}}{5}(1+\frac{17x^{2}}{42}(1+\frac{62x^{2}}{153}\frac{1}{1-.405285x^{2}}))))##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727e46")]);console.log("Queued!");
##\tan(x)\approx x(1+\frac{x^{2}}{3}(1+\frac{2x^{2}}{5}(1+\frac{17x^{2}}{42}(1+\frac{62x^{2}}{153-62x^{2}}))))##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727e51")]);console.log("Queued!");
##\tan(x)\approx x(1+\frac{x^{2}}{3}(1+\frac{2x^{2}}{5}(1+\frac{17x^{2}}{42}\frac{153}{153-62x^{2}})))##MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById("bbclatex6631459727e5b")]);console.log("Queued!");It's still a bit of work to compute, but I had fun! No to do the mathy thing and actually prove the constants converge and maybe even find it's exact value!

pimathbrainiac:
Good job! Do you think this can have applications in z80 programming (is it faster, more memory efficient, etc.)?

ben_g:
I think that if you really want speed, you should use a LUT for the sine function, calculate the cosine as sine+90°, and calculate the tangent as sine/cosine. This does require a bit of memory and isn't really related to math though.

Related: I previously had no idea how the sine, cosine and tangent were actually calculated, and good job on simplifying it so much!

EDIT: while the z80 will probably not be able to calculate that at high speed for use in games, I guess it might be usefull for CAS-related programs.

Hooloovoo:
This is really cool! I found using ries that the constant is arctan(pi)/pi (if it turns out to be a constant, which seems to be the case).

EDIT: that is probably not correct. I just saw that first and it had a tangent in it. Looking at the others, 4/(pi^2) looks like it could be promising. But those are all approximations anyway.

TheCoder1998:
Wow this topic is really interesting!
It's pretty funny that I'm reading this now, because it's Math-day at school today :)

Navigation

[0] Message Index

[#] Next page

Go to full version