我不想知道何时或是否在我的代码中使用移位运算符,我对为什么倍增感兴趣将位移到左边而不是除法。
当我四处闲逛时,我遇到了this关于划分和位移的效率和速度的问题。它基本上表明,虽然在2的幂上执行位移时可能会节省几秒钟,但是不必担心一些差异。
对此感到好奇,我决定检查C#中的位移实际上有多快,并实现了一些奇怪的事情:
正如我预期的那样,位移而不是分频更快,但“正常”乘法方法比位移更快。
我的问题很简单:为什么两位数的乘法比位移更快,尽管位移是处理器的基本操作?
以下是我的测试用例的结果:
Division: | Multiplication:
Bit shift: 315ms | 315ms
normal: 406ms | 261ms
时间是100个案例的平均值,每个案例包含10000个随机正数(从1到int.MaxValue
)的每个数字10次操作。操作范围从分割/乘以2到1024(以2为单位)和从1到10位的位移。
@usr:我使用的是.NET 4.5.1版
我更新了我的结果,因为我意识到我只计算了我说过的数字的十分之一...... facepalm
我的主要:
static Main(string[] args)
{
Fill(); // fills the array with random numbers
Profile("division shift:", 100, BitShiftDiv);
Profile("division:", 100, Div);
Profile("multiplication shift:", 100, BitShiftMul);
Profile("multiplication:", 100, Mul);
Console.ReadKey();
}
这是我的分析方法:
static void Profile(string description, int iterations, Action func)
{
GC.Collect()
GC.WaitForPendingFinalizers();
GC.Collect();
func();
Stopwatch stopWatch = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
func();
}
stopWatch.Stop();
Console.WriteLine(description);
Console.WriteLine("total: {0}ms", stopWatch.Elapsed.TotalMilliseconds);
Console.WriteLine(" avg: {0}ms", stopWatch.Elapsed.TotalMilliseconds / (double)iterations);
}
包含操作的Actions的结构如下:
static void <Name>()
{
for (int s = 1; s <= 10; s++) /* for shifts */
for (int s = 2; s <= 1024; s++) /* for others */
{
for (int i = 0; i < nums.Length; i++)
{
var useless = nums[i] <shift> s; /* shifting */
var useless = nums[i] <operator> s; /* otherwise */
}
}
}
nums
是包含10000000
int
的公开数组,由Fill()
方法填充。
答案 0 :(得分:0)
总结评论中已经提到的答案:
乘法以及位移更快,因为CPU的本机操作也是如此。它需要一个周期,而位移大约需要四个,这就是它更快的原因。分部需要11到18个周期。
使用C#我无法接近CPU以获得诊断结果,因为在我的代码和CPU之间进行了许多优化。
此外,微基准测试很难并且会产生错误的结果,这也可能因上述原因而发生。
如果我忘了什么,请评论并告诉我!