zoukankan      html  css  js  c++  java
  • 关于CoolShell博客中提到的一个代码优化的解读

    原博客在此:代码执行的效率

    那么,我们的搬道器是怎么预判的呢?就是使用过去的历史数据,如果历史数据有90%以上的走左边,那么就走左边。所以,我们排好序的数据就更容易猜得对。

    T = 走分支(条件表达式为true)
    N = 不走分支(条件表达式为false)
    
    data[] = 0, 1, 2, 3, 4, ... 126, 127, 128, 129, 130, ... 250, 251, 252, ...
    branch = N  N  N  N  N  ...   N    N    T    T    T  ...   T    T    T  ...
    
    = NNNNNNNNNNNN ... NNNNNNNTTTTTTTTT ... TTTTTTTTTT  (easy to predict)
    data[] = 226, 185, 125, 158, 198, 144, 217, 79, 202, 118,  14, 150, 177, 182, 133, ...
    branch =   T,   T,   N,   T,   T,   T,   T,  N,   T,   N,   N,   T,   T,   T,   N  ...
    
    = TTNTTTTNTNNTTTN ...   (completely random - hard to predict)

    从上面我们可以看到,排好序的数据更容易预测分支。

    对此,那我们怎么办?我们需要在这种循环中除去if-else语句。比如:

    我们把条件语句:

    if (data[j] >= 128)
    sum += data[j];
    

    变成:

    int t = (data[j] - 128) >> 31;
    sum += ~t & data[j];

    “没有分叉”的性能基本上和“排好序有分支”一个样,无论是C/C++,还是Java。

    对于最后一部分的去分支化代码,第一遍竟然没看懂,复习了一下,将结果记录下来:

    int t = (data[j] – 128) >> 31;

    这行代码得到t只有两个值:0和-1.当data[j]小于128时得到1,大于等于128时得到0.这行代码可以分解为:

    t = data[j] – 128;

    t = t >> 31;

    由于负数在计算机内是由对应正数的补码表示,所以假如t==-1,计算机(32位机)内实际保存的内容是:0xffffffff。最高位符号位为1.

    而对于移位运算,也分为操作数是有符号数和无符号数两种情况:若是无符号数,左端全部补零;若是有符号数,左端补的是有符号数的符号位。

    所以当t小于0时,左边补的是符号位1,得到的结果是-1,也就是0xFFFFFFFF。

    当t大于等于0时,左边补的是符号位0,得到的结果是0, 也就是0x00000000。

    再往下看:

    sum += ~t & data[j];

    所以此时~t的值正好跟上一步的结果倒过来,分别是:0x00000000和0xFFFFFFFF。

    再做一次与运算,假如当前数小于128,~t & data[j]的值等于0;假如当前数大于127,~t & data[j]的值还是data[j]。

    所以就省去了一次JL跳转指令,从而获得性能上的提升。

    总结一句:

    对于排好序的数据,更容易预测分支,所以更容易获得代码效率的提升。

    但假如数据未排好序时,就不容易预测分支,所以无法提升代码执行效率。

    遇到这样的问题怎么办呢?就消除分支!

  • 相关阅读:
    Python 自学笔记(二)
    Python 自学笔记(一)
    java.net.MalformedURLException: unknown protocol: 异常
    选择排序精简理解
    JAVA基于File的基本的增删改查
    Oracle常用操作表结构的语句
    jQuery
    基于jquery的ajax方法封装
    javascript运算符——条件、逗号、赋值、()和void运算符 (转载)
    javascript 闭包
  • 原文地址:https://www.cnblogs.com/tara/p/2593145.html
Copyright © 2011-2022 走看看