zoukankan      html  css  js  c++  java
  • 数学运算比IF要快

    问题

    虽然很早就知道,CPU在处理 if 这样的判断语句时,使用了预测的技术,所以如果条件总是一个结果,效率就很好。反过来说,如果你使用数学运算避免 if 判断,那么就意味着性能一定比 if 要好。

    方案1

    今天正好有个函数遇到这个问题,所以我就正好测试以下。

    待测试的方法是获取一个int32的数据中,有多少个位是 1,我的方案是将 一个int32拆开成 4个字节,然后一一判断。下面是使用 if 判断的方案 (那个  ? : 三元运算符就是 if 语句)。

     1 static int getInt32TrueCount(int value)
     2 {
     3     if (value == 0)
     4     {
     5         return 0;
     6     }
     7 
     8     return getByteTrueCount(value & 0xFF) +
     9         getByteTrueCount((value >> 8) & 0xFF) +
    10         getByteTrueCount((value >> 16) & 0xFF) +
    11         getByteTrueCount((value >> 24) & 0xFF);
    12 }
    13 
    14 static int getByteTrueCount(int value)
    15 {
    16     if (value == 0)
    17     {
    18         return 0;
    19     }
    20 
    21     int a = (value & 0x1) == 0 ? 0 : 1;
    22     int b = (value & 0x2) == 0 ? 0 : 1;
    23     int c = (value & 0x4) == 0 ? 0 : 1;
    24     int d = (value & 0x8) == 0 ? 0 : 1;
    25 
    26     int e = (value & 0x10) == 0 ? 0 : 1;
    27     int f = (value & 0x20) == 0 ? 0 : 1;
    28     int g = (value & 0x40) == 0 ? 0 : 1;
    29     int h = (value & 0x80) == 0 ? 0 : 1;
    30 
    31     return a + b + c + d + e + f + g + h;
    32 }

    可以看到, 每运算一个位都有一个 if 判断,而要命的是这个 if 判断的结果是不稳定的,随机性极大。我写了一个计时程序,在我计算机中需要 12秒。(i5 6500 Release .net core 2.0 )

     1 static void GetBitCountTest()
     2 {
     3     var wathch = Stopwatch.StartNew();
     4             
     5     var rand = new Random();
     6 
     7     for (int i = 0; i < 10000_0000; i++)
     8     {
     9         int value = rand.Next();
    10         int p = getInt32TrueCount(value);
    11     }
    12 
    13     wathch.Stop();
    14     Console.WriteLine("GetBitCount 耗时:" + wathch.Elapsed.ToString());
    15 
    16 }

    方案2

    第二种方法就是将 if 判断改为数学运算,方法是将 and 运算后的位 移动到 0位,这样就是 0 或 1 了。

     1 static int getInt32TrueCount2(int value) {
     2     if (value == 0) {
     3         return 0;
     4     }
     5 
     6     return getByteTrueCount2(value & 0xFF) +
     7         getByteTrueCount2((value >> 8) & 0xFF) +
     8         getByteTrueCount2((value >> 16) & 0xFF) +
     9         getByteTrueCount2((value >> 24) & 0xFF);
    10 }
    11 
    12 static int getByteTrueCount2(int value) {
    13     return (value & 0x1) +
    14             ((value & 0x2) >> 1) +
    15             ((value & 0x4) >> 2) +
    16             ((value & 0x8) >> 3) +
    17 
    18             ((value & 0x10) >> 4) +
    19             ((value & 0x20) >> 5) +
    20             ((value & 0x40) >> 6) +
    21             ((value & 0x80) >> 7);
    22 }

    再次运行测试用例,执行时间提高到 2 秒!提高了6倍。

    总结:

    高性能计算时,避免使用 分支 指令,尽量使用数学运算符。

  • 相关阅读:
    在 tornado 中异步无阻塞的执行耗时任务
    django在nginx uwsgi和tornado异步方案在项目中的体验
    使用tornado让你的请求异步非阻塞
    转:Parameter Server 详解
    转:复杂网络分析总结
    从SDCard获取的图片按分辨率处理的方法
    胡振亮:原来这就是非常多站点百度权重做不上去的原因
    c语言函数---I
    [LeetCode] Single Number III
    hdu 5389 Zero Escape (dp)
  • 原文地址:https://www.cnblogs.com/tansm/p/AvoidTheUseOfIf.html
Copyright © 2011-2022 走看看