10

C语言程序中,移位操作代替乘除操作,效率更高吗?

 3 years ago
source link: https://blog.popkx.com/c%E8%AF%AD%E8%A8%80%E7%A8%8B%E5%BA%8F%E4%B8%AD-%E7%A7%BB%E4%BD%8D%E6%93%8D%E4%BD%9C%E4%BB%A3%E6%9B%BF%E4%B9%98%E9%99%A4%E6%93%8D%E4%BD%9C-%E6%95%88%E7%8E%87%E6%9B%B4%E9%AB%98%E5%90%97/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C语言程序中,移位操作代替乘除操作,效率更高吗?

发表于 2019-08-23 08:08:09   |   已被 访问: 415 次   |   分类于:   C语言   |   暂无评论

在C语言程序开发中,一些移位操作似乎可以达到与乘除法操作一样的效果。例如,4>>1 等于 2,此时右移一位相当于除以 2。类似的,2<<1 等于 4,此时左移一位相当于乘以 2。

因此,有些教材推荐使用移位操作代替乘除操作,称可以为最终的C语言程序带来效率上的提升,那么真的如此吗?

移位代替乘除,C语言程序效率更高吗?

得到答案最简单直接的方法是做实验,下面是两段关于哈希算法的C语言程序,请看:

unsigned int hash( char const* s )
{
    unsigned h = 0;
    while ( *s != '\0' ) {
        h = 127 * h + (unsigned char)*s;
        ++ s;
    }
    return h;
}

读者应将注意力放在h = 127 * h + (unsigned char)*s;一行,此时C语言代码使用的是乘法操作。下面是另外一段C语言代码,请看:

unsigned int hash( char const* s )
{
    unsigned h = 0;
    while ( *s != '\0' ) {
        h = (h << 7) - h + (unsigned char)*s;
        ++ s;
    }
    return h;
}

与前面那段C语言代码相比,唯一的区别就是使用 h<<7 移位操作代替了 127 * h 乘法操作。在我的机器上,我测试了这两段C语言代码的效率,结果是两者差不多快,有时 127 * h 版本的C语言代码更快!

C语言程序中,使用移位操作代替乘除操作更快吗?现在这个问题我们已经有答案了:并不如此。原因在于C语言编译器一般都会优化我们的代码,它知道如何尽可能快地增加目标处理器体系结构的能力,也即尽量生成尽可能快的程序。

因此作为C语言程序员,我们应该做的是明确告诉编译器我们的意图(即到底是 i * 2,还是 i<<1),让它根据上下文决定如何产生更快的指令。

当硬件不支持快速乘除法时,编译器会将乘除法转换为移位和加法/减法的适当组合。因为它知道我们的最终目的,所以有时候显示的写出移位代码,倒不如直接告诉编译器我们的目的,这样才能得到尽可能快的C语言程序。

事实上,有时候简单的移位操作并不等同于乘除法,而且有些乘法并不能通过简单的移位实现,例如:

-5 / 2  = -2
-5 >> 1 = -3

i*3 = (i<<1) + i
i*10 = (i<<3) + (i<<1)

因此,使用移位操作代替乘除法操作可能会带来预计之外的结果。而且有些移位组合也会让同事难以理解这段C语言代码的真实意图,也不利于协作开发和后期维护。

本节讨论了C语言程序开发中,移位操作与乘除法操作的关系,并讨论了它们之间的效率问题。可以看出,我们并不需要纠结二者之间的取舍。事实上,考虑到代码的易读性和编译器的优化特性,我们应该写出“本意”代码,即:希望实现乘除操作时,就写出乘除代码。希望实现移位操作时,就写出移位代码。

阅读更多:   C语言


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK