整數的除法有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...