Gappy Hilmore
Gappy Hilmore

Reputation: 450

Why is my sine algorithm much slower than the default?

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.

Upvotes: 7

Views: 275

Answers (1)

Brian Rasmussen
Brian Rasmussen

Reputation: 116401

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.

Upvotes: 3

Related Questions