Reputation: 450
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
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