編譯器整數除法的優化

2021-10-09 05:36:04 字數 1807 閱讀 6142

整數的除法有2種情況

那麼編譯器會使用div指令,執行效率會下降

那麼情況會比較複雜,如果除數是2

n2^n

2n,就會使用shr a,n。其中a是被除數,n是2的冪。如果除數不是2呢?那麼情況就會更加複雜了,不同的編譯器會有不同的演算法。通常的思路是將除法轉換成乘法來提高執行的效率,最常見的優化演算法便是倒數相乘了

​ a b=

a∗(1

b)

\frac=a*(\frac)

ba​=a∗

(b1​

)下面用乙個例項說明

#include

intmain()

這是乙個非常簡單的整數除法例子,下面我列出核心彙編**進行講解

mov eax,2e8ba2e9

imul ecx //ecx是我們的a

sar edx,1

mov ecx,edx

shr ecx,1f

add edx,ecx

核心的除法優化演算法其實就是短短的6行,那麼這有什麼可講的呢?

首先eax是由編譯器生成的乙個數,然後a∗e

ax

a*eax

a∗ea

x,得到的積低32位儲存在eax中,高32位儲存在edx中,如果積大於32位的話。

sar edx,1
則是直接取出高32位來看,相當於直接捨去了低32位,也就相當於先右移了32位。再右移1位,相當於我們得到的積總共向右移了33位

a ∗(

2e8b

a2e9

h>

>33)

a*(2e8ba2e9h>>33)

a∗(2e8

ba2e

9h>

>33

)等於a∗(

2e8b

a2e9

h/233

)a*(2e8ba2e9h/2^)

a∗(2e8

ba2e

9h/2

33),(2e

8ba2

e9h/

233)≈

0.090909

(2e8ba

2e9h

/233

)≈0.

0909

09也就是所謂的倒數了。

第5行的右移31位是為了得到結果的符號位,這裡主要是看符號位是否為1,也就是是否為負數。如果是負數的話,符號位為1,最後的結果+1。

那麼問題來了,為什麼最後要加1呢?

這是因為負數算術右移負數除以2最後的結果其實是不同的,雖然我們常常認為右移1位就是除以2。

負數算術右移是向下取整的,換句話說負數s

hr的結

果+1=

負數除以

2的結果

負數shr的結果+1 = 負數除以2的結果

負數shr的

結果+1

=負數除

以2的結

果。所以最後要加1。

shr了。而無符號數永遠為正,自然也不會存在這樣的問題了。

編譯器優化

常量摺疊 a 1 2 由於結果可預見,編譯器直接生成a 3 常量傳播a 1 若後續 沒有更改a,則編譯器將a直接用其值1代替 減少變數 對於x和y的比較,可以轉換成if i j x i2 y j 2 if x y 複寫傳播 類似於常量長傳,不過傳播的是變數 若後續 未修改a的值,則編譯器用m代替a ...

編譯器優化 乘法優化

由這個想到的 31乘以某個數能不能寫成這個數乘以2的次冪 再減去這個數。用數學語言表達一下就是 設這個數為x 31 x x 2 n x 這個等式是否存在,如果存在,求n的值 那我們計算一下,31 2 n 1 得2 n 32 得n 5 也就是說存在那麼乙個n使得,31乘以某個數的結果等於這個數乘以2的...

編譯器優化問題

今天遇一程式,unsigned char a,b,c a 0x89 b a 1 c a b 在單步除錯的時候,觀察數值發現b的值為0,分析b的值應當為0x44,百思不得其解,通過檢視其彙編語句,發現問題所在。彙編語句如下 mov r7,tmod 0x89 mov a,r7 clr c rrc a a...