Please note that ExpatTech no longer operates regular office hours, meeting is by appointment only. Please call +36306031104 for details.

ExpatTech Techblog

Peter Todd 2009.07.03. 13:34

Flash Cookbook - Optimisation - optimizing flash code Part 2 - fast sine function

Using trignometric functions brings up a question of memory. Trigonometric functions are famous about slowing down everything... (if they're not, then we say it now).

The 50 point question is: is there a way to fasten Math.sin(x)?

The answer is yes, there is. But you have to consider one thing. Math.sin() function returns with a relatively high precision. Probably you won't find a way to override the speed of that precision, but actually, do we need that?

If you are not writing a high precision calculator, but handling pixel-level animations, how much do you need? Let's say first we want to reach a 4 digit precisity. This is what we have in mathematical tables, this is what people used over the centuries...

Okay, but how do we calculate the sine? Our beloved mathematics gives us the solution. There is a known mathematical function called Taylor-function (discovered by the hindi science long time ago). Taylor-function is our friend in this battle. Calculating the right length of the so called Taylor-serie of sine gives the desired precision.

How does this look like? Good question.

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

there you go.

so, we know now the secret, let's translate this to flash-language:

function taylor1(x:Number):Number
{
    var sin:Number =
    x -
    x*x*x / 6 +
    x*x*x*x*x / 120 -
    x*x*x*x*x*x*x / 5040 +
    x*x*x*x*x*x*x*x*x /362880 -
    x*x*x*x*x*x*x*x*x*x*x / 39916800 +
    x*x*x*x*x*x*x*x*x*x*x*x*x / 6227020800 -
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x / 1307674368000 +
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x / 355687428096000 -
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x / 121645100408832000 +
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x / 51090942171709440000 -
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x / 25852016738884976640000 +
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x / 15511210043330985984000000;

    return sin;
}

As you can see we left out Math.pow() aswell and calculated all the factorials.

Since we want to optimize our code some additional steps can be done:

- leave out division. You can calculate 1 / n for each n, where n is the specific factorial. But we did something else:

Create variables outside the taylor function like: var a1:Number = 1 / n! (how to calculate n factor is up to you).

- don't create local variable sin:Number. just return the whole number. Here it is:

function taylor2(x:Number):Number
{
    return x -
    x*x*x * a1 +
    x*x*x*x*x * a2 -
    x*x*x*x*x*x*x * a3 +
    x*x*x*x*x*x*x*x*x * a4 -
    x*x*x*x*x*x*x*x*x*x*x * a5 +
    x*x*x*x*x*x*x*x*x*x*x*x*x * a6 -
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x * a7 +
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x * a8 -
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x * a9 +
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x * a10 -
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x * a11 +
    x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x * a12;
}

Let's see some results:

Math.sin() runs 1 million times at an average of 3703.6 ms

and the Taylor-trick: 2601 ms.

Yes. True. Precision is the key.

Question: do other functions have their Taylor-series aswell?

Good quesion, little padawan.

Yes. Every Math class function has its own Taylor-serie.