Math.sin vs OurSin

date: January 31st, 2010

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 Main.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!

date: 20 Oct 2010 - 16:27:29, published by pinkninja
date: 22 Feb 2011 - 14:59:00, published by Anthony Pace
//try adding the variables<br /> var p2:Number = 0, sin:Number = 0;<br /> for (var i:int = 0; i &lt; 10000000; i++) {<br /> //to be fair for timing<br /> p2 = rad*rad;<br /> p3 = rad * p2;<br /> p5 = p3 * p2;<br /> p7 = p5 * p2;<br /> p9 = p7 * p2;<br /> p11 = p9 * p2;<br /> p13 = p11 * p2;<br /> sin = rad-p3/f3+p5/f5-p7/f7+p9/f9-p11/f11+p13/f13;<br /> }<br /> <br /> The above code should speed things up.