前言
今天偶然翻到很久以前发的一条说说,可谓如获至宝啊!!!
涉及到返回一个数的绝对值,最快的方法是:
for (int i = 0; i < loops; i++)
{
for (int j = 0; j < 65535; j++)
{
tmp = array[j] * (1 - (array[j] >> 31) << 1);
}
}
测试
按道理说,语句里有乘法,应该会降低执行效率,可是不可思议的是,这个弱点被位移操作弥补了!!!
然而我不淡定了,我必须得测试下:
Console.WriteLine("To start press any key");
Console.ReadKey();
int[] array = new int[65535];
long[] counters = new long[3];
long ts = 0, dtstart = 0, freq = 0;
int tmp = 0, loops = 5000;
QueryPerformanceFrequency(ref freq);
#region generate
for (int i = 0; i < 65535; i++)
{
array[i] = i - 32768;
}
#endregion
QueryPerformanceCounter(ref dtstart);
#region RL RR
for (int i = 0; i < loops; i++)
{
for (int j = 0; j < 65535; j++)
{
tmp = array[j] * (1 - (int)((((uint)array[j]) >> 31) << 1));
}
}
#endregion
QueryPerformanceCounter(ref ts);
counters[0] = ts - dtstart;
QueryPerformanceCounter(ref dtstart);
#region triitem
for (int i = 0; i < loops; i++)
{
for (int j = 0; j < 65535; j++)
{
tmp = array[j] < 0 ? -array[j] : array[j];
}
}
#endregion
QueryPerformanceCounter(ref ts);
counters[1] = ts - dtstart;
QueryPerformanceCounter(ref dtstart);
#region ifcase
for (int i = 0; i < loops; i++)
{
for (int j = 0; j < 65535; j++)
{
if (array[j] < 0)
{
tmp = -array[j];
}
else
{
tmp = array[j];
}
}
}
#endregion
QueryPerformanceCounter(ref ts);
counters[2] = ts - dtstart;
Console.WriteLine("Three Methods cost {0}ms {1}ms {2}ms, respectively!", 1000 * counters[0] / freq, 1000 * counters[1] / freq, 1000 * counters[2] / freq);
Console.WriteLine("To end press any key");
Console.ReadKey();
输出结果
Three Methods cost 185ms 176ms 185ms, respectively, when loops=500!
Three Methods cost 330ms 364ms 367ms, respectively, when loops=1000!
Three Methods cost 1638ms 1822ms 1827ms, respectively, when loops=5000!
Three Methods cost 3221ms 3700ms 3669ms, respectively, when loops=10000!
Three Methods cost 16249ms 18901ms 20479ms, respectively, when loops=50000!
不要怀疑这个结果!!因为我把代码块的位置调换了几次结论都是一样的!
结论
可见,这种针对机器码优化过的代码效率很高,那么,将乘法直接改成位操作不是更快吗?
答案是不行,因为绝对值相同的正负数其数值部分的位态是不一样的。
另一个可以得出的结论是,三目的效率与if分支相当。