Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my sine algorithm much slower than the default?

Tags:

c#

inline

const double pi = 3.1415926535897;

static double mysin(double x) {
    return ((((((-0.000140298 * x - 0.00021075890) * x + 0.008703147) * x -
        0.0003853080) * x - 0.16641544) * x - 0.00010117316) * x +
        1.000023121) * x;
}

static void Main(string[] args) {
    Stopwatch sw = new Stopwatch();

    double a = 0;
    double[] arg = new double[1000000];
    for (int i = 0; i < 1000000; i++) {
        arg[i] = (pi / 2000000);
    } 
    sw.Restart();
    for (int i = 0; i < 1000000; i++) {
        a = a + Math.Sin(arg[i]);
    }
    sw.Stop();
    double t1 = (double)(sw.Elapsed.TotalMilliseconds);

    a = 0;
    sw.Restart();
    for (int i = 0; i < 1000000; i++) {
        a = a + mysin(arg[i]);
    }
    sw.Stop();
    double t2 = (double)(sw.Elapsed.TotalMilliseconds);
    Console.WriteLine("{0}\n{1}\n", t1,t2);
    Console.Read(); 
}

This power series is valid for [0,pi/2] and it is 10 times slower than the built in sine function in release mode. 1ms vs 10ms.

But when I copy paste mysin code into the function I get practically the same time in release and my code is about 4 times faster when in debug mode.

a = 0;
sw.Restart();
for (int i = 0; i < 1000000; i++) {
    double x = arg[i];
    a = a + ((((((-0.000140298 * x - 0.00021075890) * x + 0.008703147) * x -
        0.0003853080) * x - 0.16641544) * x - 0.00010117316) * x +
        1.000023121) * x;
    //a = a + mysin(arg[i]);
}

What is the deal here? How do I make this sort of calculations faster? I am guessing the code automatically recognizes that sin algorithm should not be called but copy paste into the loop. How do I make the compiler do the same for me.

One more question, would c++ do the same optimization for its default sin/cos function? If not how would I make sure that it does. Edit: I tested it and my sine function (with 4 extra if conditions added to expand the domain to all real) runs about 25% faster (albeit inaccurate) than the default sin function. And in fact, the copy pasted version runs slower than when I write it as a separate function.

like image 930
Gappy Hilmore Avatar asked Aug 03 '15 20:08

Gappy Hilmore


People also ask

How is sin algorithm calculated?

For example, to find out sine 23, first convert 23 to radians by dividing it by 180 and then multiplying by π. We get 23/180 π = 0.401425727958696 ≈ 0.4014257.

Are trig functions expensive?

While the quick answer is that they are more expensive than the primitive math functions (addition/multiplication/subtraction etc...) they are not -expensive- in terms of human time.

Can sine function value be bigger that 1 Why or why not?

No: If you let θ be an angle in a right angled triangle, we know that sin(θ) is equal to OppositeHypotenuse. We know that the Hypotenuse is never shorter than the line Opposite the angle θ, so this fraction can never exceed 1.


1 Answers

I assume that you tested this on x86, because I cannot repro the numbers on x64. On x64, your code actually appears to be faster.

I disassembled the code for x86/release. The reason for the difference is that your method is just that, a method whereas Math.Sin is compiled to use the x86 fsin instruction directly thus eliminating a function call per invocation.

FWIW, the x64 code is quite different. Math.Sin is translated into clr!COMDouble::Sin.

See FSIN.

like image 68
Brian Rasmussen Avatar answered Oct 01 '22 19:10

Brian Rasmussen