为什么我的正弦算法比默认算法慢得多?
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();
}
此幂级数对[0,pi/2]有效,在释放模式下比内置正弦函数慢10倍。 1 毫秒与 10 毫秒。
但是,当我将 mysin
代码复制到函数中时,我在发布时几乎获得了相同的时间,并且在调试模式下我的代码快了大约 4 倍。
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]);
}
这是怎么回事?我如何使这种计算更快?我猜代码会自动识别不应该调用 sin 算法,而是将其复制粘贴到循环中。如何让编译器为我做同样的事情。
还有一个问题,c++会对其默认的sin/cos函数做同样的优化吗?如果不是,我将如何确保它确实如此。编辑:我对其进行了测试,我的正弦函数(添加了 4 个额外的 if 条件以将域扩展为所有实数)运行速度比默认正弦函数快 25%(尽管不准确)。事实上,复制粘贴版本比我将它作为一个单独的函数编写时运行得更慢。
我假设您是在 x86 上测试的,因为我无法在 x64 上重现这些数字。在 x64 上,您的代码实际上看起来更快。
我反汇编了 x86/release 的代码。差异的原因是你的方法就是这样,一个方法 Math.Sin
被编译为直接使用 x86 fsin
指令,从而消除了每次调用的函数调用。
FWIW,x64 代码完全不同。 Math.Sin
翻译成 clr!COMDouble::Sin
.
见FSIN。
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();
}
此幂级数对[0,pi/2]有效,在释放模式下比内置正弦函数慢10倍。 1 毫秒与 10 毫秒。
但是,当我将 mysin
代码复制到函数中时,我在发布时几乎获得了相同的时间,并且在调试模式下我的代码快了大约 4 倍。
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]);
}
这是怎么回事?我如何使这种计算更快?我猜代码会自动识别不应该调用 sin 算法,而是将其复制粘贴到循环中。如何让编译器为我做同样的事情。
还有一个问题,c++会对其默认的sin/cos函数做同样的优化吗?如果不是,我将如何确保它确实如此。编辑:我对其进行了测试,我的正弦函数(添加了 4 个额外的 if 条件以将域扩展为所有实数)运行速度比默认正弦函数快 25%(尽管不准确)。事实上,复制粘贴版本比我将它作为一个单独的函数编写时运行得更慢。
我假设您是在 x86 上测试的,因为我无法在 x64 上重现这些数字。在 x64 上,您的代码实际上看起来更快。
我反汇编了 x86/release 的代码。差异的原因是你的方法就是这样,一个方法 Math.Sin
被编译为直接使用 x86 fsin
指令,从而消除了每次调用的函数调用。
FWIW,x64 代码完全不同。 Math.Sin
翻译成 clr!COMDouble::Sin
.
见FSIN。