Home Tutorials Forums Articles Blogs Movies Library Employment Press
By Alex Nino
|
Published
Hi guys, last night I been reading some articles and forums where I found that there are some people having problems with performance of the Math.sin function and its brothers (Math.cos, Math.atan…). One of these guys is making a cannon game with quite many particles on the stage rotating in direction to the mouse cursor on the fly. He made it remember a quite old code I did ages ago in ActionScript 1, flash 4 (in 1998) when flash player didn’t have any support of the Math Class and we had to do everything dirty by our self.

Well I was making a quite similar game where I got a cannon that needs to be moved depending on the mouse cursor position and in that moment in flash 4 any simple thing was a nightmare. I remember that I spent “an eternity” trying to make my own sine function, but at the end it worked fine and I survived one more time.

Nowadays in most of our scenarios the Flash Math.sin function is quite useful and acceptable in terms of performance but I have to confess that I always try to avoid it, I’m not fun of it at all, these functions are quite heavy and take a lot of our CPU time when we use them a lot in blocks of code. It seems to me that I’m not alone having problems with it, there are people out there unsatisfied with it and I can understand why. Some people have even developed their own functions for extracting the sine values faster like this guy using a table with its values stored which allows him to extract an approximation value in one of his expirements. That was interesting! take a look on his approach. Fast and accurate sine/cosine approximation, at the end he used a quadratic formula based on this article, it was so cool!

Okay guys, as I said I built my own sine function ages ago based on the Tylor series (trigonometric formulas), that are the same Adobe is using I think but with the tiny difference that we have more control on it and for some strange reason is a bit faster.

If you take a look on Wikipedia in the section series definitions you can see that the formula for defining a sin value is: sine of x (in radians) = x - (x3/3!) + (x5/5!) - (x7/7!) + (x9/9!) - (x11/11!) + (x13/13!) - … and so on, the more fractions the more accuracy. For those who doesn’t know what the exclamation symbol means, it means factorial, it is the product of multiplying all positive integers less than or equal to the value given for example: factorial of 4 is 24 because of 1x2x3x4 = 24, okay?

So I did exactly the same and it works fine, what took my attention is that it is a bit faster than Math.sin, it depends a lot on how we implement it. Its implementation cannot be as part of a Class (I mean it cannot be a method of an object), even less a Static class, you have to implement the whole function in the block where you most will use it. That’s how we code in flash for making things run fast! without functions, nor classes, nor objects, everything in a single block of code. I think that it is not necessary to say that we are speaking about extremely situations.

Here we are! These are the results of the experiment I did today using the flash player release version WIN 10,0,45,2. I chose the number 12.83 degrees and I just make the Math.sin function process it 10 million (10.000.000) times in a loop.

Math.sin() function takes 797 milliseconds for processing a value 10 million iterations and my sine action took (in first 3 cases losing quality):

312 milliseconds in ‘low resolution’, 60.85% faster than Math.sin
result: Math.sin:0.22205905423468852 vs OurSin:0.2220590598322028

406 milliseconds in ‘acceptable resolution’, 49.05% faster than Math.sin
result: Math.sin:0.22205905423468852 vs OurSin:0.22205905423078934

515 milliseconds in ‘good resolution’, 35.38% faster than Math.sin
result:Math.sin:0.22205905423468852 vs OurSin:0.2220590542346903

734 milliseconds in ‘extremely high resolution’, 7.904% faster than Math.sin
Math.sin:0.22205905423468852 vs OurSin:0.22205905423468852 => exactly the same resolution.

So, now you know that if you are in an extremely situation you can implement this code in your program and use a proper accuracy level. Note that all tests I did I run them in the release version of the flash player, it is completely point less make this comparison using the debug player version, the result is completely inadequate. The final users will never use the debug player (just us, the poor developers). However running same test using the debug version of flash player in ‘extremely high resolution’ the Math.sin took 1141 milliseconds and OurSin took 890 milliseconds 21.99% faster. :D

Hmmm… what else? Can you image what’s the sine of 30 degrees using OurSin in high resolution? 0.5! unlike the Math.sin that returns 0.49999999999999994, lol!!

