一丶除法的優化
1.有符号被除數 / 無符号除數的情況下
進階代碼為:

彙編中優化的展現形式
相比于昨天,我們發現了的 無符号 / 常量多出了點東西
無符号/常量
如果無符号/常量,那麼我們還原的時候
套用公式即可
am >> n
a是被除數 m是設 2n/c 等價于 m == 2n/c
無符号的情況的,n的值是2^33次方 ,n = 33
根據上面得知, m = 0AAAAAAABh
此時求出C來即可, C = 除數
公式:
2n / m = c
套進去得到
2^33次方 / 0AAAAAAABh = 被除數 結果向上取整
向上取整,結果就是3,那麼得出被除數是3了.
2^33次方,也就是n怎麼得出來的,依據上面的彙編代碼n值等于1
也就是shr edx,1 那麼我們知道,算一個除法的時候,必須擴充符号位
也就是 變成了 EDX.EAX 了,現在EDX右移一位,那麼相當于 eax移動了32位+1,也就是33位,是以可以直接省略了.
是以此時EDX >> 1則是 33
此時繼續,有符号 / 常量
看彙編代碼,下邊多了幾條語句 顯然與上面不同
此時還原的方法
n得出結果就是32,為什麼?
因為edx直接使用了,我不用移位了.
下方的移動31位,是固定的,這個主要是解決有符号和無符号相除.
在這裡,需要進行大量的數學公式推算,鑒于大家對數學不太明白,是以不再講解.
我們隻需要知道,當一個有符号 / 一個常量的時候,那麼下方如果調整了.不用看.因為m的值如果按照 imul來計算的時候是一個負數.但是此時我們不能讓它變為負數,是以最後進行符号位調整.
還原手法同上.
如果數學公式推導:
我們知道.
a/c的結果可以變為
m = 2n / c
此時我們要知道,C的結果不會是整數的,是以使用的公式 是上整+1
也可能是小數,也需要上整+1
那麼現在我們可以把符号位提取出來,這樣也就是 移動31位(是以說是在32位系統下是固定死的),這樣如果是負數,那麼負數+1即可.如果是正數,那麼是加0,還原的時候隻看上三句即可.
2.無符号 / 7 和有符号/7的新的優化方式(當然可能不光是7介紹的是這種優化方式)
無符号/7的新方式.
又暈了是不是,一個DIV沒用到,很難看到這是一個除法對不對.
先說下還原的公式,以及方法(至于公式怎麼的出來的,那麼可以看下方推導,當然這屬于大數問題,可以不看.不過看了有好處)
2n / (M + 2^32) = C(除數)即可.(别忘了結果向上取整)
n = 32(本身32起步,看系統,當然n的取值明天會講) + 1 + 2 (指數相加) 結果為2 ^ 35次方
那麼 2^35次方 / (M + 2^32) 結果救贖除數
那麼我們按照數學界的公式去推一下.
推導:
首先得出:
得出最後的公式.
那麼根據上面的程式,繼而得到了
一步一步簡化
第一次簡化: 可以把2^32次方拿到上面來
第二次簡化
第三次簡化:
第四次簡化
第五次簡化
第六次簡化:
第七次簡化:
得出了
那麼根據以前的除法公式
設 m
那麼
進而簡化為公式得出 一個大的M, M的值太大了.變為了一個大數問題,是以我們最終的M要加上1,或者加上2^32次方.(因為進位了)
C = (2^32 + 指數 + 指數) / (2^32 + M) 故而得出了C
簡化為了
C = 2^n / M (别忘了M是一個大數)
有符号/7
這個和昨天一樣,套用 C = 2^n / M 即可 (M是正常的,不是大數)
在這裡講解一下彙編代碼:
請問為什麼要 add一下.
這裡我們就涉及到了有符号和無符号混乘的問題.
比如16位的年代,兩個寄存器相乘,怎麼解決溢出問題了.
A * 8086
A + ~A = FFFF
A + ~A + 1 = 10000 (求補碼)
A * -(10000h - 8086h)
去掉負号
A * (8086h - 10000h )
那麼得出
8086h - 10000h = dx.ax
又因為你減掉了補碼 10000h
那麼
dx.ax + 10000h = 8086h
那麼此時 10000h的高位變成了1,那麼 dx直接加1即可了.
是以這就是為什麼 add edx,ecx(乘積的高位)
到此,除數為正數的幾種情況講解完畢.
二丶除數為負數
1.除數為 -2的幂的情況下
進階代碼:
彙編代碼:
公式還是一樣的,向上取整的公式.也就是昨天的
b- 1是3
b是除數, 結果是2 ^2次方.
得出除數是4 隻需要求反即可.
2.除數為-7的時候,有符号除,和無符号除的表現形式
2.1 有符号除
進階代碼還是上面的,隻不過 -4 變為-7
argc / -7
此時,和 有符号 * 無符号問題又沖突了
隻不過,現在的M變為負數了 需要你求補碼了. 而又因為M是一個大數,下面需要調整1F(31)位,是以
還原公式為
2^n / neg(2^32 + M) = C (向上取整)
也就是說依照上圖,我們的M變為了16DB6DB6D了,此時要對它取反+1變為真正的M 然後用2^n次方去除,然後求出C來(除數)
計算一下得到
2^34 / neg(16DB6DB6D) = 6.99999xxxx 向上取整是7
那麼此時怎麼判斷是否是 ±7那?
可以看彙編代碼,裡面有個 sub edx,ecx(相當于上面舉例子 A * 8086, 那麼此時 EDX隻能減去乘積的高位才會得出真正的8086)
那麼此時,我們判定了m的高位是負數,是求補後的,那麼得出了 M是負數,說明了除數為負數,又因為還原了,M 得出的結果是原除數的絕對值.是以判定為負數.
2.2無符号/-7的優化.
這個是特殊還原公式
還原公式:
C = 2^n / M 轉為16進制當做有符号解釋即可.
現在的n是29 加上原來的32 = 61 那麼就是2^61次方 / 20000001h 結果轉化為16進制當做有符号解釋.
作者:IBinary