有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;
- }

唯一的區別就是使用 h<<7 移位操作代替了 127 * 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語言程序開發中,移位操作與乘除法操作的關系,并討論了它們之間的效率問題。可以看出,我們并不需要糾結二者之間的取舍。事實上,考慮到代碼的易讀性和編譯器的優化特性,我們應該寫出“本意”代碼,即:希望實現乘除操作時,就寫出乘除代碼。希望實現移位操作時,就寫出移位代碼。




