Here is the source code (just copy and paste it in a Class.as and compile it):

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.system.Capabilities;
    import flash.text.TextField;
    public class Main extends Sprite {       
        public function Main():void {           
            var deg:Number = 12.83; //our value in degrees.
            var rad:Number = deg*(Math.PI/180); //conver degrees to radians.           
            var sin:Number; //variable where we store result.
            var time:Number = new Date().getTime(); //get the time from the bios.           
            //code by Alex Nino, yoambulante.com
            //these are our factorial constant values
            /* [BEGIN] */           
            var f3:Number = (1 * 2 * 3);
            var f5:Number = (f3 * 4 * 5);
            var f7:Number = (f5 * 6 * 7);
            var f9:Number = (f7 * 8 * 9);
            var f11:Number = (f9 * 10 * 11);
            var f13:Number = (f11 * 12 * 13);           
            //these are the variables where we store the powers,
            //note they have to be defined each time we execute the function           
            var p3:Number;
            var p5:Number;
            var p7:Number;
            var p9:Number;
            var p11:Number;
            var p13:Number;
            /* [END] */
            for (var i:int = 0; i < 10000000; i++) {              
                /* [BEGIN] */
                p3 = rad * rad * rad;
                p5 = p3 * rad * rad;
               
                //low resolution
                //sin = rad - (p3 / f3) + (p5 / f5);
               
                //aceptable resolution
                p7 = p5 * rad * rad;
                sin = rad - (p3 / f3) + (p5 / f5) - (p7 / f7);
               
                //good resolution               
                /*p7 = p5 * rad * rad;
                p9 = p7 * rad * rad;
                sin = rad - (p3 / f3) + (p5 / f5) - (p7 / f7) + (p9 / f9);*/
               
                //excelent resolution               
                /*p7 = p5 * rad * rad;
                p9 = p7 * rad * rad;
                p11 = p9 * rad * rad;
                p13 = p11 * rad * rad;
                sin = rad - (p3 / f3) + (p5 / f5) - (p7 / f7) + (p9 / f9) - (p11 / f11) + (p13 / f13);*/
               
                /* [END] */
                //uncoment next line and comment the block above for testing the flash Math.sin function.
                //sin = Math.sin(rad);               
            }
            time = new Date().getTime() - time; //check the time difference, how long it took!
            var field:TextField = new TextField(); //create a textfield for showing results.
            field.width = 600; //total text width.
            field.text = "FlashPlayer:"+Capabilities.version+" => "+time + " ms, resolution => Math.sin:"+Math.sin(rad)+" vs OurSin:"+sin; //show results.
            addChild(field); //show the textfield on the screen.
        }
       
    }   
}

Cheers!



Spread The Word


4 Responses to "Math.sin vs OurSin"

 
Greg K
said this on 27 Jul 2010 4:47:26 PM EST
interesting approach. I'll have to try it. There's one flaw however. Taylor series only approximate Sine wave in the range of a single circle. The more polinomials you add, the wider the approximation, but even with ...-rad^23/23! you will still only have accuracy from -9 to +9 radians. Now add to your timing calculation normalization of the angle (while(rad>PI*2)rad-=PI*2;while(rad<-PI*2)rad+=PI*2;) and you'll have a VEEEERY different time table. Make sure to run your tests in a non-debug flash player (export release build), because in debug mode assignments are type validated.

 
Anthony Pace
said this on 25 Mar 2011 3:45:05 AM EST
It's a good article; yet, here is a way you could tune the algorithm a bit.
.
For Example, take a look at how many times you are calling rad*rad...
Why not just make a var called p2 which represent rad to the power of 2, and replace the extra multiplications? Instantly you get rid of 8 multiplications.

With that said, I like the fact that you are showing people how to use a MacLauren Series.

 
pianisimo
said this on 10 Jun 2011 10:24:35 AM EST
Well this is nice the formulas sure comes from Taylor's series, but in order to do the: "sine of x (in radians) = x - (x3/3!) + (x5/5!) - (x7/7!) + (x9/9!) - (x11/11!) + (x13/13!)" I still need to use the Math class, or should I do it manually as well?

 
Joanne
said this on 25 Mar 2013 9:27:32 AM EST
Hmm is anyone else having problems with the pictures on this blog
loading? I'm trying to find out if its a problem on my end or if it's the blog.


Any feed-back would be greatly appreciated.




Leave a reply:
Your Name *: Email (private) *: Website:
Please copy the characters from the image below into the text field below. Doing this helps us prevent automated submissions.
Security Code: img

Copyright 2000-2013 ActionScript.org. All Rights Reserved.
Your use of this site is subject to our Privacy Policy and Terms of Use.