11-07除法

代码分析:分段,以块为单位看代码,逐个击破

流水线优化:在不影响结果的前提下,排列指令顺序,提高并行程度


除法

变化一

     如果除数是变量,只能使用除法指令,有符号是idiv,无符号是div

这是经过数学论证的,当除数位置是没有优化的余地的

变化二

     除数不是变量,且除数是2的幂

1.在无符号的情况下,采取向下取整的除法,,一般直接使用右移指令


11-07除法_第1张图片
图片.png

2.有符号的情况下,需要经过数学推导:

11-07除法_第2张图片
IMG_2861.JPG

数学除法会产生小数,C语言计算产生的误差只要在0- |1/b| 之间的范围,可以利用这个推导来忽略误差

11-07除法_第3张图片
IMG_2862.JPG

由以上推导,处理有符号数的时候,例如

11-07除法_第4张图片
图片.png

编译器的优化过程以推导7作为基础

11-07除法_第5张图片
IMG_2863.JPG

可是,如何将 n > 0 和 n < 0 这两个分支优化,编译器采取的思路是利用cdq配合and指令

cdq                         ;符号拓展,将eax的符号拓展到edx,edx要么位0xffffffff要么为0
and         edx,7           ;利用与运算,若n > 0 ,edx = 0,   n < 0, edx = 7
add         eax,edx
sar         eax,3

定式:

cdq
and edx, immA
add eax, edx
sar eax, immB

验证:

(2^immB) -1 = immA
若不相等,则可能是作者内联汇编挖的坑,因为c语言语法是不会产生cdq指令的

还原:

eax / (2^immB)

     除数不是变量,且除数不是2的幂

Debug:不做有优化
Release:

推导:

11-07除法_第6张图片
IMG_2864.JPG

m = 2^n / c
n由编译器决定,一般16位环境从16开始,32位环境从32开始,以此类推。
所以2^n为常量
c为常量
n的取值由c决定,需要满足误差小于1/c
所以m为常量,又称为MagicNumber,这个值由编译器编译时产生

又因为 a*m = edx. eax
有可能直接使用edx,那么这就是结果 >>32 位
所以最后的结果需要以edx做移位,
所以edx的移位位数需要加上32

定式

mov eax, MagicNumber
imul ....
sar edx, ...
mov reg, edx
shr reg, 1fh
add edx, reg

还原

o = 2^n / c
n从右移的次数得到,MagicNumber作为c,代入公式求解到除数近似值,还原除法原型

你可能感兴趣的:(11-07除法)