[2010-8-10]

  1.今天一大早就继续看HAKMEM,发现了一条公示:(A | B) + (A & B) === A + B === (A^B) + ((A&B)<<1),我马上有个感觉,这个公式可以优化加法运算,然后就在我那台单核1.7G主频CPU的笔记本上开始了实验,不过结果非常不稳定,三中加法代码各自都有比较快的时候。不过当我把运算次数调到300亿次(回到家才发现溢出了,没有300亿,大概就10~20亿左右),这时候就发现(A^B) + ((A&B)<<1) 最快的次数占了大多数,正如我所猜测。然而回到家,我继续实验,把计算次数真正设置到300亿,但三种运算代码的时间差相差不过100MS,依然各有领先的时候,不过依然是(A^B) + ((A&B)<<1)较多,看来这个优化实际用途不大,跟机器结构关系很大。

  2.晚上在家里继续优化文章解释程序,进行了好几个优化,成功把运行时间从47300MS降到44300MS(对于250单词的文章)。首先是大小写忽视的功能,最直截了当的代码是判断是否要进行忽视,如果要,则判断字符是否大写,是的话把字符值+32变成小写。还没开始写代码,我就觉得肯定有更快的方法,一个不需要比较的方法,我甚至想到ASCII表中,以前一直不懂为什么大小写字符的数值不是连续,中间隔了一些符号,突然灵机一触,我知道这个间隔肯定是人为,而且优化的手段必定在这里!(我的第六感不错),为了可以做性能对比,我还是用老实而低效的方法写了转换大小写的代码,并记录时间。接下来我就开始研究,我发现ASCII中大小写字母的间隔是32,对了,肯定就是它,32二进制就是00100000,只要使用位或就能够不用判断当前字符是大写还是小写,而直接变成小写,char c = c|32。就这一个关键点让速度快了1秒多,我的天。

    2.1不允许大小写忽略时的最优性能:

    [2010-8-10]

    2.2允许使用大小写忽略,但选择不使用时的最优性能:

    [2010-8-10]

    2.3使用大小写忽略功能时的最优性能:

    [2010-8-10]

    2.4第一次优化后,使用大小写忽略功能(转大写):

    [2010-8-10]

    2.5第一次优化后,使用大小写忽略功能(转小写):

    [2010-8-10]

  3.接下来在代码中还要判断是否需要大小写忽略这个功能,不需要就不做,这肯定少不了至少一个判断,我不喜欢,而且我知道VC++中bool值就是0,1,那就行了,直接利用这个指示变量的值做左移5位把1变成32,然后做位或,如果原值是0,则位或没效果,代表不需要这功能。不过这里我担心参数传进来不一定是0,1,可能是其他整数,于是实验了一下,发现VC++在把整形变成bool的过程会截断并把目标值变成1(原来的整数大于0的话,否则为0)。有了这个保证,于是就可以 char c = c | (ignoreCase<<5),不过我猜想这个改变不但不能优化,反而会减慢效率,因为if判断只是简单的一次位操作,而这里就设计了移位。而事实数据说明性能的确慢了一点,大概10~30MS。

    3.1第二次优化,使用移位判断是否需要大小写忽视

    [2010-8-10]

  4.下一步的优化是昨晚发现的HASH表扩容问题,不过尽管我把扩容后的内部数组大小定义为新素数,优化效果也就是减少了20MS左右的时间,不过聊胜于无。

    4.1扩容后的内部数组大小不为素数时的性能:

    [2010-8-10]

    4.2扩容后的内部数组大小是素数:

    [2010-8-10]

  5.最后一个优化是最让人激动,在原来的代码中,每次发现一个单词,都会分配一个char数组来缓存改单词,然后构造string类型,但这样涉及到大量的堆内存分配操作,还有释放。基本上文章中的英文单词都不会超过100个字符的长度,于是我改为使用一个线程局部char数组,大小是100,来代替分配的。由此得到的速度提升高达2秒左右,太厉害了。

    5.1从原文复制解释的单词时,使用线程局部的大小为100的字符数组

    [2010-8-10]

你可能感兴趣的:([2010-8-10])