除法和乘法与位移的差异

时间:2014-06-15 18:30:54

标签: c# performance division bit-shift

声明

想知道何时或是否在我的代码中使用移位运算符,我对为什么倍增感兴趣将位移到左边而不是除法。


当我四处闲逛时,我遇到了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()方法填充。

1 个答案:

答案 0 :(得分:0)

总结评论中已经提到的答案:

  • 乘法以及位移更快,因为CPU的本机操作也是如此。它需要一个周期,而位移大约需要四个,这就是它更快的原因。分部需要11到18个周期。

  • 使用C#我无法接近CPU以获得诊断结果,因为在我的代码和CPU之间进行了许多优化。

  • 此外,微基准测试很难并且会产生错误的结果,这也可能因上述原因而发生。

如果我忘了什么,请评论并告诉我!