03 有符号数除以非2的幂
右移是向下取整操作,对于除法A/C,当C>0且C不是2的幂时,除法转乘法(magic无进位):
if (A > 0) {
AM >> n; //正数直接右移
}
else {
(AM >> n) + 1; //负数右移后要 +1
}
还原:
2^33 / 66666667h 得5
int nVal = argc/5;
还原:
2^32 / 55555556h得3
int nVal = argc/3;
有符号数*无符号数的计算方法:
用16bit举例,有符号数A * 无符号数8086h ,如果用imul指令,相当于把8086h视为负数
A * 8086 = A * -(10000h-8086h)
= A*(8086h-10000h)
= 8086*A - 10000*A => dx.ax
结果再加10000*A才等于8086*A,相当于dx再加A
8086*A - 10000*A + 10000*A => add dx, A
mov eax, 0x80868086
mov ecx, 0x123
imul ecx
add edx, ecx
A/(-2^n) = -(A/2^n)
计算A/C, 若C>0, 可转换为(A*M)>>n,
若C<0, 可转换为 -((A*M)>>n), 即(A*(-M))>>n
magic为正,imul和sar之间出现对edx的减调整,说明除数为负。
2^34/neg(magic) => argc/-7
Magic大于0,在imul和sar之间存在对edx的减调整
或者
Magic小于0,在imul和sar之间没有调整
皆判定除数为负
优化除法:
1. 除数为正数
1.1 无符号除法
1.1.1 除数为2的幂:shr
1.1.2 除数为非2的幂
1.1.2.1 magic无进位:mul, shr
1.1.2.2 magic有进位:mul, sub, shr, add, shr
1.2 有符号除法
1.2.1 除数为2的幂:cdq, and, add, shr
1.2.2 除数为非2的幂
1.2.2.1 magic为正数:imul, sar
1.2.2.2 magic为负数:imul, add, sar
2. 除数为负数
2.1 除数为2的幂:cdq, and, add, sar, neg
2.2 除数为非2的幂
2.2.1 magic为正数:imul, sar
2.2.2 magic为负数:imul, add, sar